@sdcorejs/angular 21.1.2 → 21.1.4
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 +127 -807
- package/fesm2022/sdcorejs-angular-components-anchor.mjs +14 -14
- package/fesm2022/sdcorejs-angular-components-anchor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-audit-diff.mjs +332 -0
- package/fesm2022/sdcorejs-angular-components-audit-diff.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-badge.mjs +1 -0
- package/fesm2022/sdcorejs-angular-components-badge.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-breadcrumb.mjs +121 -0
- package/fesm2022/sdcorejs-angular-components-breadcrumb.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-data-state.mjs +68 -0
- package/fesm2022/sdcorejs-angular-components-data-state.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-document-builder.mjs +18 -23
- package/fesm2022/sdcorejs-angular-components-document-builder.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-editor.mjs +6 -4
- package/fesm2022/sdcorejs-angular-components-editor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-form-generic.mjs +633 -886
- package/fesm2022/sdcorejs-angular-components-form-generic.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-import-excel.mjs +26 -41
- package/fesm2022/sdcorejs-angular-components-import-excel.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-job-progress.mjs +97 -0
- package/fesm2022/sdcorejs-angular-components-job-progress.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-mini-editor.mjs +10 -20
- package/fesm2022/sdcorejs-angular-components-mini-editor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-modal.mjs +61 -4
- package/fesm2022/sdcorejs-angular-components-modal.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-preview.mjs +1438 -218
- package/fesm2022/sdcorejs-angular-components-preview.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-query-bar.mjs +9 -17
- package/fesm2022/sdcorejs-angular-components-query-bar.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-query-builder.mjs +1 -1
- package/fesm2022/sdcorejs-angular-components-query-builder.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-side-drawer.mjs +39 -2
- package/fesm2022/sdcorejs-angular-components-side-drawer.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-tab-router.mjs +76 -52
- package/fesm2022/sdcorejs-angular-components-tab-router.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-tab.mjs +48 -4
- package/fesm2022/sdcorejs-angular-components-tab.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-table.mjs +123 -89
- package/fesm2022/sdcorejs-angular-components-table.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-tree.mjs +188 -18
- package/fesm2022/sdcorejs-angular-components-tree.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-upload-file.mjs +17 -23
- package/fesm2022/sdcorejs-angular-components-upload-file.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components.mjs +4 -0
- package/fesm2022/sdcorejs-angular-components.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-directives.mjs +29 -41
- package/fesm2022/sdcorejs-angular-directives.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs +9 -8
- package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-checkbox.mjs +20 -71
- package/fesm2022/sdcorejs-angular-forms-checkbox.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs +8 -4
- package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-chip.mjs +8 -4
- package/fesm2022/sdcorejs-angular-forms-chip.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-date-range.mjs +18 -14
- package/fesm2022/sdcorejs-angular-forms-date-range.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-date.mjs +48 -70
- package/fesm2022/sdcorejs-angular-forms-date.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-datetime.mjs +62 -528
- package/fesm2022/sdcorejs-angular-forms-datetime.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-entity-picker.mjs +384 -0
- package/fesm2022/sdcorejs-angular-forms-entity-picker.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-input-color.mjs +5 -3
- package/fesm2022/sdcorejs-angular-forms-input-color.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-input-number.mjs +16 -11
- package/fesm2022/sdcorejs-angular-forms-input-number.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-input.mjs +297 -59
- package/fesm2022/sdcorejs-angular-forms-input.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-models.mjs +155 -2
- package/fesm2022/sdcorejs-angular-forms-models.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-radio.mjs +44 -66
- package/fesm2022/sdcorejs-angular-forms-radio.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-select.mjs +8 -21
- package/fesm2022/sdcorejs-angular-forms-select.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-switch.mjs +19 -64
- package/fesm2022/sdcorejs-angular-forms-switch.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-textarea.mjs +8 -6
- package/fesm2022/sdcorejs-angular-forms-textarea.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-time-range.mjs +277 -0
- package/fesm2022/sdcorejs-angular-forms-time-range.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-time.mjs +307 -0
- package/fesm2022/sdcorejs-angular-forms-time.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-tree-select.mjs +210 -0
- package/fesm2022/sdcorejs-angular-forms-tree-select.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms.mjs +73 -4
- package/fesm2022/sdcorejs-angular-forms.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-i18n.mjs +355 -10
- package/fesm2022/sdcorejs-angular-i18n.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-interceptors.mjs +12 -17
- package/fesm2022/sdcorejs-angular-interceptors.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-icon.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-layout.mjs +861 -80
- package/fesm2022/sdcorejs-angular-modules-layout.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules.mjs +0 -1
- package/fesm2022/sdcorejs-angular-modules.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-pipes.mjs +5 -7
- package/fesm2022/sdcorejs-angular-pipes.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-api.mjs +407 -137
- package/fesm2022/sdcorejs-angular-services-api.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-cache.mjs +515 -105
- package/fesm2022/sdcorejs-angular-services-cache.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-confirm.mjs +5 -7
- package/fesm2022/sdcorejs-angular-services-confirm.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-docx.mjs +7 -10
- package/fesm2022/sdcorejs-angular-services-docx.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-loading.mjs +340 -66
- package/fesm2022/sdcorejs-angular-services-loading.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-notify.mjs +7 -10
- package/fesm2022/sdcorejs-angular-services-notify.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-persistence.mjs +899 -0
- package/fesm2022/sdcorejs-angular-services-persistence.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-services-storage.mjs +324 -122
- package/fesm2022/sdcorejs-angular-services-storage.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-task.mjs +389 -0
- package/fesm2022/sdcorejs-angular-services-task.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-services-unsaved-changes.mjs +255 -0
- package/fesm2022/sdcorejs-angular-services-unsaved-changes.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-services-viewport.mjs +76 -0
- package/fesm2022/sdcorejs-angular-services-viewport.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-services.mjs +4 -0
- package/fesm2022/sdcorejs-angular-services.mjs.map +1 -1
- package/package.json +50 -5
- package/types/sdcorejs-angular-components-audit-diff.d.ts +74 -0
- package/types/sdcorejs-angular-components-badge.d.ts +1 -1
- package/types/sdcorejs-angular-components-breadcrumb.d.ts +53 -0
- package/types/sdcorejs-angular-components-data-state.d.ts +44 -0
- package/types/sdcorejs-angular-components-document-builder.d.ts +5 -5
- package/types/sdcorejs-angular-components-form-generic.d.ts +89 -103
- package/types/sdcorejs-angular-components-import-excel.d.ts +4 -14
- package/types/sdcorejs-angular-components-job-progress.d.ts +38 -0
- package/types/sdcorejs-angular-components-mini-editor.d.ts +9 -9
- package/types/sdcorejs-angular-components-modal.d.ts +7 -1
- package/types/sdcorejs-angular-components-preview.d.ts +181 -28
- package/types/sdcorejs-angular-components-side-drawer.d.ts +7 -1
- package/types/sdcorejs-angular-components-tab.d.ts +9 -2
- package/types/sdcorejs-angular-components-table.d.ts +8 -7
- package/types/sdcorejs-angular-components-tree.d.ts +24 -2
- package/types/sdcorejs-angular-components-upload-file.d.ts +5 -4
- package/types/sdcorejs-angular-components.d.ts +4 -0
- package/types/sdcorejs-angular-directives.d.ts +10 -8
- package/types/sdcorejs-angular-forms-autocomplete.d.ts +3 -4
- package/types/sdcorejs-angular-forms-checkbox.d.ts +4 -8
- package/types/sdcorejs-angular-forms-date-range.d.ts +6 -7
- package/types/sdcorejs-angular-forms-date.d.ts +3 -3
- package/types/sdcorejs-angular-forms-datetime.d.ts +3 -3
- package/types/sdcorejs-angular-forms-entity-picker.d.ts +128 -0
- package/types/sdcorejs-angular-forms-input-color.d.ts +3 -1
- package/types/sdcorejs-angular-forms-input-number.d.ts +4 -2
- package/types/sdcorejs-angular-forms-input.d.ts +76 -11
- package/types/sdcorejs-angular-forms-models.d.ts +86 -3
- package/types/sdcorejs-angular-forms-radio.d.ts +12 -8
- package/types/sdcorejs-angular-forms-switch.d.ts +4 -7
- package/types/sdcorejs-angular-forms-time-range.d.ts +98 -0
- package/types/sdcorejs-angular-forms-time.d.ts +117 -0
- package/types/sdcorejs-angular-forms-tree-select.d.ts +76 -0
- package/types/sdcorejs-angular-forms.d.ts +15 -5
- package/types/sdcorejs-angular-i18n.d.ts +68 -2
- package/types/sdcorejs-angular-interceptors.d.ts +5 -6
- package/types/sdcorejs-angular-modules-icon.d.ts +2 -3
- package/types/sdcorejs-angular-modules-layout.d.ts +288 -15
- package/types/sdcorejs-angular-modules.d.ts +0 -1
- package/types/sdcorejs-angular-pipes.d.ts +2 -2
- package/types/sdcorejs-angular-services-api.d.ts +68 -24
- package/types/sdcorejs-angular-services-cache.d.ts +52 -16
- package/types/sdcorejs-angular-services-confirm.d.ts +3 -2
- package/types/sdcorejs-angular-services-docx.d.ts +2 -3
- package/types/sdcorejs-angular-services-loading.d.ts +16 -8
- package/types/sdcorejs-angular-services-persistence.d.ts +159 -0
- package/types/sdcorejs-angular-services-storage.d.ts +26 -8
- package/types/sdcorejs-angular-services-task.d.ts +104 -0
- package/types/sdcorejs-angular-services-unsaved-changes.d.ts +83 -0
- package/types/sdcorejs-angular-services-viewport.d.ts +42 -0
- package/types/sdcorejs-angular-services.d.ts +4 -0
- package/fesm2022/sdcorejs-angular-modules-authom.mjs +0 -360
- package/fesm2022/sdcorejs-angular-modules-authom.mjs.map +0 -1
- package/types/sdcorejs-angular-modules-authom.d.ts +0 -70
|
@@ -73,10 +73,10 @@ class SdAnchor {
|
|
|
73
73
|
sidebarWidth = input('200px', ...(ngDevMode ? [{ debugName: "sidebarWidth" }] : /* istanbul ignore next */ []));
|
|
74
74
|
ellipsis = input(false, { ...(ngDevMode ? { debugName: "ellipsis" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
75
75
|
overScroll = input(false, { ...(ngDevMode ? { debugName: "overScroll" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
76
|
-
// Mobile:
|
|
77
|
-
// Consumer
|
|
76
|
+
// Mobile: mặc định ẩn nav (sidebar TOC chiếm chỗ trên màn hình hẹp).
|
|
77
|
+
// Consumer truyền `[hideNav]="false"` để buộc hiển thị trên mobile.
|
|
78
78
|
hideNav = input(BrowserUtilities.isMobile(), { ...(ngDevMode ? { debugName: "hideNav" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
79
|
-
//
|
|
79
|
+
// Màu highlight active nav (text + icon + vertical bar). Default 'primary'.
|
|
80
80
|
color = input('primary', ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
|
|
81
81
|
activeSectionId = signal('', ...(ngDevMode ? [{ debugName: "activeSectionId" }] : /* istanbul ignore next */ []));
|
|
82
82
|
#initialized = false;
|
|
@@ -93,7 +93,7 @@ class SdAnchor {
|
|
|
93
93
|
this.#registerIntersectionObserver();
|
|
94
94
|
}
|
|
95
95
|
});
|
|
96
|
-
//
|
|
96
|
+
// Lắng nghe thay đổi sections để đăng ký lại observer cho từng section.
|
|
97
97
|
effect(() => {
|
|
98
98
|
this.sections();
|
|
99
99
|
if (!this.hideNav() && this.#initialized) {
|
|
@@ -104,24 +104,24 @@ class SdAnchor {
|
|
|
104
104
|
#registerIntersectionObserver() {
|
|
105
105
|
this.#cleanIntersectionObserver();
|
|
106
106
|
const wrapperEl = this.wrapper().nativeElement;
|
|
107
|
-
//
|
|
107
|
+
// Browser API IntersectionObserver hỗ trợ xác định section đang hiển thị trong wrapperEl.
|
|
108
108
|
this.#intersectionObserver = new IntersectionObserver(entries => {
|
|
109
109
|
for (const entry of entries) {
|
|
110
110
|
if (entry.isIntersecting) {
|
|
111
|
-
//
|
|
111
|
+
// Nếu section mới đi vào vùng nhìn thấy thì thêm vào set.
|
|
112
112
|
this.#visibleSections.add(entry.target);
|
|
113
113
|
}
|
|
114
114
|
else {
|
|
115
|
-
//
|
|
115
|
+
// Nếu section đã đi ra khỏi vùng nhìn thấy thì xóa khỏi set.
|
|
116
116
|
this.#visibleSections.delete(entry.target);
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
-
//
|
|
119
|
+
// Nếu đang scroll do click section thì không cần quét section đang active.
|
|
120
120
|
if (this.#isClickScrolling) {
|
|
121
121
|
return;
|
|
122
122
|
}
|
|
123
123
|
for (const section of this.sections()) {
|
|
124
|
-
//
|
|
124
|
+
// Kiểm tra DOM của section nào đang nằm trong danh sách nhìn thấy để active chính xác.
|
|
125
125
|
if (this.#visibleSections.has(section.elementRef.nativeElement)) {
|
|
126
126
|
if (this.activeSectionId() !== section.id) {
|
|
127
127
|
this.activeSectionId.set(section.id);
|
|
@@ -130,7 +130,7 @@ class SdAnchor {
|
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
}, { root: wrapperEl, threshold: 0 });
|
|
133
|
-
//
|
|
133
|
+
// Đăng ký theo dõi từng section có trong anchor.
|
|
134
134
|
for (const section of this.sections()) {
|
|
135
135
|
this.#intersectionObserver.observe(section.elementRef.nativeElement);
|
|
136
136
|
}
|
|
@@ -145,15 +145,15 @@ class SdAnchor {
|
|
|
145
145
|
this.#isClickScrolling = true;
|
|
146
146
|
const wrapperEl = this.wrapper().nativeElement;
|
|
147
147
|
const targetElement = targetSection.nativeElement;
|
|
148
|
-
const prevScrollTop = wrapperEl.scrollTop; //
|
|
149
|
-
const scrollTop = prevScrollTop + targetElement.getBoundingClientRect().top - wrapperEl.getBoundingClientRect().top; //
|
|
150
|
-
//
|
|
148
|
+
const prevScrollTop = wrapperEl.scrollTop; // Lưu lại vị trí cuộn hiện tại của container.
|
|
149
|
+
const scrollTop = prevScrollTop + targetElement.getBoundingClientRect().top - wrapperEl.getBoundingClientRect().top; // Vị trí section cần scroll tới.
|
|
150
|
+
// Đăng ký sự kiện khi scroll hoàn tất.
|
|
151
151
|
this.#clickScrollSubscription = fromEvent(wrapperEl, 'scrollend')
|
|
152
152
|
.pipe(take(1))
|
|
153
153
|
.subscribe(() => {
|
|
154
154
|
this.#isClickScrolling = false;
|
|
155
155
|
});
|
|
156
|
-
//
|
|
156
|
+
// Nếu sectionTarget đã ở đúng vị trí (click nhưng không scroll) thì kích hoạt lại IntersectionObserver sau timeout.
|
|
157
157
|
this.#timeoutId = setTimeout(() => {
|
|
158
158
|
if (wrapperEl.scrollTop === prevScrollTop) {
|
|
159
159
|
this.#isClickScrolling = false;
|
|
@@ -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 { IAnchorItem } from '../../models';\nimport { Utilities } from '@sdcorejs/utils/fns';\n\n@Component({\n selector: 'sd-anchor-item',\n templateUrl: './anchor-item.component.html',\n styleUrl: './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 { Color } from '@sdcorejs/utils/models';\nimport { Subject, Subscription, debounceTime } from 'rxjs';\n\nimport { SdAnchorItem } from '../anchor-item/anchor-item.component';\nimport { SdIcon } from '@sdcorejs/angular/modules/icon';\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: [SdIcon, CommonModule],\n standalone: true,\n})\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(this.#clickSectionSubject.pipe(debounceTime(this.#delay)).subscribe((id: string) => this.clickSection.emit(id)));\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 <sd-icon class=\"c-anchor-list-item-icon\" [name]=\"section.icon()\"></sd-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 styleUrl: './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\"` d? 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 d?i sections d? dang 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 du?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 di v�o v�ng nh�n th?y -> add v�o set\n this.#visibleSections.add(entry.target);\n } else {\n // N?u section d� di 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 dang scroll b?i click section th� return lu�n, k ph?i qu�t qua t�m v�ng section du?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 dang n?m trong danh s�ch dang nh�n th?y d? 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 // �ang 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; // Luu 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 // �ang k� s? ki?n n?u d� du?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 d� ? d�ng v? tr� (click nhung 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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"}
|
|
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 styleUrl: './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 { Color } from '@sdcorejs/utils/models';\nimport { Subject, Subscription, debounceTime } from 'rxjs';\n\nimport { SdAnchorItem } from '../anchor-item/anchor-item.component';\nimport { SdIcon } from '@sdcorejs/angular/modules/icon';\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: [SdIcon, CommonModule],\n standalone: true,\n})\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(this.#clickSectionSubject.pipe(debounceTime(this.#delay)).subscribe((id: string) => this.clickSection.emit(id)));\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 <sd-icon class=\"c-anchor-list-item-icon\" [name]=\"section.icon()\"></sd-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 styleUrl: './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: mặc định ẩn nav (sidebar TOC chiếm chỗ trên màn hình hẹp).\n // Consumer truyền `[hideNav]=\"false\"` để buộc hiển thị 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 observer cho từng 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 // Browser API IntersectionObserver hỗ trợ xác định section đang hiển thị 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 thì thêm 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 thì xóa khỏi set.\n this.#visibleSections.delete(entry.target);\n }\n }\n\n // Nếu đang scroll do click section thì không cần quét section đang active.\n if (this.#isClickScrolling) {\n return;\n }\n\n for (const section of this.sections()) {\n // Kiểm tra DOM của section nào đang nằm trong danh sách 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 khi scroll hoàn tất.\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ì kích hoạt lại IntersectionObserver sau timeout.\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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"}
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import { NgTemplateOutlet } from '@angular/common';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
import { inject, TemplateRef, Directive, input, computed, contentChild, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
4
|
+
import { I18nService } from '@sdcorejs/angular/i18n';
|
|
5
|
+
|
|
6
|
+
const DEFAULT_REDACTED_VALUE = '••••••';
|
|
7
|
+
function sdBuildAuditDiff(before, after, options = {}) {
|
|
8
|
+
const context = {
|
|
9
|
+
options,
|
|
10
|
+
fields: options.fields ?? [],
|
|
11
|
+
rows: [],
|
|
12
|
+
activeBefore: new WeakSet(),
|
|
13
|
+
activeAfter: new WeakSet(),
|
|
14
|
+
};
|
|
15
|
+
walkValue(context, before, after, true, true, '$', '$');
|
|
16
|
+
return context.rows.sort((left, right) => compareRows(left, right, context.fields));
|
|
17
|
+
}
|
|
18
|
+
function walkValue(context, before, after, beforePresent, afterPresent, path, configPath) {
|
|
19
|
+
if (isConfigured(context.fields, configPath, 'hidden'))
|
|
20
|
+
return;
|
|
21
|
+
if (isConfigured(context.fields, configPath, 'redacted')) {
|
|
22
|
+
addAtomicRow(context, before, after, beforePresent, afterPresent, path, configPath, true);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const field = findExactField(context.fields, configPath);
|
|
26
|
+
if (field?.format || field?.enumMap) {
|
|
27
|
+
addAtomicRow(context, before, after, beforePresent, afterPresent, path, configPath, false);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const beforeArray = Array.isArray(before);
|
|
31
|
+
const afterArray = Array.isArray(after);
|
|
32
|
+
if (beforeArray || afterArray) {
|
|
33
|
+
if ((!beforePresent && afterArray) || (beforeArray && !afterPresent) || (beforeArray && afterArray)) {
|
|
34
|
+
const arrayKey = field?.arrayKey;
|
|
35
|
+
if (arrayKey && walkStableArray(context, beforeArray ? before : [], afterArray ? after : [], path, configPath, arrayKey))
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
addAtomicRow(context, before, after, beforePresent, afterPresent, path, configPath, false);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const beforeObject = isPlainObject(before);
|
|
42
|
+
const afterObject = isPlainObject(after);
|
|
43
|
+
const canRecurse = (beforeObject && afterObject) || (beforeObject && !afterPresent) || (afterObject && !beforePresent);
|
|
44
|
+
if (canRecurse) {
|
|
45
|
+
if ((beforeObject && context.activeBefore.has(before)) || (afterObject && context.activeAfter.has(after)))
|
|
46
|
+
return;
|
|
47
|
+
if (beforeObject)
|
|
48
|
+
context.activeBefore.add(before);
|
|
49
|
+
if (afterObject)
|
|
50
|
+
context.activeAfter.add(after);
|
|
51
|
+
const beforeRecord = beforeObject ? before : {};
|
|
52
|
+
const afterRecord = afterObject ? after : {};
|
|
53
|
+
const keys = [...new Set([...Object.keys(beforeRecord), ...Object.keys(afterRecord)])].sort(compareText);
|
|
54
|
+
if (keys.length === 0) {
|
|
55
|
+
addAtomicRow(context, before, after, beforePresent, afterPresent, path, configPath, false);
|
|
56
|
+
if (beforeObject)
|
|
57
|
+
context.activeBefore.delete(before);
|
|
58
|
+
if (afterObject)
|
|
59
|
+
context.activeAfter.delete(after);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
for (const key of keys) {
|
|
63
|
+
const childBeforePresent = beforeObject && hasOwn(beforeRecord, key);
|
|
64
|
+
const childAfterPresent = afterObject && hasOwn(afterRecord, key);
|
|
65
|
+
walkValue(context, childBeforePresent ? beforeRecord[key] : undefined, childAfterPresent ? afterRecord[key] : undefined, childBeforePresent, childAfterPresent, path === '$' ? key : `${path}.${key}`, configPath === '$' ? key : `${configPath}.${key}`);
|
|
66
|
+
}
|
|
67
|
+
if (beforeObject)
|
|
68
|
+
context.activeBefore.delete(before);
|
|
69
|
+
if (afterObject)
|
|
70
|
+
context.activeAfter.delete(after);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
addAtomicRow(context, before, after, beforePresent, afterPresent, path, configPath, false);
|
|
74
|
+
}
|
|
75
|
+
function walkStableArray(context, before, after, path, configPath, keySelector) {
|
|
76
|
+
const beforeItems = indexStableArray(before, keySelector);
|
|
77
|
+
const afterItems = indexStableArray(after, keySelector);
|
|
78
|
+
if (!beforeItems || !afterItems)
|
|
79
|
+
return false;
|
|
80
|
+
const keys = [...new Set([...beforeItems.keys(), ...afterItems.keys()])].sort(compareText);
|
|
81
|
+
const keyName = typeof keySelector === 'string' ? keySelector : 'key';
|
|
82
|
+
for (const key of keys) {
|
|
83
|
+
const beforeItem = beforeItems.get(key);
|
|
84
|
+
const afterItem = afterItems.get(key);
|
|
85
|
+
const itemPath = `${path}[${keyName}=${encodeURIComponent(key)}]`;
|
|
86
|
+
const itemConfigPath = `${configPath}[]`;
|
|
87
|
+
if (!beforeItem || !afterItem) {
|
|
88
|
+
walkValue(context, beforeItem?.value, afterItem?.value, Boolean(beforeItem), Boolean(afterItem), itemPath, itemConfigPath);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
walkValue(context, beforeItem.value, afterItem.value, true, true, itemPath, itemConfigPath);
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
function indexStableArray(items, keySelector) {
|
|
96
|
+
const result = new Map();
|
|
97
|
+
for (const item of items) {
|
|
98
|
+
let key;
|
|
99
|
+
try {
|
|
100
|
+
key = typeof keySelector === 'function' ? keySelector(item) : isObject(item) ? item[keySelector] : undefined;
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
const serialized = serializeStableKey(key);
|
|
106
|
+
if (serialized === null || result.has(serialized))
|
|
107
|
+
return null;
|
|
108
|
+
result.set(serialized, { key, value: item });
|
|
109
|
+
}
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
function serializeStableKey(key) {
|
|
113
|
+
if (key === null)
|
|
114
|
+
return 'null:null';
|
|
115
|
+
switch (typeof key) {
|
|
116
|
+
case 'string':
|
|
117
|
+
case 'number':
|
|
118
|
+
case 'bigint':
|
|
119
|
+
case 'boolean':
|
|
120
|
+
return `${typeof key}:${String(key)}`;
|
|
121
|
+
default:
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function addAtomicRow(context, before, after, beforePresent, afterPresent, path, configPath, redacted) {
|
|
126
|
+
const kind = classifyChange(before, after, beforePresent, afterPresent);
|
|
127
|
+
if (kind === 'unchanged' && !context.options.includeUnchanged)
|
|
128
|
+
return;
|
|
129
|
+
const field = findExactField(context.fields, configPath);
|
|
130
|
+
const redactedValue = context.options.redactedValue ?? DEFAULT_REDACTED_VALUE;
|
|
131
|
+
const normalizedBefore = redacted
|
|
132
|
+
? beforePresent
|
|
133
|
+
? redactedValue
|
|
134
|
+
: undefined
|
|
135
|
+
: normalizeValue(before, beforePresent, 'before', kind, path, configPath, field, after);
|
|
136
|
+
const normalizedAfter = redacted
|
|
137
|
+
? afterPresent
|
|
138
|
+
? redactedValue
|
|
139
|
+
: undefined
|
|
140
|
+
: normalizeValue(after, afterPresent, 'after', kind, path, configPath, field, before);
|
|
141
|
+
context.rows.push({
|
|
142
|
+
id: path,
|
|
143
|
+
path,
|
|
144
|
+
configPath,
|
|
145
|
+
label: field?.label ?? (path === '$' ? (context.options.rootLabel ?? 'Value') : path),
|
|
146
|
+
kind,
|
|
147
|
+
before: normalizedBefore,
|
|
148
|
+
after: normalizedAfter,
|
|
149
|
+
beforePresent,
|
|
150
|
+
afterPresent,
|
|
151
|
+
redacted,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
function normalizeValue(value, present, side, kind, path, configPath, field, otherValue) {
|
|
155
|
+
if (!present)
|
|
156
|
+
return undefined;
|
|
157
|
+
const mapped = field?.enumMap && hasOwn(field.enumMap, String(value)) ? field.enumMap[String(value)] : value;
|
|
158
|
+
if (!field?.format)
|
|
159
|
+
return mapped;
|
|
160
|
+
try {
|
|
161
|
+
return field.format(mapped, {
|
|
162
|
+
path,
|
|
163
|
+
configPath,
|
|
164
|
+
side,
|
|
165
|
+
kind,
|
|
166
|
+
before: side === 'before' ? value : otherValue,
|
|
167
|
+
after: side === 'after' ? value : otherValue,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
return mapped;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function classifyChange(before, after, beforePresent, afterPresent) {
|
|
175
|
+
if (!beforePresent && afterPresent)
|
|
176
|
+
return 'added';
|
|
177
|
+
if (beforePresent && !afterPresent)
|
|
178
|
+
return 'removed';
|
|
179
|
+
return deepEqual(before, after) ? 'unchanged' : 'changed';
|
|
180
|
+
}
|
|
181
|
+
function deepEqual(left, right, seen = new WeakMap()) {
|
|
182
|
+
if (Object.is(left, right))
|
|
183
|
+
return true;
|
|
184
|
+
if (left instanceof Date && right instanceof Date)
|
|
185
|
+
return left.getTime() === right.getTime();
|
|
186
|
+
if (!isObject(left) || !isObject(right))
|
|
187
|
+
return false;
|
|
188
|
+
let rightSet = seen.get(left);
|
|
189
|
+
if (rightSet?.has(right))
|
|
190
|
+
return true;
|
|
191
|
+
if (!rightSet) {
|
|
192
|
+
rightSet = new WeakSet();
|
|
193
|
+
seen.set(left, rightSet);
|
|
194
|
+
}
|
|
195
|
+
rightSet.add(right);
|
|
196
|
+
if (Array.isArray(left) && Array.isArray(right)) {
|
|
197
|
+
if (left.length !== right.length)
|
|
198
|
+
return false;
|
|
199
|
+
return left.every((value, index) => deepEqual(value, right[index], seen));
|
|
200
|
+
}
|
|
201
|
+
if (!isPlainObject(left) || !isPlainObject(right))
|
|
202
|
+
return false;
|
|
203
|
+
const leftKeys = Object.keys(left).sort(compareText);
|
|
204
|
+
const rightKeys = Object.keys(right).sort(compareText);
|
|
205
|
+
if (leftKeys.length !== rightKeys.length || leftKeys.some((key, index) => key !== rightKeys[index]))
|
|
206
|
+
return false;
|
|
207
|
+
return leftKeys.every(key => deepEqual(left[key], right[key], seen));
|
|
208
|
+
}
|
|
209
|
+
function compareRows(left, right, fields) {
|
|
210
|
+
const leftOrder = explicitOrder(left.configPath, fields);
|
|
211
|
+
const rightOrder = explicitOrder(right.configPath, fields);
|
|
212
|
+
if (leftOrder !== rightOrder)
|
|
213
|
+
return leftOrder - rightOrder;
|
|
214
|
+
return compareText(left.path, right.path);
|
|
215
|
+
}
|
|
216
|
+
function explicitOrder(path, fields) {
|
|
217
|
+
const field = fields
|
|
218
|
+
.filter(candidate => Number.isFinite(candidate.order) && isPathOrDescendant(path, candidate.path))
|
|
219
|
+
.sort((left, right) => right.path.length - left.path.length)[0];
|
|
220
|
+
return field?.order ?? Number.POSITIVE_INFINITY;
|
|
221
|
+
}
|
|
222
|
+
function findExactField(fields, path) {
|
|
223
|
+
return fields.find(field => field.path === path);
|
|
224
|
+
}
|
|
225
|
+
function isConfigured(fields, path, property) {
|
|
226
|
+
return fields.some(field => Boolean(field[property]) && isPathOrDescendant(path, field.path));
|
|
227
|
+
}
|
|
228
|
+
function isPathOrDescendant(path, ancestor) {
|
|
229
|
+
return path === ancestor || path.startsWith(`${ancestor}.`) || path.startsWith(`${ancestor}[]`);
|
|
230
|
+
}
|
|
231
|
+
function isObject(value) {
|
|
232
|
+
return typeof value === 'object' && value !== null;
|
|
233
|
+
}
|
|
234
|
+
function isPlainObject(value) {
|
|
235
|
+
if (!isObject(value))
|
|
236
|
+
return false;
|
|
237
|
+
const prototype = Object.getPrototypeOf(value);
|
|
238
|
+
return prototype === Object.prototype || prototype === null;
|
|
239
|
+
}
|
|
240
|
+
function hasOwn(object, key) {
|
|
241
|
+
return Object.prototype.hasOwnProperty.call(object, key);
|
|
242
|
+
}
|
|
243
|
+
function compareText(left, right) {
|
|
244
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
class SdAuditDiffValueTemplateDirective {
|
|
248
|
+
template = inject(TemplateRef);
|
|
249
|
+
static ngTemplateContextGuard(_directive, _context) {
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SdAuditDiffValueTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
253
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.17", type: SdAuditDiffValueTemplateDirective, isStandalone: true, selector: "ng-template[sdAuditDiffValue]", ngImport: i0 });
|
|
254
|
+
}
|
|
255
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SdAuditDiffValueTemplateDirective, decorators: [{
|
|
256
|
+
type: Directive,
|
|
257
|
+
args: [{
|
|
258
|
+
selector: 'ng-template[sdAuditDiffValue]',
|
|
259
|
+
standalone: true,
|
|
260
|
+
}]
|
|
261
|
+
}] });
|
|
262
|
+
class SdAuditDiff {
|
|
263
|
+
before = input(undefined, ...(ngDevMode ? [{ debugName: "before" }] : /* istanbul ignore next */ []));
|
|
264
|
+
after = input(undefined, ...(ngDevMode ? [{ debugName: "after" }] : /* istanbul ignore next */ []));
|
|
265
|
+
options = input({}, ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
|
|
266
|
+
mode = input('table', ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
|
|
267
|
+
ariaLabel = input(undefined, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
268
|
+
#i18n = inject(I18nService);
|
|
269
|
+
rows = computed(() => {
|
|
270
|
+
const options = this.options();
|
|
271
|
+
return sdBuildAuditDiff(this.before(), this.after(), {
|
|
272
|
+
...options,
|
|
273
|
+
rootLabel: options.rootLabel ?? this.text('value.label'),
|
|
274
|
+
});
|
|
275
|
+
}, ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
|
|
276
|
+
valueTemplate = contentChild(SdAuditDiffValueTemplateDirective, ...(ngDevMode ? [{ debugName: "valueTemplate" }] : /* istanbul ignore next */ []));
|
|
277
|
+
text(key) {
|
|
278
|
+
return this.#i18n.t(`core.component.audit-diff.${key}`);
|
|
279
|
+
}
|
|
280
|
+
valueContext(row, side) {
|
|
281
|
+
return { $implicit: row[side], row, side };
|
|
282
|
+
}
|
|
283
|
+
displayValue(row, side) {
|
|
284
|
+
const present = side === 'before' ? row.beforePresent : row.afterPresent;
|
|
285
|
+
if (!present)
|
|
286
|
+
return this.text('value.not-set');
|
|
287
|
+
const value = row[side];
|
|
288
|
+
if (value === undefined)
|
|
289
|
+
return this.text('value.undefined');
|
|
290
|
+
if (value === null)
|
|
291
|
+
return this.text('value.null');
|
|
292
|
+
if (value instanceof Date)
|
|
293
|
+
return value.toISOString();
|
|
294
|
+
if (typeof value === 'boolean')
|
|
295
|
+
return this.text(`value.${value ? 'true' : 'false'}`);
|
|
296
|
+
if (typeof value === 'string')
|
|
297
|
+
return value;
|
|
298
|
+
if (typeof value === 'number' || typeof value === 'bigint')
|
|
299
|
+
return String(value);
|
|
300
|
+
return safeStringify(value);
|
|
301
|
+
}
|
|
302
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SdAuditDiff, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
303
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: SdAuditDiff, isStandalone: true, selector: "sd-audit-diff", inputs: { before: { classPropertyName: "before", publicName: "before", isSignal: true, isRequired: false, transformFunction: null }, after: { classPropertyName: "after", publicName: "after", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "valueTemplate", first: true, predicate: SdAuditDiffValueTemplateDirective, descendants: true, isSignal: true }], ngImport: i0, template: "@let currentRows = rows();\n@let customValue = valueTemplate();\n\n@if (currentRows.length === 0) {\n <p class=\"sd-audit-diff__empty\" data-audit-empty role=\"status\">{{ text('empty') }}</p>\n} @else if (mode() === 'table') {\n <div class=\"sd-audit-diff__table-scroll\">\n <table class=\"sd-audit-diff__table\" [attr.aria-label]=\"ariaLabel() || text('label')\">\n <thead>\n <tr>\n <th scope=\"col\">{{ text('field') }}</th>\n <th scope=\"col\">{{ text('before') }}</th>\n <th scope=\"col\">{{ text('after') }}</th>\n </tr>\n </thead>\n <tbody>\n @for (row of currentRows; track row.id) {\n <tr data-audit-row [attr.data-change-kind]=\"row.kind\">\n <th scope=\"row\">\n <span class=\"sd-audit-diff__field\">{{ row.label }}</span>\n <span class=\"sd-audit-diff__kind\">{{ text('kind.' + row.kind) }}</span>\n </th>\n <td data-audit-before>\n @if (customValue) {\n <ng-container\n [ngTemplateOutlet]=\"customValue.template\"\n [ngTemplateOutletContext]=\"valueContext(row, 'before')\"></ng-container>\n } @else {\n {{ displayValue(row, 'before') }}\n }\n </td>\n <td data-audit-after>\n @if (customValue) {\n <ng-container\n [ngTemplateOutlet]=\"customValue.template\"\n [ngTemplateOutletContext]=\"valueContext(row, 'after')\"></ng-container>\n } @else {\n {{ displayValue(row, 'after') }}\n }\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n} @else {\n <dl class=\"sd-audit-diff__details\" [attr.aria-label]=\"ariaLabel() || text('label')\">\n @for (row of currentRows; track row.id) {\n <div class=\"sd-audit-diff__detail\" data-audit-row [attr.data-change-kind]=\"row.kind\">\n <dt>\n <span class=\"sd-audit-diff__field\">{{ row.label }}</span>\n <span class=\"sd-audit-diff__kind\">{{ text('kind.' + row.kind) }}</span>\n </dt>\n <dd data-audit-before>\n <span class=\"sd-audit-diff__side-label\">{{ text('before') }}</span>\n @if (customValue) {\n <ng-container [ngTemplateOutlet]=\"customValue.template\" [ngTemplateOutletContext]=\"valueContext(row, 'before')\"></ng-container>\n } @else {\n <span>{{ displayValue(row, 'before') }}</span>\n }\n </dd>\n <dd data-audit-after>\n <span class=\"sd-audit-diff__side-label\">{{ text('after') }}</span>\n @if (customValue) {\n <ng-container [ngTemplateOutlet]=\"customValue.template\" [ngTemplateOutletContext]=\"valueContext(row, 'after')\"></ng-container>\n } @else {\n <span>{{ displayValue(row, 'after') }}</span>\n }\n </dd>\n </div>\n }\n </dl>\n}\n", styles: [":host{display:block}.sd-audit-diff__table-scroll{overflow-x:auto;border:1px solid var(--sd-border-color, #dfe3e8);border-radius:8px}.sd-audit-diff__table{width:100%;border-collapse:collapse;background:var(--sd-surface, #fff)}.sd-audit-diff__table th,.sd-audit-diff__table td{min-width:160px;padding:10px 12px;border-bottom:1px solid var(--sd-border-color, #dfe3e8);text-align:left;vertical-align:top;overflow-wrap:anywhere}.sd-audit-diff__table th:first-child{min-width:180px}.sd-audit-diff__table tbody tr:last-child>*{border-bottom:0}.sd-audit-diff__field,.sd-audit-diff__kind,.sd-audit-diff__side-label{display:block}.sd-audit-diff__kind,.sd-audit-diff__side-label{margin-top:2px;color:var(--sd-text-muted, #5f6772);font-size:.75rem;font-weight:400}.sd-audit-diff__details{display:grid;gap:12px;margin:0}.sd-audit-diff__detail{display:grid;grid-template-columns:minmax(140px,.8fr) repeat(2,minmax(0,1fr));gap:12px;padding:12px;border:1px solid var(--sd-border-color, #dfe3e8);border-radius:8px;background:var(--sd-surface, #fff)}.sd-audit-diff__detail dt,.sd-audit-diff__detail dd{min-width:0;margin:0;overflow-wrap:anywhere}.sd-audit-diff__empty{margin:0;padding:16px;border:1px dashed var(--sd-border-color, #dfe3e8);border-radius:8px;color:var(--sd-text-muted, #5f6772);text-align:center}@media(max-width:640px){.sd-audit-diff__detail{grid-template-columns:1fr}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
304
|
+
}
|
|
305
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SdAuditDiff, decorators: [{
|
|
306
|
+
type: Component,
|
|
307
|
+
args: [{ selector: 'sd-audit-diff', standalone: true, imports: [NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let currentRows = rows();\n@let customValue = valueTemplate();\n\n@if (currentRows.length === 0) {\n <p class=\"sd-audit-diff__empty\" data-audit-empty role=\"status\">{{ text('empty') }}</p>\n} @else if (mode() === 'table') {\n <div class=\"sd-audit-diff__table-scroll\">\n <table class=\"sd-audit-diff__table\" [attr.aria-label]=\"ariaLabel() || text('label')\">\n <thead>\n <tr>\n <th scope=\"col\">{{ text('field') }}</th>\n <th scope=\"col\">{{ text('before') }}</th>\n <th scope=\"col\">{{ text('after') }}</th>\n </tr>\n </thead>\n <tbody>\n @for (row of currentRows; track row.id) {\n <tr data-audit-row [attr.data-change-kind]=\"row.kind\">\n <th scope=\"row\">\n <span class=\"sd-audit-diff__field\">{{ row.label }}</span>\n <span class=\"sd-audit-diff__kind\">{{ text('kind.' + row.kind) }}</span>\n </th>\n <td data-audit-before>\n @if (customValue) {\n <ng-container\n [ngTemplateOutlet]=\"customValue.template\"\n [ngTemplateOutletContext]=\"valueContext(row, 'before')\"></ng-container>\n } @else {\n {{ displayValue(row, 'before') }}\n }\n </td>\n <td data-audit-after>\n @if (customValue) {\n <ng-container\n [ngTemplateOutlet]=\"customValue.template\"\n [ngTemplateOutletContext]=\"valueContext(row, 'after')\"></ng-container>\n } @else {\n {{ displayValue(row, 'after') }}\n }\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n} @else {\n <dl class=\"sd-audit-diff__details\" [attr.aria-label]=\"ariaLabel() || text('label')\">\n @for (row of currentRows; track row.id) {\n <div class=\"sd-audit-diff__detail\" data-audit-row [attr.data-change-kind]=\"row.kind\">\n <dt>\n <span class=\"sd-audit-diff__field\">{{ row.label }}</span>\n <span class=\"sd-audit-diff__kind\">{{ text('kind.' + row.kind) }}</span>\n </dt>\n <dd data-audit-before>\n <span class=\"sd-audit-diff__side-label\">{{ text('before') }}</span>\n @if (customValue) {\n <ng-container [ngTemplateOutlet]=\"customValue.template\" [ngTemplateOutletContext]=\"valueContext(row, 'before')\"></ng-container>\n } @else {\n <span>{{ displayValue(row, 'before') }}</span>\n }\n </dd>\n <dd data-audit-after>\n <span class=\"sd-audit-diff__side-label\">{{ text('after') }}</span>\n @if (customValue) {\n <ng-container [ngTemplateOutlet]=\"customValue.template\" [ngTemplateOutletContext]=\"valueContext(row, 'after')\"></ng-container>\n } @else {\n <span>{{ displayValue(row, 'after') }}</span>\n }\n </dd>\n </div>\n }\n </dl>\n}\n", styles: [":host{display:block}.sd-audit-diff__table-scroll{overflow-x:auto;border:1px solid var(--sd-border-color, #dfe3e8);border-radius:8px}.sd-audit-diff__table{width:100%;border-collapse:collapse;background:var(--sd-surface, #fff)}.sd-audit-diff__table th,.sd-audit-diff__table td{min-width:160px;padding:10px 12px;border-bottom:1px solid var(--sd-border-color, #dfe3e8);text-align:left;vertical-align:top;overflow-wrap:anywhere}.sd-audit-diff__table th:first-child{min-width:180px}.sd-audit-diff__table tbody tr:last-child>*{border-bottom:0}.sd-audit-diff__field,.sd-audit-diff__kind,.sd-audit-diff__side-label{display:block}.sd-audit-diff__kind,.sd-audit-diff__side-label{margin-top:2px;color:var(--sd-text-muted, #5f6772);font-size:.75rem;font-weight:400}.sd-audit-diff__details{display:grid;gap:12px;margin:0}.sd-audit-diff__detail{display:grid;grid-template-columns:minmax(140px,.8fr) repeat(2,minmax(0,1fr));gap:12px;padding:12px;border:1px solid var(--sd-border-color, #dfe3e8);border-radius:8px;background:var(--sd-surface, #fff)}.sd-audit-diff__detail dt,.sd-audit-diff__detail dd{min-width:0;margin:0;overflow-wrap:anywhere}.sd-audit-diff__empty{margin:0;padding:16px;border:1px dashed var(--sd-border-color, #dfe3e8);border-radius:8px;color:var(--sd-text-muted, #5f6772);text-align:center}@media(max-width:640px){.sd-audit-diff__detail{grid-template-columns:1fr}}\n"] }]
|
|
308
|
+
}], propDecorators: { before: [{ type: i0.Input, args: [{ isSignal: true, alias: "before", required: false }] }], after: [{ type: i0.Input, args: [{ isSignal: true, alias: "after", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], valueTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SdAuditDiffValueTemplateDirective), { isSignal: true }] }] } });
|
|
309
|
+
function safeStringify(value) {
|
|
310
|
+
const seen = new WeakSet();
|
|
311
|
+
try {
|
|
312
|
+
const result = JSON.stringify(value, (_key, current) => {
|
|
313
|
+
if (typeof current !== 'object' || current === null)
|
|
314
|
+
return current;
|
|
315
|
+
if (seen.has(current))
|
|
316
|
+
return '[Circular]';
|
|
317
|
+
seen.add(current);
|
|
318
|
+
return current;
|
|
319
|
+
});
|
|
320
|
+
return result ?? String(value);
|
|
321
|
+
}
|
|
322
|
+
catch {
|
|
323
|
+
return String(value);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Generated bundle index. Do not edit.
|
|
329
|
+
*/
|
|
330
|
+
|
|
331
|
+
export { SdAuditDiff, SdAuditDiffValueTemplateDirective, sdBuildAuditDiff };
|
|
332
|
+
//# sourceMappingURL=sdcorejs-angular-components-audit-diff.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdcorejs-angular-components-audit-diff.mjs","sources":["../../../projects/sdcorejs-angular/components/audit-diff/src/audit-diff.engine.ts","../../../projects/sdcorejs-angular/components/audit-diff/src/audit-diff.component.ts","../../../projects/sdcorejs-angular/components/audit-diff/src/audit-diff.component.html","../../../projects/sdcorejs-angular/components/audit-diff/sdcorejs-angular-components-audit-diff.ts"],"sourcesContent":["export type SdAuditDiffKind = 'added' | 'removed' | 'changed' | 'unchanged';\nexport type SdAuditDiffSide = 'before' | 'after';\nexport type SdAuditDiffArrayKey = string | ((item: unknown) => unknown);\n\nexport interface SdAuditDiffFormatContext {\n readonly path: string;\n readonly configPath: string;\n readonly side: SdAuditDiffSide;\n readonly kind: SdAuditDiffKind;\n readonly before: unknown;\n readonly after: unknown;\n}\n\nexport interface SdAuditDiffField {\n readonly path: string;\n readonly label?: string;\n readonly order?: number;\n readonly hidden?: boolean;\n readonly redacted?: boolean;\n readonly arrayKey?: SdAuditDiffArrayKey;\n readonly enumMap?: Readonly<Record<string, unknown>>;\n readonly format?: (value: unknown, context: SdAuditDiffFormatContext) => unknown;\n}\n\nexport interface SdAuditDiffOptions {\n readonly fields?: readonly SdAuditDiffField[];\n readonly includeUnchanged?: boolean;\n readonly redactedValue?: unknown;\n readonly rootLabel?: string;\n}\n\nexport interface SdAuditDiffRow {\n readonly id: string;\n readonly path: string;\n readonly configPath: string;\n readonly label: string;\n readonly kind: SdAuditDiffKind;\n readonly before: unknown;\n readonly after: unknown;\n readonly beforePresent: boolean;\n readonly afterPresent: boolean;\n readonly redacted: boolean;\n}\n\ninterface WalkContext {\n readonly options: SdAuditDiffOptions;\n readonly fields: readonly SdAuditDiffField[];\n readonly rows: SdAuditDiffRow[];\n readonly activeBefore: WeakSet<object>;\n readonly activeAfter: WeakSet<object>;\n}\n\ninterface StableArrayItem {\n readonly key: unknown;\n readonly value: unknown;\n}\n\nconst DEFAULT_REDACTED_VALUE = '••••••';\n\nexport function sdBuildAuditDiff(before: unknown, after: unknown, options: SdAuditDiffOptions = {}): SdAuditDiffRow[] {\n const context: WalkContext = {\n options,\n fields: options.fields ?? [],\n rows: [],\n activeBefore: new WeakSet<object>(),\n activeAfter: new WeakSet<object>(),\n };\n walkValue(context, before, after, true, true, '$', '$');\n return context.rows.sort((left, right) => compareRows(left, right, context.fields));\n}\n\nfunction walkValue(\n context: WalkContext,\n before: unknown,\n after: unknown,\n beforePresent: boolean,\n afterPresent: boolean,\n path: string,\n configPath: string\n): void {\n if (isConfigured(context.fields, configPath, 'hidden')) return;\n if (isConfigured(context.fields, configPath, 'redacted')) {\n addAtomicRow(context, before, after, beforePresent, afterPresent, path, configPath, true);\n return;\n }\n\n const field = findExactField(context.fields, configPath);\n if (field?.format || field?.enumMap) {\n addAtomicRow(context, before, after, beforePresent, afterPresent, path, configPath, false);\n return;\n }\n\n const beforeArray = Array.isArray(before);\n const afterArray = Array.isArray(after);\n if (beforeArray || afterArray) {\n if ((!beforePresent && afterArray) || (beforeArray && !afterPresent) || (beforeArray && afterArray)) {\n const arrayKey = field?.arrayKey;\n if (arrayKey && walkStableArray(context, beforeArray ? before : [], afterArray ? after : [], path, configPath, arrayKey)) return;\n }\n addAtomicRow(context, before, after, beforePresent, afterPresent, path, configPath, false);\n return;\n }\n\n const beforeObject = isPlainObject(before);\n const afterObject = isPlainObject(after);\n const canRecurse = (beforeObject && afterObject) || (beforeObject && !afterPresent) || (afterObject && !beforePresent);\n if (canRecurse) {\n if ((beforeObject && context.activeBefore.has(before)) || (afterObject && context.activeAfter.has(after))) return;\n if (beforeObject) context.activeBefore.add(before);\n if (afterObject) context.activeAfter.add(after);\n const beforeRecord = beforeObject ? before : {};\n const afterRecord = afterObject ? after : {};\n const keys = [...new Set([...Object.keys(beforeRecord), ...Object.keys(afterRecord)])].sort(compareText);\n if (keys.length === 0) {\n addAtomicRow(context, before, after, beforePresent, afterPresent, path, configPath, false);\n if (beforeObject) context.activeBefore.delete(before);\n if (afterObject) context.activeAfter.delete(after);\n return;\n }\n for (const key of keys) {\n const childBeforePresent = beforeObject && hasOwn(beforeRecord, key);\n const childAfterPresent = afterObject && hasOwn(afterRecord, key);\n walkValue(\n context,\n childBeforePresent ? beforeRecord[key] : undefined,\n childAfterPresent ? afterRecord[key] : undefined,\n childBeforePresent,\n childAfterPresent,\n path === '$' ? key : `${path}.${key}`,\n configPath === '$' ? key : `${configPath}.${key}`\n );\n }\n if (beforeObject) context.activeBefore.delete(before);\n if (afterObject) context.activeAfter.delete(after);\n return;\n }\n\n addAtomicRow(context, before, after, beforePresent, afterPresent, path, configPath, false);\n}\n\nfunction walkStableArray(\n context: WalkContext,\n before: readonly unknown[],\n after: readonly unknown[],\n path: string,\n configPath: string,\n keySelector: SdAuditDiffArrayKey\n): boolean {\n const beforeItems = indexStableArray(before, keySelector);\n const afterItems = indexStableArray(after, keySelector);\n if (!beforeItems || !afterItems) return false;\n\n const keys = [...new Set([...beforeItems.keys(), ...afterItems.keys()])].sort(compareText);\n const keyName = typeof keySelector === 'string' ? keySelector : 'key';\n for (const key of keys) {\n const beforeItem = beforeItems.get(key);\n const afterItem = afterItems.get(key);\n const itemPath = `${path}[${keyName}=${encodeURIComponent(key)}]`;\n const itemConfigPath = `${configPath}[]`;\n if (!beforeItem || !afterItem) {\n walkValue(context, beforeItem?.value, afterItem?.value, Boolean(beforeItem), Boolean(afterItem), itemPath, itemConfigPath);\n continue;\n }\n walkValue(context, beforeItem.value, afterItem.value, true, true, itemPath, itemConfigPath);\n }\n return true;\n}\n\nfunction indexStableArray(items: readonly unknown[], keySelector: SdAuditDiffArrayKey): Map<string, StableArrayItem> | null {\n const result = new Map<string, StableArrayItem>();\n for (const item of items) {\n let key: unknown;\n try {\n key = typeof keySelector === 'function' ? keySelector(item) : isObject(item) ? item[keySelector] : undefined;\n } catch {\n return null;\n }\n const serialized = serializeStableKey(key);\n if (serialized === null || result.has(serialized)) return null;\n result.set(serialized, { key, value: item });\n }\n return result;\n}\n\nfunction serializeStableKey(key: unknown): string | null {\n if (key === null) return 'null:null';\n switch (typeof key) {\n case 'string':\n case 'number':\n case 'bigint':\n case 'boolean':\n return `${typeof key}:${String(key)}`;\n default:\n return null;\n }\n}\n\nfunction addAtomicRow(\n context: WalkContext,\n before: unknown,\n after: unknown,\n beforePresent: boolean,\n afterPresent: boolean,\n path: string,\n configPath: string,\n redacted: boolean\n): void {\n const kind = classifyChange(before, after, beforePresent, afterPresent);\n if (kind === 'unchanged' && !context.options.includeUnchanged) return;\n\n const field = findExactField(context.fields, configPath);\n const redactedValue = context.options.redactedValue ?? DEFAULT_REDACTED_VALUE;\n const normalizedBefore = redacted\n ? beforePresent\n ? redactedValue\n : undefined\n : normalizeValue(before, beforePresent, 'before', kind, path, configPath, field, after);\n const normalizedAfter = redacted\n ? afterPresent\n ? redactedValue\n : undefined\n : normalizeValue(after, afterPresent, 'after', kind, path, configPath, field, before);\n\n context.rows.push({\n id: path,\n path,\n configPath,\n label: field?.label ?? (path === '$' ? (context.options.rootLabel ?? 'Value') : path),\n kind,\n before: normalizedBefore,\n after: normalizedAfter,\n beforePresent,\n afterPresent,\n redacted,\n });\n}\n\nfunction normalizeValue(\n value: unknown,\n present: boolean,\n side: SdAuditDiffSide,\n kind: SdAuditDiffKind,\n path: string,\n configPath: string,\n field: SdAuditDiffField | undefined,\n otherValue: unknown\n): unknown {\n if (!present) return undefined;\n const mapped = field?.enumMap && hasOwn(field.enumMap, String(value)) ? field.enumMap[String(value)] : value;\n if (!field?.format) return mapped;\n try {\n return field.format(mapped, {\n path,\n configPath,\n side,\n kind,\n before: side === 'before' ? value : otherValue,\n after: side === 'after' ? value : otherValue,\n });\n } catch {\n return mapped;\n }\n}\n\nfunction classifyChange(before: unknown, after: unknown, beforePresent: boolean, afterPresent: boolean): SdAuditDiffKind {\n if (!beforePresent && afterPresent) return 'added';\n if (beforePresent && !afterPresent) return 'removed';\n return deepEqual(before, after) ? 'unchanged' : 'changed';\n}\n\nfunction deepEqual(left: unknown, right: unknown, seen = new WeakMap<object, WeakSet<object>>()): boolean {\n if (Object.is(left, right)) return true;\n if (left instanceof Date && right instanceof Date) return left.getTime() === right.getTime();\n if (!isObject(left) || !isObject(right)) return false;\n let rightSet = seen.get(left);\n if (rightSet?.has(right)) return true;\n if (!rightSet) {\n rightSet = new WeakSet<object>();\n seen.set(left, rightSet);\n }\n rightSet.add(right);\n if (Array.isArray(left) && Array.isArray(right)) {\n if (left.length !== right.length) return false;\n return left.every((value, index) => deepEqual(value, right[index], seen));\n }\n if (!isPlainObject(left) || !isPlainObject(right)) return false;\n const leftKeys = Object.keys(left).sort(compareText);\n const rightKeys = Object.keys(right).sort(compareText);\n if (leftKeys.length !== rightKeys.length || leftKeys.some((key, index) => key !== rightKeys[index])) return false;\n return leftKeys.every(key => deepEqual(left[key], right[key], seen));\n}\n\nfunction compareRows(left: SdAuditDiffRow, right: SdAuditDiffRow, fields: readonly SdAuditDiffField[]): number {\n const leftOrder = explicitOrder(left.configPath, fields);\n const rightOrder = explicitOrder(right.configPath, fields);\n if (leftOrder !== rightOrder) return leftOrder - rightOrder;\n return compareText(left.path, right.path);\n}\n\nfunction explicitOrder(path: string, fields: readonly SdAuditDiffField[]): number {\n const field = fields\n .filter(candidate => Number.isFinite(candidate.order) && isPathOrDescendant(path, candidate.path))\n .sort((left, right) => right.path.length - left.path.length)[0];\n return field?.order ?? Number.POSITIVE_INFINITY;\n}\n\nfunction findExactField(fields: readonly SdAuditDiffField[], path: string): SdAuditDiffField | undefined {\n return fields.find(field => field.path === path);\n}\n\nfunction isConfigured(fields: readonly SdAuditDiffField[], path: string, property: 'hidden' | 'redacted'): boolean {\n return fields.some(field => Boolean(field[property]) && isPathOrDescendant(path, field.path));\n}\n\nfunction isPathOrDescendant(path: string, ancestor: string): boolean {\n return path === ancestor || path.startsWith(`${ancestor}.`) || path.startsWith(`${ancestor}[]`);\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (!isObject(value)) return false;\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n\nfunction hasOwn(object: object, key: PropertyKey): boolean {\n return Object.prototype.hasOwnProperty.call(object, key);\n}\n\nfunction compareText(left: string, right: string): number {\n return left < right ? -1 : left > right ? 1 : 0;\n}\n","import { NgTemplateOutlet } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, Directive, TemplateRef, computed, contentChild, inject, input } from '@angular/core';\nimport { I18nService } from '@sdcorejs/angular/i18n';\nimport { SdAuditDiffOptions, SdAuditDiffRow, SdAuditDiffSide, sdBuildAuditDiff } from './audit-diff.engine';\n\nexport type SdAuditDiffMode = 'table' | 'detail-list';\n\nexport interface SdAuditDiffValueTemplateContext {\n readonly $implicit: unknown;\n readonly row: SdAuditDiffRow;\n readonly side: SdAuditDiffSide;\n}\n\n@Directive({\n selector: 'ng-template[sdAuditDiffValue]',\n standalone: true,\n})\nexport class SdAuditDiffValueTemplateDirective {\n readonly template = inject<TemplateRef<SdAuditDiffValueTemplateContext>>(TemplateRef);\n\n static ngTemplateContextGuard(\n _directive: SdAuditDiffValueTemplateDirective,\n _context: unknown\n ): _context is SdAuditDiffValueTemplateContext {\n return true;\n }\n}\n\n@Component({\n selector: 'sd-audit-diff',\n standalone: true,\n imports: [NgTemplateOutlet],\n templateUrl: './audit-diff.component.html',\n styleUrl: './audit-diff.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SdAuditDiff {\n readonly before = input<unknown>(undefined);\n readonly after = input<unknown>(undefined);\n readonly options = input<SdAuditDiffOptions>({});\n readonly mode = input<SdAuditDiffMode>('table');\n readonly ariaLabel = input<string | undefined>(undefined);\n\n readonly #i18n = inject(I18nService);\n readonly rows = computed(() => {\n const options = this.options();\n return sdBuildAuditDiff(this.before(), this.after(), {\n ...options,\n rootLabel: options.rootLabel ?? this.text('value.label'),\n });\n });\n protected readonly valueTemplate = contentChild(SdAuditDiffValueTemplateDirective);\n\n protected text(key: string): string {\n return this.#i18n.t(`core.component.audit-diff.${key}`);\n }\n\n protected valueContext(row: SdAuditDiffRow, side: SdAuditDiffSide): SdAuditDiffValueTemplateContext {\n return { $implicit: row[side], row, side };\n }\n\n protected displayValue(row: SdAuditDiffRow, side: SdAuditDiffSide): string {\n const present = side === 'before' ? row.beforePresent : row.afterPresent;\n if (!present) return this.text('value.not-set');\n const value = row[side];\n if (value === undefined) return this.text('value.undefined');\n if (value === null) return this.text('value.null');\n if (value instanceof Date) return value.toISOString();\n if (typeof value === 'boolean') return this.text(`value.${value ? 'true' : 'false'}`);\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'bigint') return String(value);\n return safeStringify(value);\n }\n}\n\nfunction safeStringify(value: unknown): string {\n const seen = new WeakSet<object>();\n try {\n const result = JSON.stringify(value, (_key, current: unknown) => {\n if (typeof current !== 'object' || current === null) return current;\n if (seen.has(current)) return '[Circular]';\n seen.add(current);\n return current;\n });\n return result ?? String(value);\n } catch {\n return String(value);\n }\n}\n","@let currentRows = rows();\n@let customValue = valueTemplate();\n\n@if (currentRows.length === 0) {\n <p class=\"sd-audit-diff__empty\" data-audit-empty role=\"status\">{{ text('empty') }}</p>\n} @else if (mode() === 'table') {\n <div class=\"sd-audit-diff__table-scroll\">\n <table class=\"sd-audit-diff__table\" [attr.aria-label]=\"ariaLabel() || text('label')\">\n <thead>\n <tr>\n <th scope=\"col\">{{ text('field') }}</th>\n <th scope=\"col\">{{ text('before') }}</th>\n <th scope=\"col\">{{ text('after') }}</th>\n </tr>\n </thead>\n <tbody>\n @for (row of currentRows; track row.id) {\n <tr data-audit-row [attr.data-change-kind]=\"row.kind\">\n <th scope=\"row\">\n <span class=\"sd-audit-diff__field\">{{ row.label }}</span>\n <span class=\"sd-audit-diff__kind\">{{ text('kind.' + row.kind) }}</span>\n </th>\n <td data-audit-before>\n @if (customValue) {\n <ng-container\n [ngTemplateOutlet]=\"customValue.template\"\n [ngTemplateOutletContext]=\"valueContext(row, 'before')\"></ng-container>\n } @else {\n {{ displayValue(row, 'before') }}\n }\n </td>\n <td data-audit-after>\n @if (customValue) {\n <ng-container\n [ngTemplateOutlet]=\"customValue.template\"\n [ngTemplateOutletContext]=\"valueContext(row, 'after')\"></ng-container>\n } @else {\n {{ displayValue(row, 'after') }}\n }\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n} @else {\n <dl class=\"sd-audit-diff__details\" [attr.aria-label]=\"ariaLabel() || text('label')\">\n @for (row of currentRows; track row.id) {\n <div class=\"sd-audit-diff__detail\" data-audit-row [attr.data-change-kind]=\"row.kind\">\n <dt>\n <span class=\"sd-audit-diff__field\">{{ row.label }}</span>\n <span class=\"sd-audit-diff__kind\">{{ text('kind.' + row.kind) }}</span>\n </dt>\n <dd data-audit-before>\n <span class=\"sd-audit-diff__side-label\">{{ text('before') }}</span>\n @if (customValue) {\n <ng-container [ngTemplateOutlet]=\"customValue.template\" [ngTemplateOutletContext]=\"valueContext(row, 'before')\"></ng-container>\n } @else {\n <span>{{ displayValue(row, 'before') }}</span>\n }\n </dd>\n <dd data-audit-after>\n <span class=\"sd-audit-diff__side-label\">{{ text('after') }}</span>\n @if (customValue) {\n <ng-container [ngTemplateOutlet]=\"customValue.template\" [ngTemplateOutletContext]=\"valueContext(row, 'after')\"></ng-container>\n } @else {\n <span>{{ displayValue(row, 'after') }}</span>\n }\n </dd>\n </div>\n }\n </dl>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|