@simplysm/angular 14.0.40 → 14.0.42
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/dist/controls/collapse/sd-collapse-icon.d.ts +2 -4
- package/dist/controls/collapse/sd-collapse-icon.d.ts.map +1 -1
- package/dist/controls/collapse/sd-collapse-icon.js +5 -5
- package/dist/core/app-structure/sd-app-structure.provider.d.ts +2 -2
- package/dist/core/app-structure/sd-app-structure.provider.d.ts.map +1 -1
- package/dist/core/app-structure/sd-app-structure.provider.js +4 -4
- package/dist/core/config/sd-local-storage.provider.d.ts +1 -1
- package/dist/core/config/sd-local-storage.provider.d.ts.map +1 -1
- package/dist/core/config/sd-local-storage.provider.js +4 -4
- package/dist/core/error-handler/sd-global-error-handler.plugin.d.ts +1 -1
- package/dist/core/error-handler/sd-global-error-handler.plugin.d.ts.map +1 -1
- package/dist/core/error-handler/sd-global-error-handler.plugin.js +3 -3
- package/dist/core/modal/sd-modal.d.ts +4 -3
- package/dist/core/modal/sd-modal.d.ts.map +1 -1
- package/dist/core/modal/sd-modal.js +14 -12
- package/dist/core/modal/sd-modal.provider.d.ts +1 -0
- package/dist/core/modal/sd-modal.provider.d.ts.map +1 -1
- package/dist/core/routing/injectViewTitleSignal.js +3 -3
- package/dist/core/routing/injectViewTypeSignal.js +2 -2
- package/dist/core/routing/sd-router-link.d.ts +1 -1
- package/dist/core/routing/sd-router-link.d.ts.map +1 -1
- package/dist/core/routing/sd-router-link.js +4 -4
- package/dist/core/routing/setupCanDeactivate.js +3 -3
- package/dist/core/service-client/sd-service-client-factory.provider.d.ts +2 -2
- package/dist/core/service-client/sd-service-client-factory.provider.d.ts.map +1 -1
- package/dist/core/service-client/sd-service-client-factory.provider.js +4 -4
- package/dist/core/shared-data/sd-shared-data.provider.d.ts +4 -3
- package/dist/core/shared-data/sd-shared-data.provider.d.ts.map +1 -1
- package/dist/core/shared-data/sd-shared-data.provider.js +4 -4
- package/dist/core/toast/sd-toast.provider.d.ts +3 -3
- package/dist/core/toast/sd-toast.provider.d.ts.map +1 -1
- package/dist/core/toast/sd-toast.provider.js +2 -2
- package/dist/data/data-detail/sd-data-detail.base.d.ts +6 -4
- package/dist/data/data-detail/sd-data-detail.base.d.ts.map +1 -1
- package/dist/data/data-select-button/sd-data-select-button.base.d.ts +2 -2
- package/dist/data/data-select-button/sd-data-select-button.base.d.ts.map +1 -1
- package/dist/data/data-sheet/sd-data-sheet.d.ts.map +1 -1
- package/dist/data/data-sheet/sd-data-sheet.js +75 -43
- package/dist/data/sheet/sd-sheet-column-cell-template.d.ts +9 -0
- package/dist/data/sheet/sd-sheet-column-cell-template.d.ts.map +1 -0
- package/dist/data/sheet/sd-sheet-column-cell-template.js +17 -0
- package/dist/data/sheet/sd-sheet-column.d.ts +10 -7
- package/dist/data/sheet/sd-sheet-column.d.ts.map +1 -1
- package/dist/data/sheet/sd-sheet-column.js +10 -6
- package/dist/data/sheet/sd-sheet-config.modal.d.ts +1 -1
- package/dist/data/sheet/sd-sheet-config.modal.d.ts.map +1 -1
- package/dist/data/sheet/sd-sheet.d.ts +4 -3
- package/dist/data/sheet/sd-sheet.d.ts.map +1 -1
- package/dist/data/sheet/sd-sheet.js +61 -36
- package/dist/data/sheet/types.d.ts +2 -0
- package/dist/data/sheet/types.d.ts.map +1 -1
- package/dist/data/sheet/useSheetCellStyling.d.ts.map +1 -1
- package/dist/data/sheet/useSheetCellStyling.js +7 -1
- package/dist/data/sheet/useSheetLayoutEngine.d.ts.map +1 -1
- package/dist/data/sheet/useSheetLayoutEngine.js +2 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/layout/base-container/sd-base-container.d.ts +1 -1
- package/dist/layout/base-container/sd-base-container.d.ts.map +1 -1
- package/dist/layout/base-container/sd-base-container.js +2 -2
- package/package.json +6 -6
- package/src/controls/collapse/sd-collapse-icon.ts +2 -3
- package/src/core/app-structure/sd-app-structure.provider.ts +4 -4
- package/src/core/config/sd-local-storage.provider.ts +4 -4
- package/src/core/error-handler/sd-global-error-handler.plugin.ts +3 -3
- package/src/core/modal/sd-modal.provider.ts +1 -0
- package/src/core/modal/sd-modal.ts +10 -9
- package/src/core/routing/injectViewTitleSignal.ts +3 -3
- package/src/core/routing/injectViewTypeSignal.ts +2 -2
- package/src/core/routing/sd-router-link.ts +4 -4
- package/src/core/routing/setupCanDeactivate.ts +3 -3
- package/src/core/service-client/sd-service-client-factory.provider.ts +4 -4
- package/src/core/shared-data/sd-shared-data.provider.ts +5 -5
- package/src/core/toast/sd-toast.provider.ts +6 -6
- package/src/data/data-detail/sd-data-detail.base.ts +3 -3
- package/src/data/data-select-button/sd-data-select-button.base.ts +1 -1
- package/src/data/data-sheet/sd-data-sheet.ts +14 -5
- package/src/data/sheet/sd-sheet-column-cell-template.ts +17 -0
- package/src/data/sheet/sd-sheet-column.ts +12 -5
- package/src/data/sheet/sd-sheet.ts +14 -3
- package/src/data/sheet/types.ts +2 -0
- package/src/data/sheet/useSheetCellStyling.ts +5 -1
- package/src/data/sheet/useSheetLayoutEngine.ts +2 -0
- package/src/index.ts +2 -1
- package/src/layout/base-container/sd-base-container.ts +2 -2
|
@@ -38,7 +38,7 @@ import "@simplysm/core-browser";
|
|
|
38
38
|
(keydown)="onDialogKeydown($event)"
|
|
39
39
|
(focus)="onDialogFocus()">
|
|
40
40
|
@if (!hideHeader()) {
|
|
41
|
-
<div class="_header" (mousedown)="onHeaderMouseDown($event)">
|
|
41
|
+
<div class="_header" (mousedown)="onHeaderMouseDown($event)" [style]="headerStyle()">
|
|
42
42
|
<span class="_title">{{ title() }}</span>
|
|
43
43
|
@if (actionTplRef()) {
|
|
44
44
|
<ng-container *ngTemplateOutlet="actionTplRef()!" />
|
|
@@ -285,8 +285,8 @@ import "@simplysm/core-browser";
|
|
|
285
285
|
})
|
|
286
286
|
export class SdModal {
|
|
287
287
|
private readonly _elRef = inject(ElementRef<HTMLElement>);
|
|
288
|
-
private readonly
|
|
289
|
-
private readonly
|
|
288
|
+
private readonly _sdActivatedModal = inject(SdActivatedModalProvider, { optional: true });
|
|
289
|
+
private readonly _sdSystemConfig = inject(SdSystemConfigProvider, { optional: true });
|
|
290
290
|
private readonly _errorHandler = inject(ErrorHandler);
|
|
291
291
|
private readonly _focusTrap = injectFocusTrap();
|
|
292
292
|
|
|
@@ -297,6 +297,7 @@ export class SdModal {
|
|
|
297
297
|
title = input("");
|
|
298
298
|
hideHeader = input(false);
|
|
299
299
|
hideCloseButton = input(false);
|
|
300
|
+
headerStyle = input<string | undefined>(undefined);
|
|
300
301
|
useCloseByBackdrop = input(true);
|
|
301
302
|
useCloseByEscapeKey = input(true);
|
|
302
303
|
float = input(false);
|
|
@@ -347,7 +348,7 @@ export class SdModal {
|
|
|
347
348
|
// key 기반 설정 복원
|
|
348
349
|
effect(() => {
|
|
349
350
|
const k = this.key();
|
|
350
|
-
if (k === undefined || this.
|
|
351
|
+
if (k === undefined || this._sdSystemConfig == null) return;
|
|
351
352
|
|
|
352
353
|
void this._restoreConfig(k).catch((err) => this._errorHandler.handleError(err));
|
|
353
354
|
});
|
|
@@ -389,7 +390,7 @@ export class SdModal {
|
|
|
389
390
|
}
|
|
390
391
|
|
|
391
392
|
private _requestClose(): void {
|
|
392
|
-
if (this.
|
|
393
|
+
if (this._sdActivatedModal !== null && !this._sdActivatedModal.canDeactivateFn()) {
|
|
393
394
|
return;
|
|
394
395
|
}
|
|
395
396
|
void this._saveConfig().catch((err) => this._errorHandler.handleError(err));
|
|
@@ -418,7 +419,7 @@ export class SdModal {
|
|
|
418
419
|
|
|
419
420
|
private async _saveConfig(): Promise<void> {
|
|
420
421
|
const k = this.key();
|
|
421
|
-
if (k === undefined || this.
|
|
422
|
+
if (k === undefined || this._sdSystemConfig == null) return;
|
|
422
423
|
|
|
423
424
|
const dialogEl = this._getDialogEl();
|
|
424
425
|
if (dialogEl === null) return;
|
|
@@ -429,13 +430,13 @@ export class SdModal {
|
|
|
429
430
|
if (dialogEl.style.left !== "") config["left"] = dialogEl.style.left;
|
|
430
431
|
if (dialogEl.style.top !== "") config["top"] = dialogEl.style.top;
|
|
431
432
|
|
|
432
|
-
await this.
|
|
433
|
+
await this._sdSystemConfig.setAsync(`sd-modal.${k}` as any, config as any);
|
|
433
434
|
}
|
|
434
435
|
|
|
435
436
|
private async _restoreConfig(k: string): Promise<void> {
|
|
436
|
-
if (this.
|
|
437
|
+
if (this._sdSystemConfig == null) return;
|
|
437
438
|
|
|
438
|
-
const config = (await this.
|
|
439
|
+
const config = (await this._sdSystemConfig.getAsync(`sd-modal.${k}` as any)) as
|
|
439
440
|
| Record<string, string | undefined>
|
|
440
441
|
| undefined;
|
|
441
442
|
if (config == null) return;
|
|
@@ -5,15 +5,15 @@ import { injectFullPageCodeSignal } from "./injectFullPageCodeSignal";
|
|
|
5
5
|
import { injectCurrentPageCodeSignal } from "./injectCurrentPageCodeSignal";
|
|
6
6
|
|
|
7
7
|
export function injectViewTitleSignal(): Signal<string> {
|
|
8
|
-
const
|
|
8
|
+
const sdActivatedModal = inject(SdActivatedModalProvider, { optional: true });
|
|
9
9
|
const sdAppStructure = inject(SdAppStructureProvider);
|
|
10
10
|
|
|
11
11
|
const fullPageCode = injectFullPageCodeSignal();
|
|
12
12
|
const currPageCode = injectCurrentPageCodeSignal();
|
|
13
13
|
|
|
14
14
|
return computed(() => {
|
|
15
|
-
if (
|
|
16
|
-
return
|
|
15
|
+
if (sdActivatedModal != null) {
|
|
16
|
+
return sdActivatedModal.modalComponent()?.title() ?? "";
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
try {
|
|
@@ -5,14 +5,14 @@ import { injectCurrentPageCodeSignal } from "./injectCurrentPageCodeSignal";
|
|
|
5
5
|
import { injectFullPageCodeSignal } from "./injectFullPageCodeSignal";
|
|
6
6
|
|
|
7
7
|
export function injectViewTypeSignal(getComp: () => object): Signal<SdViewType> {
|
|
8
|
-
const
|
|
8
|
+
const sdActivatedModal = inject(SdActivatedModalProvider, { optional: true });
|
|
9
9
|
const activatedRoute = inject(ActivatedRoute, { optional: true });
|
|
10
10
|
|
|
11
11
|
const fullPageCode = injectFullPageCodeSignal();
|
|
12
12
|
const currPageCode = injectCurrentPageCodeSignal();
|
|
13
13
|
|
|
14
14
|
return computed<SdViewType>(() => {
|
|
15
|
-
if (
|
|
15
|
+
if (sdActivatedModal != null) {
|
|
16
16
|
return "modal";
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -12,7 +12,7 @@ import { SdNavigateWindowProvider } from "./sd-navigate-window.provider";
|
|
|
12
12
|
})
|
|
13
13
|
export class SdRouterLink {
|
|
14
14
|
private readonly _router = inject(Router);
|
|
15
|
-
private readonly
|
|
15
|
+
private readonly _sdNavigateWindow = inject(SdNavigateWindowProvider);
|
|
16
16
|
|
|
17
17
|
option = input<
|
|
18
18
|
| {
|
|
@@ -39,13 +39,13 @@ export class SdRouterLink {
|
|
|
39
39
|
event.preventDefault();
|
|
40
40
|
event.stopPropagation();
|
|
41
41
|
|
|
42
|
-
if (this.
|
|
42
|
+
if (this._sdNavigateWindow.isWindow) {
|
|
43
43
|
const width = option.window?.width ?? 800;
|
|
44
44
|
const height = option.window?.height ?? 800;
|
|
45
45
|
const qp = option.queryParams
|
|
46
46
|
? "?" + new URLSearchParams(option.queryParams).toString()
|
|
47
47
|
: "";
|
|
48
|
-
this.
|
|
48
|
+
this._sdNavigateWindow.open(
|
|
49
49
|
option.link + qp,
|
|
50
50
|
option.params,
|
|
51
51
|
`width=${width},height=${height}`,
|
|
@@ -54,7 +54,7 @@ export class SdRouterLink {
|
|
|
54
54
|
const qp = option.queryParams
|
|
55
55
|
? "?" + new URLSearchParams(option.queryParams).toString()
|
|
56
56
|
: "";
|
|
57
|
-
this.
|
|
57
|
+
this._sdNavigateWindow.open(option.link + qp, option.params);
|
|
58
58
|
} else if (option.outletName === undefined) {
|
|
59
59
|
await this._router.navigate(
|
|
60
60
|
[option.link, ...(option.params ? [option.params] : [])],
|
|
@@ -3,12 +3,12 @@ import { ActivatedRoute, type CanDeactivateFn } from "@angular/router";
|
|
|
3
3
|
import { SdActivatedModalProvider } from "../modal/sd-activated-modal.provider";
|
|
4
4
|
|
|
5
5
|
export function setupCanDeactivate(fn: () => boolean): void {
|
|
6
|
-
const
|
|
6
|
+
const sdActivatedModal = inject(SdActivatedModalProvider, { optional: true });
|
|
7
7
|
const activatedRoute = inject(ActivatedRoute, { optional: true });
|
|
8
8
|
const elRef = inject(ElementRef);
|
|
9
9
|
|
|
10
|
-
if (
|
|
11
|
-
|
|
10
|
+
if (sdActivatedModal != null) {
|
|
11
|
+
sdActivatedModal.canDeactivateFn = fn;
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -6,8 +6,8 @@ import { SdToastProvider } from "../toast/sd-toast.provider";
|
|
|
6
6
|
|
|
7
7
|
@Injectable({ providedIn: "root" })
|
|
8
8
|
export class SdServiceClientFactoryProvider {
|
|
9
|
-
private readonly
|
|
10
|
-
private readonly
|
|
9
|
+
private readonly _sdToast = inject(SdToastProvider);
|
|
10
|
+
private readonly _sdAngularConfig = inject(SdAngularConfigProvider);
|
|
11
11
|
private readonly _destroyRef = inject(DestroyRef);
|
|
12
12
|
|
|
13
13
|
private readonly _clientMap = new Map<string, ServiceClient>();
|
|
@@ -43,7 +43,7 @@ export class SdServiceClientFactoryProvider {
|
|
|
43
43
|
...options,
|
|
44
44
|
};
|
|
45
45
|
|
|
46
|
-
const client = createServiceClient(this.
|
|
46
|
+
const client = createServiceClient(this._sdAngularConfig.clientName, mergedOptions);
|
|
47
47
|
|
|
48
48
|
client.on("request-progress", (state: ServiceProgressState) => {
|
|
49
49
|
this._handleProgress("요청을 전송하는 중입니다.", state);
|
|
@@ -85,7 +85,7 @@ export class SdServiceClientFactoryProvider {
|
|
|
85
85
|
|
|
86
86
|
let progressSignal = this._progressMap.get(uuid);
|
|
87
87
|
if (progressSignal == null) {
|
|
88
|
-
progressSignal = this.
|
|
88
|
+
progressSignal = this._sdToast.info(message, true);
|
|
89
89
|
this._progressMap.set(uuid, progressSignal);
|
|
90
90
|
}
|
|
91
91
|
|
|
@@ -40,8 +40,8 @@ interface SharedDataEntry<T extends SharedDataBase<string | number>> {
|
|
|
40
40
|
|
|
41
41
|
@Injectable()
|
|
42
42
|
export abstract class SdSharedDataProvider<T extends Record<string, SharedDataBase<string | number>>> {
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
protected readonly _sdServiceClientFactory = inject(SdServiceClientFactoryProvider);
|
|
44
|
+
protected readonly _errorHandler = inject(ErrorHandler);
|
|
45
45
|
|
|
46
46
|
readonly loadingCount: WritableSignal<number> = signal(0);
|
|
47
47
|
|
|
@@ -54,7 +54,7 @@ export abstract class SdSharedDataProvider<T extends Record<string, SharedDataBa
|
|
|
54
54
|
if (existing != null) {
|
|
55
55
|
// 기존 리스너 키 초기화 + generation 증가로 이전 이벤트 무시
|
|
56
56
|
if (existing.listenerKey != null) {
|
|
57
|
-
const client = this.
|
|
57
|
+
const client = this._sdServiceClientFactory.get(existing.info.serviceKey);
|
|
58
58
|
void client.removeListener(existing.listenerKey);
|
|
59
59
|
existing.listenerKey = undefined;
|
|
60
60
|
}
|
|
@@ -109,7 +109,7 @@ export abstract class SdSharedDataProvider<T extends Record<string, SharedDataBa
|
|
|
109
109
|
throw new Error(`등록되지 않은 공유 데이터: ${name as string}`);
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
const client = this.
|
|
112
|
+
const client = this._sdServiceClientFactory.get(entry.info.serviceKey);
|
|
113
113
|
const event = client.getEvent<typeof SdSharedDataChangeEvent>("SdSharedDataChange");
|
|
114
114
|
await event.emit(
|
|
115
115
|
(item) => item.name === (name as string) && obj.equal(item.filter, entry.info.filter),
|
|
@@ -137,7 +137,7 @@ export abstract class SdSharedDataProvider<T extends Record<string, SharedDataBa
|
|
|
137
137
|
|
|
138
138
|
// 이벤트 리스너 등록
|
|
139
139
|
if (entry.listenerKey == null) {
|
|
140
|
-
const client = this.
|
|
140
|
+
const client = this._sdServiceClientFactory.get(entry.info.serviceKey);
|
|
141
141
|
const event = client.getEvent<typeof SdSharedDataChangeEvent>("SdSharedDataChange");
|
|
142
142
|
entry.listenerKey = await event.addListener(
|
|
143
143
|
{ name, filter: entry.info.filter },
|
|
@@ -36,7 +36,7 @@ export class SdToastProvider {
|
|
|
36
36
|
private readonly _appRef = inject(ApplicationRef);
|
|
37
37
|
private readonly _envInjector = inject(EnvironmentInjector);
|
|
38
38
|
private readonly _injector = inject(Injector);
|
|
39
|
-
private readonly
|
|
39
|
+
private readonly _sdSystemLog = inject(SdSystemLogProvider);
|
|
40
40
|
|
|
41
41
|
alertThemes = signal<SdToastSeverity[]>([]);
|
|
42
42
|
overlap = signal(false);
|
|
@@ -145,11 +145,11 @@ export class SdToastProvider {
|
|
|
145
145
|
});
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
async try<R>(fn: () => Promise<R
|
|
149
|
-
|
|
148
|
+
async try<R>(fn: () => Promise<R>, messageFn?: (err: Error) => string): Promise<R | undefined>;
|
|
149
|
+
try<R>(fn: () => R, messageFn?: (err: Error) => string): R | undefined;
|
|
150
150
|
async try<R>(
|
|
151
|
-
fn: () => Promise<R
|
|
152
|
-
messageFn?: (err:
|
|
151
|
+
fn: () => Promise<R> | R,
|
|
152
|
+
messageFn?: (err: Error) => string,
|
|
153
153
|
): Promise<R | undefined> {
|
|
154
154
|
try {
|
|
155
155
|
return await fn();
|
|
@@ -160,7 +160,7 @@ export class SdToastProvider {
|
|
|
160
160
|
|
|
161
161
|
const message = messageFn !== undefined ? messageFn(err) : err.message;
|
|
162
162
|
this.danger(message);
|
|
163
|
-
await this.
|
|
163
|
+
await this._sdSystemLog.writeAsync("error", err.stack ?? err.message);
|
|
164
164
|
return undefined;
|
|
165
165
|
}
|
|
166
166
|
}
|
|
@@ -47,9 +47,9 @@ export abstract class SdDataDetailBase<T extends object, R = boolean>
|
|
|
47
47
|
|
|
48
48
|
//-- implement
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
protected readonly _sdToast = inject(SdToastProvider);
|
|
51
|
+
protected readonly _sdSharedData = inject(SdSharedDataProvider);
|
|
52
|
+
protected readonly _errorHandler = inject(ErrorHandler);
|
|
53
53
|
|
|
54
54
|
viewType = injectViewTypeSignal(() => this);
|
|
55
55
|
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import { SdButton } from "../../controls/button/sd-button";
|
|
14
14
|
import { SdForm } from "../../controls/form/sd-form";
|
|
15
15
|
import { SdSheetColumn } from "../sheet/sd-sheet-column";
|
|
16
|
+
import { SdSheetColumnCellTemplate } from "../sheet/sd-sheet-column-cell-template";
|
|
16
17
|
import { SdSheet } from "../sheet/sd-sheet";
|
|
17
18
|
import { injectParent } from "../../core/injectParent";
|
|
18
19
|
import { FormatPipe } from "../../core/format.pipe";
|
|
@@ -45,6 +46,7 @@ import { SdDataSheetBase } from "./sd-data-sheet.base";
|
|
|
45
46
|
SdButton,
|
|
46
47
|
SdSheet,
|
|
47
48
|
SdSheetColumn,
|
|
49
|
+
SdSheetColumnCellTemplate,
|
|
48
50
|
NgTemplateOutlet,
|
|
49
51
|
SdBaseContainer,
|
|
50
52
|
FormatPipe,
|
|
@@ -214,7 +216,7 @@ import { SdDataSheetBase } from "./sd-data-sheet.base";
|
|
|
214
216
|
parent.itemPropInfo.isDeleted
|
|
215
217
|
) {
|
|
216
218
|
<sd-sheet-column [fixed]="true" [key]="parent.itemPropInfo.isDeleted!">
|
|
217
|
-
<ng-template
|
|
219
|
+
<ng-template [cell]="parent.items()" let-item="item">
|
|
218
220
|
<div class="p-xs-sm tx-center">
|
|
219
221
|
<sd-anchor
|
|
220
222
|
[theme]="'danger'"
|
|
@@ -244,12 +246,19 @@ import { SdDataSheetBase } from "./sd-data-sheet.base";
|
|
|
244
246
|
[key]="columnControl.key()"
|
|
245
247
|
[fixed]="columnControl.fixed()"
|
|
246
248
|
[header]="columnControl.header()"
|
|
249
|
+
[headerStyle]="columnControl.headerStyle()"
|
|
250
|
+
[tooltip]="columnControl.tooltip()"
|
|
247
251
|
[width]="columnControl.width()"
|
|
248
252
|
[disableSorting]="columnControl.disableSorting()"
|
|
249
253
|
[disableResizing]="columnControl.disableResizing()"
|
|
250
254
|
[hidden]="columnControl.hidden()"
|
|
251
255
|
[collapse]="columnControl.collapse()"
|
|
252
256
|
>
|
|
257
|
+
@if (columnControl.headerTplRef()) {
|
|
258
|
+
<ng-template #headerTpl>
|
|
259
|
+
<ng-template [ngTemplateOutlet]="columnControl.headerTplRef()!" />
|
|
260
|
+
</ng-template>
|
|
261
|
+
}
|
|
253
262
|
@if (columnControl.summaryTplRef()) {
|
|
254
263
|
<ng-template #summaryTpl>
|
|
255
264
|
<ng-template [ngTemplateOutlet]="columnControl.summaryTplRef()!" />
|
|
@@ -257,8 +266,8 @@ import { SdDataSheetBase } from "./sd-data-sheet.base";
|
|
|
257
266
|
}
|
|
258
267
|
|
|
259
268
|
<ng-template
|
|
260
|
-
|
|
261
|
-
let-item
|
|
269
|
+
[cell]="parent.items()"
|
|
270
|
+
let-item="item"
|
|
262
271
|
let-index="index"
|
|
263
272
|
let-depth="depth"
|
|
264
273
|
let-edit="edit"
|
|
@@ -311,7 +320,7 @@ import { SdDataSheetBase } from "./sd-data-sheet.base";
|
|
|
311
320
|
[key]="parent.itemPropInfo.lastModifiedAt!"
|
|
312
321
|
[hidden]="true"
|
|
313
322
|
>
|
|
314
|
-
<ng-template
|
|
323
|
+
<ng-template [cell]="parent.items()" let-item="item">
|
|
315
324
|
<div class="p-xs-sm tx-center">
|
|
316
325
|
{{
|
|
317
326
|
item[parent.itemPropInfo.lastModifiedAt!]
|
|
@@ -327,7 +336,7 @@ import { SdDataSheetBase } from "./sd-data-sheet.base";
|
|
|
327
336
|
[key]="parent.itemPropInfo.lastModifiedBy!"
|
|
328
337
|
[hidden]="true"
|
|
329
338
|
>
|
|
330
|
-
<ng-template
|
|
339
|
+
<ng-template [cell]="parent.items()" let-item="item">
|
|
331
340
|
<div class="p-xs-sm tx-center">
|
|
332
341
|
{{ item[parent.itemPropInfo.lastModifiedBy!] }}
|
|
333
342
|
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Directive, input } from "@angular/core";
|
|
2
|
+
import type { SdSheetCellContext } from "./sd-sheet-column";
|
|
3
|
+
|
|
4
|
+
@Directive({
|
|
5
|
+
selector: "ng-template[cell]",
|
|
6
|
+
standalone: true,
|
|
7
|
+
})
|
|
8
|
+
export class SdSheetColumnCellTemplate<T> {
|
|
9
|
+
cell = input.required<T[]>();
|
|
10
|
+
|
|
11
|
+
static ngTemplateContextGuard<TContextItem>(
|
|
12
|
+
_dir: SdSheetColumnCellTemplate<TContextItem>,
|
|
13
|
+
_ctx: unknown,
|
|
14
|
+
): _ctx is SdSheetCellContext<TContextItem> {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -5,10 +5,11 @@ import {
|
|
|
5
5
|
input,
|
|
6
6
|
TemplateRef,
|
|
7
7
|
} from "@angular/core";
|
|
8
|
+
import { SdSheetColumnCellTemplate } from "./sd-sheet-column-cell-template";
|
|
8
9
|
|
|
9
|
-
export interface SdSheetCellContext {
|
|
10
|
-
$implicit:
|
|
11
|
-
item:
|
|
10
|
+
export interface SdSheetCellContext<T = unknown> {
|
|
11
|
+
$implicit: T;
|
|
12
|
+
item: T;
|
|
12
13
|
index: number;
|
|
13
14
|
depth: number;
|
|
14
15
|
edit: boolean;
|
|
@@ -18,9 +19,11 @@ export interface SdSheetCellContext {
|
|
|
18
19
|
selector: "sd-sheet-column",
|
|
19
20
|
standalone: true,
|
|
20
21
|
})
|
|
21
|
-
export class SdSheetColumn {
|
|
22
|
+
export class SdSheetColumn<T = unknown> {
|
|
22
23
|
key = input.required<string>();
|
|
23
24
|
header = input<string | string[]>("");
|
|
25
|
+
headerStyle = input<string>();
|
|
26
|
+
tooltip = input<string>();
|
|
24
27
|
width = input<string>();
|
|
25
28
|
fixed = input(false, { transform: booleanAttribute });
|
|
26
29
|
hidden = input(false, { transform: booleanAttribute });
|
|
@@ -29,6 +32,10 @@ export class SdSheetColumn {
|
|
|
29
32
|
disableResizing = input(false, { transform: booleanAttribute });
|
|
30
33
|
ordering = input(0);
|
|
31
34
|
|
|
32
|
-
cellTplRef = contentChild<TemplateRef<SdSheetCellContext
|
|
35
|
+
cellTplRef = contentChild.required<any, TemplateRef<SdSheetCellContext<T>>>(
|
|
36
|
+
SdSheetColumnCellTemplate,
|
|
37
|
+
{ read: TemplateRef },
|
|
38
|
+
);
|
|
39
|
+
headerTplRef = contentChild<TemplateRef<void>>("headerTpl");
|
|
33
40
|
summaryTplRef = contentChild<TemplateRef<void>>("summaryTpl");
|
|
34
41
|
}
|
|
@@ -99,10 +99,16 @@ import { SdSheetConfigModal } from "./sd-sheet-config.modal";
|
|
|
99
99
|
[attr.colspan]="cell.colspan > 1 ? cell.colspan : null"
|
|
100
100
|
[attr.rowspan]="cell.rowspan > 1 ? cell.rowspan : null"
|
|
101
101
|
[attr.aria-sort]="getAriaSortValue(cell)"
|
|
102
|
+
[attr.title]="cell.colDef?.tooltip ?? cell.text"
|
|
103
|
+
[class.help]="cell.colDef?.tooltip"
|
|
102
104
|
[style]="getHeaderCellStyle(cell)"
|
|
103
105
|
(click)="onHeaderClick($event, cell)"
|
|
104
106
|
>
|
|
105
|
-
|
|
107
|
+
@if (cell.colDef && getColumnHeaderTpl(cell.colDef.key); as headerTpl) {
|
|
108
|
+
<ng-template [ngTemplateOutlet]="headerTpl" />
|
|
109
|
+
} @else {
|
|
110
|
+
<span>{{ cell.text }}</span>
|
|
111
|
+
}
|
|
106
112
|
@if (cell.colDef && getSortDef(cell.colDef.key); as sortDef) {
|
|
107
113
|
<ng-icon
|
|
108
114
|
class="_sort-icon"
|
|
@@ -368,7 +374,7 @@ export class SdSheet<T> {
|
|
|
368
374
|
columnControls = contentChildren(SdSheetColumn);
|
|
369
375
|
|
|
370
376
|
// Injected providers
|
|
371
|
-
private readonly
|
|
377
|
+
private readonly _sdModal = inject(SdModalProvider);
|
|
372
378
|
|
|
373
379
|
// DOM accessor & cell agent
|
|
374
380
|
domAccessor = injectSheetDomAccessor();
|
|
@@ -463,6 +469,11 @@ export class SdSheet<T> {
|
|
|
463
469
|
return map;
|
|
464
470
|
});
|
|
465
471
|
|
|
472
|
+
getColumnHeaderTpl(key: string) {
|
|
473
|
+
const col = this._columnControlMap().get(key);
|
|
474
|
+
return col?.headerTplRef() ?? null;
|
|
475
|
+
}
|
|
476
|
+
|
|
466
477
|
getColumnCellTpl(key: string) {
|
|
467
478
|
const col = this._columnControlMap().get(key);
|
|
468
479
|
return col?.cellTplRef() ?? null;
|
|
@@ -564,7 +575,7 @@ export class SdSheet<T> {
|
|
|
564
575
|
}
|
|
565
576
|
|
|
566
577
|
async onConfigButtonClick(): Promise<void> {
|
|
567
|
-
const result = await this.
|
|
578
|
+
const result = await this._sdModal.showAsync(
|
|
568
579
|
{
|
|
569
580
|
title: "시트 설정",
|
|
570
581
|
type: SdSheetConfigModal,
|
package/src/data/sheet/types.ts
CHANGED
|
@@ -60,7 +60,11 @@ export function useSheetCellStyling<T>(options: {
|
|
|
60
60
|
|
|
61
61
|
function getHeaderCellStyle(cell: SdSheetHeaderDef): string | null {
|
|
62
62
|
if (cell.colDef == null) return null;
|
|
63
|
-
|
|
63
|
+
const parts: string[] = [];
|
|
64
|
+
const baseStyle = headerColumnStyles().get(cell.colDef.key);
|
|
65
|
+
if (baseStyle != null) parts.push(baseStyle);
|
|
66
|
+
if (cell.colDef.headerStyle != null) parts.push(cell.colDef.headerStyle);
|
|
67
|
+
return parts.length > 0 ? parts.join("; ") : null;
|
|
64
68
|
}
|
|
65
69
|
|
|
66
70
|
function getCellStyle(item: T, colDef: SdSheetColumnDef): string | null {
|
|
@@ -17,6 +17,8 @@ export function useSheetLayoutEngine(options: {
|
|
|
17
17
|
return {
|
|
18
18
|
key,
|
|
19
19
|
header: col.header(),
|
|
20
|
+
headerStyle: col.headerStyle(),
|
|
21
|
+
tooltip: col.tooltip(),
|
|
20
22
|
width: cfgCol?.width ?? col.width(),
|
|
21
23
|
fixed: cfgCol?.fixed ?? col.fixed(),
|
|
22
24
|
hidden: cfgCol?.hidden ?? col.hidden(),
|
package/src/index.ts
CHANGED
|
@@ -224,7 +224,8 @@ export {
|
|
|
224
224
|
|
|
225
225
|
// data/sheet
|
|
226
226
|
export { SdSheet } from "./data/sheet/sd-sheet";
|
|
227
|
-
export { SdSheetColumn } from "./data/sheet/sd-sheet-column";
|
|
227
|
+
export { SdSheetColumn, type SdSheetCellContext } from "./data/sheet/sd-sheet-column";
|
|
228
|
+
export { SdSheetColumnCellTemplate } from "./data/sheet/sd-sheet-column-cell-template";
|
|
228
229
|
export { SdSheetConfigModal } from "./data/sheet/sd-sheet-config.modal";
|
|
229
230
|
export type {
|
|
230
231
|
SdSheetColumnDef,
|
|
@@ -82,7 +82,7 @@ import { tablerAlertTriangle } from "@ng-icons/tabler-icons";
|
|
|
82
82
|
export class SdBaseContainer {
|
|
83
83
|
private readonly _sdActivatedModal = inject(SdActivatedModalProvider, { optional: true });
|
|
84
84
|
private readonly _sdAppStructure = inject(SdAppStructureProvider);
|
|
85
|
-
private readonly
|
|
85
|
+
private readonly _sdSystemLog = inject(SdSystemLogProvider);
|
|
86
86
|
|
|
87
87
|
private readonly _parent = injectParent();
|
|
88
88
|
|
|
@@ -107,7 +107,7 @@ export class SdBaseContainer {
|
|
|
107
107
|
this._sdAppStructure.getTitleByFullCode(this._currPageCode?.() ?? this._fullPageCode())
|
|
108
108
|
);
|
|
109
109
|
} catch (err) {
|
|
110
|
-
void this.
|
|
110
|
+
void this._sdSystemLog.writeAsync("warn", `modalOrPageTitle 계산 중 에러: ${String(err)}`);
|
|
111
111
|
return "";
|
|
112
112
|
}
|
|
113
113
|
});
|