@simplysm/angular 14.0.46 → 14.0.48

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.
Files changed (128) hide show
  1. package/README.md +468 -0
  2. package/dist/controls/dropdown/sd-dropdown-popup.d.ts +1 -0
  3. package/dist/controls/dropdown/sd-dropdown-popup.d.ts.map +1 -1
  4. package/dist/controls/dropdown/sd-dropdown-popup.js +6 -1
  5. package/dist/controls/dropdown/sd-dropdown.d.ts.map +1 -1
  6. package/dist/controls/dropdown/sd-dropdown.js +6 -2
  7. package/dist/controls/select/sd-select.d.ts.map +1 -1
  8. package/dist/controls/select/sd-select.js +12 -34
  9. package/dist/core/routing/injectViewTypeSignal.d.ts +1 -1
  10. package/dist/core/routing/injectViewTypeSignal.d.ts.map +1 -1
  11. package/dist/core/routing/injectViewTypeSignal.js +15 -7
  12. package/dist/core/selection/useSelectionManager.d.ts +1 -0
  13. package/dist/core/selection/useSelectionManager.d.ts.map +1 -1
  14. package/dist/core/selection/useSelectionManager.js +54 -14
  15. package/dist/data/shared-data/sd-shared-data-select-button.d.ts +11 -5
  16. package/dist/data/shared-data/sd-shared-data-select-button.d.ts.map +1 -1
  17. package/dist/data/shared-data/sd-shared-data-select-button.js +68 -29
  18. package/dist/data/sheet/sd-sheet.d.ts +4 -1
  19. package/dist/data/sheet/sd-sheet.d.ts.map +1 -1
  20. package/dist/data/sheet/sd-sheet.js +23 -4
  21. package/dist/index.d.ts +0 -13
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +0 -17
  24. package/docs/bootstrap.md +38 -0
  25. package/docs/directives.md +236 -0
  26. package/docs/features.md +169 -0
  27. package/docs/pipes.md +32 -0
  28. package/docs/plugins.md +37 -0
  29. package/docs/provider-types.md +283 -0
  30. package/docs/providers.md +379 -0
  31. package/docs/recipes/crud-detail.md +860 -0
  32. package/docs/recipes/crud-list.md +779 -0
  33. package/docs/recipes/data-select-button.md +319 -0
  34. package/docs/recipes/page-modal-container.md +178 -0
  35. package/docs/styling.md +222 -0
  36. package/docs/type-utilities.md +250 -0
  37. package/docs/ui-data.md +333 -0
  38. package/docs/ui-form.md +502 -0
  39. package/docs/ui-layout.md +140 -0
  40. package/docs/ui-navigation.md +273 -0
  41. package/docs/ui-overlay.md +157 -0
  42. package/docs/ui-visual.md +127 -0
  43. package/docs/utils.md +244 -0
  44. package/package.json +27 -26
  45. package/src/controls/dropdown/sd-dropdown-popup.ts +6 -2
  46. package/src/controls/dropdown/sd-dropdown.ts +3 -4
  47. package/src/controls/select/sd-select.ts +6 -30
  48. package/src/core/routing/injectViewTypeSignal.ts +17 -10
  49. package/src/core/selection/useSelectionManager.ts +62 -12
  50. package/src/data/shared-data/sd-shared-data-select-button.ts +49 -14
  51. package/src/data/sheet/sd-sheet.ts +21 -0
  52. package/src/index.ts +0 -29
  53. package/dist/core/commons.d.ts +0 -2
  54. package/dist/core/commons.d.ts.map +0 -1
  55. package/dist/core/commons.js +0 -4
  56. package/dist/core/injectParent.d.ts +0 -7
  57. package/dist/core/injectParent.d.ts.map +0 -1
  58. package/dist/core/injectParent.js +0 -30
  59. package/dist/core/selection/setupCumulateSelectedKeys.d.ts +0 -9
  60. package/dist/core/selection/setupCumulateSelectedKeys.d.ts.map +0 -1
  61. package/dist/core/selection/setupCumulateSelectedKeys.js +0 -27
  62. package/dist/core/withBusy.d.ts +0 -3
  63. package/dist/core/withBusy.d.ts.map +0 -1
  64. package/dist/core/withBusy.js +0 -9
  65. package/dist/data/data-detail/sd-data-detail.base.d.ts +0 -51
  66. package/dist/data/data-detail/sd-data-detail.base.d.ts.map +0 -1
  67. package/dist/data/data-detail/sd-data-detail.base.js +0 -127
  68. package/dist/data/data-detail/sd-data-detail.d.ts +0 -30
  69. package/dist/data/data-detail/sd-data-detail.d.ts.map +0 -1
  70. package/dist/data/data-detail/sd-data-detail.js +0 -495
  71. package/dist/data/data-select-button/sd-data-select-button.base.d.ts +0 -24
  72. package/dist/data/data-select-button/sd-data-select-button.base.d.ts.map +0 -1
  73. package/dist/data/data-select-button/sd-data-select-button.base.js +0 -68
  74. package/dist/data/data-select-button/sd-data-select-button.d.ts +0 -15
  75. package/dist/data/data-select-button/sd-data-select-button.d.ts.map +0 -1
  76. package/dist/data/data-select-button/sd-data-select-button.js +0 -152
  77. package/dist/data/data-sheet/injectDataSheetExcelManager.d.ts +0 -14
  78. package/dist/data/data-sheet/injectDataSheetExcelManager.d.ts.map +0 -1
  79. package/dist/data/data-sheet/injectDataSheetExcelManager.js +0 -31
  80. package/dist/data/data-sheet/injectDataSheetInlineEditManager.d.ts +0 -26
  81. package/dist/data/data-sheet/injectDataSheetInlineEditManager.d.ts.map +0 -1
  82. package/dist/data/data-sheet/injectDataSheetInlineEditManager.js +0 -54
  83. package/dist/data/data-sheet/injectDataSheetModalEditManager.d.ts +0 -19
  84. package/dist/data/data-sheet/injectDataSheetModalEditManager.d.ts.map +0 -1
  85. package/dist/data/data-sheet/injectDataSheetModalEditManager.js +0 -44
  86. package/dist/data/data-sheet/injectDataSheetRefreshManager.d.ts +0 -25
  87. package/dist/data/data-sheet/injectDataSheetRefreshManager.d.ts.map +0 -1
  88. package/dist/data/data-sheet/injectDataSheetRefreshManager.js +0 -50
  89. package/dist/data/data-sheet/sd-data-sheet-column.d.ts +0 -8
  90. package/dist/data/data-sheet/sd-data-sheet-column.d.ts.map +0 -1
  91. package/dist/data/data-sheet/sd-data-sheet-column.js +0 -15
  92. package/dist/data/data-sheet/sd-data-sheet.base.d.ts +0 -75
  93. package/dist/data/data-sheet/sd-data-sheet.base.d.ts.map +0 -1
  94. package/dist/data/data-sheet/sd-data-sheet.base.js +0 -188
  95. package/dist/data/data-sheet/sd-data-sheet.d.ts +0 -49
  96. package/dist/data/data-sheet/sd-data-sheet.d.ts.map +0 -1
  97. package/dist/data/data-sheet/sd-data-sheet.js +0 -968
  98. package/dist/data/data-sheet/sd-data-sheet.types.d.ts +0 -17
  99. package/dist/data/data-sheet/sd-data-sheet.types.d.ts.map +0 -1
  100. package/dist/data/data-sheet/sd-data-sheet.types.js +0 -1
  101. package/dist/data/data-sheet/setupCloserWhenSingleSelectionChange.d.ts +0 -9
  102. package/dist/data/data-sheet/setupCloserWhenSingleSelectionChange.d.ts.map +0 -1
  103. package/dist/data/data-sheet/setupCloserWhenSingleSelectionChange.js +0 -20
  104. package/dist/data/data-sheet/useDataSheetFilterManager.d.ts +0 -13
  105. package/dist/data/data-sheet/useDataSheetFilterManager.d.ts.map +0 -1
  106. package/dist/data/data-sheet/useDataSheetFilterManager.js +0 -19
  107. package/dist/layout/base-container/sd-base-container.d.ts +0 -27
  108. package/dist/layout/base-container/sd-base-container.d.ts.map +0 -1
  109. package/dist/layout/base-container/sd-base-container.js +0 -193
  110. package/src/core/commons.ts +0 -4
  111. package/src/core/injectParent.ts +0 -45
  112. package/src/core/selection/setupCumulateSelectedKeys.ts +0 -38
  113. package/src/core/withBusy.ts +0 -13
  114. package/src/data/data-detail/sd-data-detail.base.ts +0 -187
  115. package/src/data/data-detail/sd-data-detail.ts +0 -237
  116. package/src/data/data-select-button/sd-data-select-button.base.ts +0 -104
  117. package/src/data/data-select-button/sd-data-select-button.ts +0 -105
  118. package/src/data/data-sheet/injectDataSheetExcelManager.ts +0 -57
  119. package/src/data/data-sheet/injectDataSheetInlineEditManager.ts +0 -89
  120. package/src/data/data-sheet/injectDataSheetModalEditManager.ts +0 -76
  121. package/src/data/data-sheet/injectDataSheetRefreshManager.ts +0 -90
  122. package/src/data/data-sheet/sd-data-sheet-column.ts +0 -10
  123. package/src/data/data-sheet/sd-data-sheet.base.ts +0 -294
  124. package/src/data/data-sheet/sd-data-sheet.ts +0 -479
  125. package/src/data/data-sheet/sd-data-sheet.types.ts +0 -18
  126. package/src/data/data-sheet/setupCloserWhenSingleSelectionChange.ts +0 -29
  127. package/src/data/data-sheet/useDataSheetFilterManager.ts +0 -30
  128. package/src/layout/base-container/sd-base-container.ts +0 -121
@@ -1,9 +1,13 @@
1
1
  import { NgTemplateOutlet } from "@angular/common";
2
2
  import {
3
+ booleanAttribute,
3
4
  ChangeDetectionStrategy,
4
5
  Component,
5
6
  contentChild,
7
+ effect,
6
8
  input,
9
+ model,
10
+ signal,
7
11
  TemplateRef,
8
12
  ViewEncapsulation,
9
13
  } from "@angular/core";
@@ -12,11 +16,10 @@ import {
12
16
  SdItemOfTemplate,
13
17
  type SdItemOfTemplateContext,
14
18
  } from "../../core/template/sd-item-of-template";
15
- import { SdDataSelectButton } from "../data-select-button/sd-data-select-button";
16
- import { SdDataSelectButtonBase } from "../data-select-button/sd-data-select-button.base";
17
- import type {
18
- SdSelectModal,
19
- SdSelectModalInfo,
19
+ import {
20
+ SdModalSelectButton,
21
+ type SdSelectModal,
22
+ type SdSelectModalInfo,
20
23
  } from "../../controls/button/sd-modal-select-button";
21
24
  import type { SelectModeValue } from "../../controls/select/sd-select";
22
25
 
@@ -25,10 +28,22 @@ import type { SelectModeValue } from "../../controls/select/sd-select";
25
28
  changeDetection: ChangeDetectionStrategy.OnPush,
26
29
  encapsulation: ViewEncapsulation.None,
27
30
  standalone: true,
28
- imports: [SdDataSelectButton, NgTemplateOutlet, SdItemOfTemplate],
31
+ imports: [SdModalSelectButton, NgTemplateOutlet],
29
32
  template: `
30
- <sd-data-select-button>
31
- <ng-template [itemOf]="items()" let-item let-index="index">
33
+ <sd-modal-select-button
34
+ [(value)]="value"
35
+ [(selectedItems)]="_selectedItems"
36
+ [modal]="modal()"
37
+ [disabled]="disabled()"
38
+ [required]="required()"
39
+ [inset]="inset()"
40
+ [size]="size()"
41
+ [selectMode]="selectMode()"
42
+ >
43
+ @for (item of _selectedItems(); track item; let index = $index) {
44
+ @if (index !== 0) {
45
+ <span>,&nbsp;</span>
46
+ }
32
47
  <ng-template
33
48
  [ngTemplateOutlet]="itemTplRef()"
34
49
  [ngTemplateOutletContext]="{
@@ -38,25 +53,45 @@ import type { SelectModeValue } from "../../controls/select/sd-select";
38
53
  depth: 0,
39
54
  }"
40
55
  />
41
- </ng-template>
42
- <ng-content />
43
- </sd-data-select-button>
56
+ }
57
+ </sd-modal-select-button>
44
58
  `,
45
59
  })
46
60
  export class SdSharedDataSelectButton<
47
61
  TItem extends SharedDataBase<string | number>,
48
62
  TMode extends keyof SelectModeValue<string | number>,
49
63
  TModal extends SdSelectModal<any>,
50
- > extends SdDataSelectButtonBase<TItem, string | number, TMode> {
64
+ > {
65
+ value = model<SelectModeValue<string | number>[TMode]>();
51
66
  items = input<TItem[]>([]);
52
67
  modal = input.required<SdSelectModalInfo<TModal>>();
68
+ selectMode = input<TMode>("single" as TMode);
69
+ disabled = input(false, { transform: booleanAttribute });
70
+ required = input(false, { transform: booleanAttribute });
71
+ inset = input(false, { transform: booleanAttribute });
72
+ size = input<"sm" | "lg">();
53
73
 
54
74
  itemTplRef = contentChild.required<any, TemplateRef<SdItemOfTemplateContext<TItem>>>(
55
75
  SdItemOfTemplate,
56
76
  { read: TemplateRef },
57
77
  );
58
78
 
59
- override load(keys: (string | number)[]): TItem[] {
60
- return this.items().filter((item) => keys.includes(item.__valueKey));
79
+ protected readonly _selectedItems = signal<TItem[]>([]);
80
+
81
+ constructor() {
82
+ effect(() => {
83
+ const v = this.value();
84
+ const items = this.items();
85
+ const mode = this.selectMode();
86
+
87
+ if (mode === "multi" && Array.isArray(v) && v.filterExists().length > 0) {
88
+ const keys = v.filterExists() as (string | number)[];
89
+ this._selectedItems.set(items.filter((it) => keys.includes(it.__valueKey)));
90
+ } else if (mode === "single" && !Array.isArray(v) && v != null) {
91
+ this._selectedItems.set(items.filter((it) => it.__valueKey === v));
92
+ } else {
93
+ this._selectedItems.set([]);
94
+ }
95
+ });
61
96
  }
62
97
  }
@@ -4,11 +4,13 @@ import {
4
4
  Component,
5
5
  computed,
6
6
  contentChildren,
7
+ effect,
7
8
  inject,
8
9
  input,
9
10
  model,
10
11
  output,
11
12
  signal,
13
+ untracked,
12
14
  ViewEncapsulation,
13
15
  } from "@angular/core";
14
16
  import { NgTemplateOutlet } from "@angular/common";
@@ -578,6 +580,7 @@ export class SdSheet<T> {
578
580
  getItemCellClassFn = input<(item: T, colKey: string) => string>();
579
581
  getItemCellStyleFn = input<(item: T, colKey: string) => string | undefined>();
580
582
  hideConfigBar = input(false, { transform: booleanAttribute });
583
+ cumulativeSelection = input(false, { transform: booleanAttribute });
581
584
 
582
585
  // Outputs
583
586
  itemKeydown = output<SdSheetItemKeydownEventParam<T>>();
@@ -696,6 +699,24 @@ export class SdSheet<T> {
696
699
  selectedItems: this.selectedItems,
697
700
  selectMode: this.selectMode,
698
701
  getItemSelectableFn: this.getItemSelectableFn,
702
+ trackByFn: this.trackByFn,
703
+ });
704
+
705
+ // cumulativeSelection=false면 items 변경 시 selectedItems를 초기화한다.
706
+ // 첫 실행(초기 마운트)은 skip하여 소비자가 넘긴 초기 selectedItems 값을 보존한다.
707
+ private _resetOnItemsChangeSkipFirst = true;
708
+ private readonly _resetOnItemsChange = effect(() => {
709
+ this.items(); // track only items
710
+ if (this._resetOnItemsChangeSkipFirst) {
711
+ this._resetOnItemsChangeSkipFirst = false;
712
+ return;
713
+ }
714
+ untracked(() => {
715
+ if (this.cumulativeSelection()) return;
716
+ if (this.selectedItems().length > 0) {
717
+ this.selectedItems.set([]);
718
+ }
719
+ });
699
720
  });
700
721
 
701
722
  // Icons
package/src/index.ts CHANGED
@@ -1,13 +1,10 @@
1
1
  import "@simplysm/core-browser";
2
2
 
3
3
  // core
4
- export { TXT_CHANGE_IGNORE_CONFIRM } from "./core/commons";
5
4
  export { provideSdAngular } from "./core/provideSdAngular";
6
5
  export { setupBgTheme } from "./core/setupBgTheme";
7
6
  export { setSafeStyle } from "./core/setSafeStyle";
8
7
  export { setupModelHook } from "./core/setupModelHook";
9
- export { injectParent } from "./core/injectParent";
10
- export { withBusy } from "./core/withBusy";
11
8
  export { mark } from "./core/mark";
12
9
  export { FormatPipe } from "./core/format.pipe";
13
10
  export type { SelectModalOutputResult } from "./core/select-modal-output-result";
@@ -96,7 +93,6 @@ export {
96
93
  } from "./core/shared-data/sd-shared-data.provider";
97
94
 
98
95
  // core/selection
99
- export { setupCumulateSelectedKeys } from "./core/selection/setupCumulateSelectedKeys";
100
96
  export {
101
97
  useExpandingManager,
102
98
  type ExpandItemDef,
@@ -199,9 +195,6 @@ export { SdPagination } from "./controls/pagination/sd-pagination";
199
195
  export { SdDockContainer } from "./layout/dock/sd-dock-container";
200
196
  export { SdDock } from "./layout/dock/sd-dock";
201
197
 
202
- // layout/base-container
203
- export { SdBaseContainer } from "./layout/base-container/sd-base-container";
204
-
205
198
  // layout/sidebar
206
199
  export { SdSidebarContainer } from "./layout/sidebar/sd-sidebar-container";
207
200
  export { SdSidebar } from "./layout/sidebar/sd-sidebar";
@@ -233,31 +226,9 @@ export type {
233
226
  SdSheetCellKeydownEventParam,
234
227
  } from "./data/sheet/types";
235
228
 
236
- // data/data-sheet
237
- export { SdDataSheet } from "./data/data-sheet/sd-data-sheet";
238
- export {
239
- SdDataSheetBase,
240
- type SdDataSheetItemPropInfo,
241
- type SdDataSheetItemInfo,
242
- type SdDataSheetSearchResult,
243
- } from "./data/data-sheet/sd-data-sheet.base";
244
- export { SdDataSheetColumn } from "./data/data-sheet/sd-data-sheet-column";
245
- export { setupCloserWhenSingleSelectionChange } from "./data/data-sheet/setupCloserWhenSingleSelectionChange";
246
-
247
- // data/data-detail
248
- export { SdDataDetail } from "./data/data-detail/sd-data-detail";
249
- export {
250
- SdDataDetailBase,
251
- type SdDataDetailDataInfo,
252
- } from "./data/data-detail/sd-data-detail.base";
253
-
254
229
  // data/utils
255
230
  export { getOrmDataEditToastErrorMessage } from "./data/getOrmDataEditToastErrorMessage";
256
231
 
257
- // data/data-select-button
258
- export { SdDataSelectButton } from "./data/data-select-button/sd-data-select-button";
259
- export { SdDataSelectButtonBase } from "./data/data-select-button/sd-data-select-button.base";
260
-
261
232
  // data/shared-data
262
233
  export { SdSharedDataSelect } from "./data/shared-data/sd-shared-data-select";
263
234
  export { SdSharedDataSelectButton } from "./data/shared-data/sd-shared-data-select-button";
@@ -1,2 +0,0 @@
1
- export declare const TXT_CHANGE_IGNORE_CONFIRM: string;
2
- //# sourceMappingURL=commons.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"commons.d.ts","sourceRoot":"","sources":["../../src/core/commons.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,yBAAyB,QAGC,CAAC"}
@@ -1,4 +0,0 @@
1
- export const TXT_CHANGE_IGNORE_CONFIRM = `
2
- 변경사항이 있습니다. 모든 변경사항을 무시하시겠습니까?
3
- - 확인: 변경사항을 무시하고, 현재 요청한 작업을 수행
4
- - 취소: 현재 요청한 작업을 취소하고, 변경사항 재검토`.trim();
@@ -1,7 +0,0 @@
1
- import { type AbstractType } from "@angular/core";
2
- export declare function injectParent<T = object>(): T;
3
- export declare function injectParent<T = object>(type: AbstractType<T>): T;
4
- export declare function injectParent<T = object>(type: AbstractType<T>, options: {
5
- optional: true;
6
- }): T | undefined;
7
- //# sourceMappingURL=injectParent.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"injectParent.d.ts","sourceRoot":"","sources":["../../src/core/injectParent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAsC,MAAM,eAAe,CAAC;AAEtF,wBAAgB,YAAY,CAAC,CAAC,GAAG,MAAM,KAAK,CAAC,CAAC;AAC9C,wBAAgB,YAAY,CAAC,CAAC,GAAG,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AACnE,wBAAgB,YAAY,CAAC,CAAC,GAAG,MAAM,EACrC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,EACrB,OAAO,EAAE;IAAE,QAAQ,EAAE,IAAI,CAAA;CAAE,GAC1B,CAAC,GAAG,SAAS,CAAC"}
@@ -1,30 +0,0 @@
1
- import { inject, Injector, ViewContainerRef } from "@angular/core";
2
- export function injectParent(type, options) {
3
- let currentInjector = inject(ViewContainerRef).injector;
4
- while (currentInjector != null) {
5
- // Angular internal: NodeInjector._lView[CONTEXT=8]에 컴포넌트 인스턴스 저장
6
- const lView = currentInjector._lView;
7
- if (lView == null) {
8
- break;
9
- }
10
- const comp = lView[8];
11
- // 컴포넌트 인스턴스 검증: null, primitive, plain object({})는 건너뜀
12
- // Angular 내부 슬롯 변경 시 잘못된 객체 반환을 방지하는 방어 코드
13
- if (comp != null && typeof comp === "object" && comp.constructor !== Object) {
14
- if (type == null) {
15
- return comp;
16
- }
17
- if (comp instanceof type) {
18
- return comp;
19
- }
20
- }
21
- currentInjector = currentInjector.get(Injector, undefined, {
22
- skipSelf: true,
23
- optional: true,
24
- });
25
- }
26
- if (options?.optional) {
27
- return undefined;
28
- }
29
- throw new Error("부모 컴포넌트를 찾을 수 없습니다.");
30
- }
@@ -1,9 +0,0 @@
1
- import { type Signal, type WritableSignal } from "@angular/core";
2
- export declare function setupCumulateSelectedKeys<TItem, TKey>(options: {
3
- items: Signal<TItem[]>;
4
- selectedItems: WritableSignal<TItem[]>;
5
- selectedItemKeys: WritableSignal<TKey[]>;
6
- selectMode: () => "single" | "multi" | undefined;
7
- keySelectorFn: (item: TItem) => TKey | undefined;
8
- }): void;
9
- //# sourceMappingURL=setupCumulateSelectedKeys.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"setupCumulateSelectedKeys.d.ts","sourceRoot":"","sources":["../../../src/core/selection/setupCumulateSelectedKeys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,cAAc,EAAqB,MAAM,eAAe,CAAC;AAEpF,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE;IAC9D,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IACvB,aAAa,EAAE,cAAc,CAAC,KAAK,EAAE,CAAC,CAAC;IACvC,gBAAgB,EAAE,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC;IACzC,UAAU,EAAE,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;IACjD,aAAa,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI,GAAG,SAAS,CAAC;CAClD,GAAG,IAAI,CA6BP"}
@@ -1,27 +0,0 @@
1
- import { effect, untracked } from "@angular/core";
2
- export function setupCumulateSelectedKeys(options) {
3
- // items 변경 시 selectedItems에서 현재 items에 존재하지 않는 항목 제거
4
- // selectedItems는 untracked로 읽어 effect 재실행 방지
5
- effect(() => {
6
- const items = options.items();
7
- const selectedItems = untracked(() => options.selectedItems());
8
- if (selectedItems.length === 0)
9
- return;
10
- const itemKeySet = new Set(items.map((item) => options.keySelectorFn(item)).filter((k) => k != null));
11
- const filtered = selectedItems.filter((item) => {
12
- const key = options.keySelectorFn(item);
13
- return key != null && itemKeySet.has(key);
14
- });
15
- if (filtered.length !== selectedItems.length) {
16
- options.selectedItems.set(filtered);
17
- }
18
- });
19
- // selectedItems 변경 시 selectedItemKeys 갱신
20
- effect(() => {
21
- const selectedItems = options.selectedItems();
22
- const keys = selectedItems
23
- .map((item) => options.keySelectorFn(item))
24
- .filter((k) => k != null);
25
- options.selectedItemKeys.set(keys);
26
- });
27
- }
@@ -1,3 +0,0 @@
1
- import type { WritableSignal } from "@angular/core";
2
- export declare function withBusy(busyCount: WritableSignal<number>, fn: () => Promise<void>): Promise<void>;
3
- //# sourceMappingURL=withBusy.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"withBusy.d.ts","sourceRoot":"","sources":["../../src/core/withBusy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,wBAAsB,QAAQ,CAC5B,SAAS,EAAE,cAAc,CAAC,MAAM,CAAC,EACjC,EAAE,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GACtB,OAAO,CAAC,IAAI,CAAC,CAOf"}
@@ -1,9 +0,0 @@
1
- export async function withBusy(busyCount, fn) {
2
- busyCount.update((v) => v + 1);
3
- try {
4
- await fn();
5
- }
6
- finally {
7
- busyCount.update((v) => v - 1);
8
- }
9
- }
@@ -1,51 +0,0 @@
1
- import { ErrorHandler, type Signal, TemplateRef } from "@angular/core";
2
- import { DateTime } from "@simplysm/core-common";
3
- import { SdSharedDataProvider } from "../../core/shared-data/sd-shared-data.provider";
4
- import { type SdModalContentDef } from "../../core/modal/sd-modal.provider";
5
- import { SdToastProvider } from "../../core/toast/sd-toast.provider";
6
- import * as i0 from "@angular/core";
7
- export interface SdDataDetailDataInfo {
8
- isNew: boolean;
9
- isDeleted: boolean;
10
- lastModifiedAt: DateTime | undefined;
11
- lastModifiedBy: string | undefined;
12
- }
13
- export declare abstract class SdDataDetailBase<T extends object, R = boolean> implements SdModalContentDef<R> {
14
- abstract canUse: Signal<boolean>;
15
- abstract canEdit: Signal<boolean>;
16
- canDelete?: Signal<boolean>;
17
- prepareRefreshEffect?(): void;
18
- abstract load(): Promise<{
19
- data: T;
20
- info: SdDataDetailDataInfo;
21
- }> | {
22
- data: T;
23
- info: SdDataDetailDataInfo;
24
- };
25
- toggleDelete?(del: boolean): Promise<R | undefined> | R | undefined;
26
- submit?(data: T): Promise<R | undefined> | R | undefined;
27
- protected readonly _sdToast: SdToastProvider;
28
- protected readonly _sdSharedData: SdSharedDataProvider<Record<string, import("../..").SharedDataBase<string | number>>>;
29
- protected readonly _errorHandler: ErrorHandler;
30
- viewType: Signal<import("../..").SdViewType>;
31
- busyCount: import("@angular/core").WritableSignal<number>;
32
- busyMessage: import("@angular/core").WritableSignal<string | undefined>;
33
- initialized: import("@angular/core").WritableSignal<boolean>;
34
- close: import("@angular/core").OutputEmitterRef<R>;
35
- actionTplRef?: TemplateRef<any>;
36
- data: import("@angular/core").WritableSignal<T>;
37
- dataInfo: import("@angular/core").WritableSignal<SdDataDetailDataInfo | undefined>;
38
- private _dataSnapshot?;
39
- constructor();
40
- checkIgnoreChanges(): boolean;
41
- doRefresh(): Promise<void>;
42
- refresh(): Promise<void>;
43
- doToggleDelete(del: boolean): Promise<void>;
44
- doSubmit(opt?: {
45
- permCheck?: boolean;
46
- hideNoChangeMessage?: boolean;
47
- }): Promise<void>;
48
- static ɵfac: i0.ɵɵFactoryDeclaration<SdDataDetailBase<any, any>, never>;
49
- static ɵdir: i0.ɵɵDirectiveDeclaration<SdDataDetailBase<any, any>, never, never, {}, { "close": "close"; }, never, never, true, never>;
50
- }
51
- //# sourceMappingURL=sd-data-detail.base.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sd-data-detail.base.d.ts","sourceRoot":"","sources":["../../../src/data/data-detail/sd-data-detail.base.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,YAAY,EAIZ,KAAK,MAAM,EACX,WAAW,EACZ,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAO,MAAM,uBAAuB,CAAC;AAEtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AAItF,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;;AAGrE,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,QAAQ,GAAG,SAAS,CAAC;IACrC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC;AAED,8BACsB,gBAAgB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,GAAG,OAAO,CAClE,YAAW,iBAAiB,CAAC,CAAC,CAAC;IAI/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAE5B,oBAAoB,CAAC,IAAI,IAAI;IAE7B,QAAQ,CAAC,IAAI,IACT,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,CAAC;QAAC,IAAI,EAAE,oBAAoB,CAAA;KAAE,CAAC,GAChD;QAAE,IAAI,EAAE,CAAC,CAAC;QAAC,IAAI,EAAE,oBAAoB,CAAA;KAAE;IAE3C,YAAY,CAAC,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,SAAS;IAEnE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,SAAS;IAIxD,SAAS,CAAC,QAAQ,CAAC,QAAQ,kBAA2B;IACtD,SAAS,CAAC,QAAQ,CAAC,aAAa,wFAAgC;IAChE,SAAS,CAAC,QAAQ,CAAC,aAAa,eAAwB;IAExD,QAAQ,qCAAoC;IAE5C,SAAS,iDAAa;IACtB,WAAW,6DAAyC;IACpD,WAAW,kDAAiB;IAC5B,KAAK,8CAAe;IACpB,YAAY,CAAC,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC;IAEhC,IAAI,4CAAsB;IAE1B,QAAQ,2EAAuD;IAE/D,OAAO,CAAC,aAAa,CAAC,CAAI;;IAoC1B,kBAAkB;IAQZ,SAAS;IAYT,OAAO;IASP,cAAc,CAAC,GAAG,EAAE,OAAO;IAqB3B,QAAQ,CAAC,GAAG,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,mBAAmB,CAAC,EAAE,OAAO,CAAA;KAAE;yCA3HvD,gBAAgB;2CAAhB,gBAAgB;CA8JrC"}
@@ -1,127 +0,0 @@
1
- import { Directive, effect, ErrorHandler, inject, output, signal, TemplateRef, } from "@angular/core";
2
- import { DateTime, obj } from "@simplysm/core-common";
3
- import { TXT_CHANGE_IGNORE_CONFIRM } from "../../core/commons";
4
- import { SdSharedDataProvider } from "../../core/shared-data/sd-shared-data.provider";
5
- import { setupCanDeactivate } from "../../core/routing/setupCanDeactivate";
6
- import { injectViewTypeSignal } from "../../core/routing/injectViewTypeSignal";
7
- import { withBusy } from "../../core/withBusy";
8
- import {} from "../../core/modal/sd-modal.provider";
9
- import { SdToastProvider } from "../../core/toast/sd-toast.provider";
10
- import { getOrmDataEditToastErrorMessage } from "../getOrmDataEditToastErrorMessage";
11
- import * as i0 from "@angular/core";
12
- export class SdDataDetailBase {
13
- canDelete;
14
- //-- implement
15
- _sdToast = inject(SdToastProvider);
16
- _sdSharedData = inject(SdSharedDataProvider);
17
- _errorHandler = inject(ErrorHandler);
18
- viewType = injectViewTypeSignal(() => this);
19
- busyCount = signal(0, ...(ngDevMode ? [{ debugName: "busyCount" }] : /* istanbul ignore next */ []));
20
- busyMessage = signal(undefined, ...(ngDevMode ? [{ debugName: "busyMessage" }] : /* istanbul ignore next */ []));
21
- initialized = signal(false, ...(ngDevMode ? [{ debugName: "initialized" }] : /* istanbul ignore next */ []));
22
- close = output();
23
- actionTplRef;
24
- data = signal({}, ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
25
- dataInfo = signal(undefined, ...(ngDevMode ? [{ debugName: "dataInfo" }] : /* istanbul ignore next */ []));
26
- _dataSnapshot;
27
- constructor() {
28
- effect((onCleanup) => {
29
- this.prepareRefreshEffect?.();
30
- let cancelled = false;
31
- onCleanup(() => {
32
- cancelled = true;
33
- });
34
- queueMicrotask(async () => {
35
- try {
36
- if (cancelled)
37
- return;
38
- if (!this.canUse()) {
39
- this.initialized.set(true);
40
- return;
41
- }
42
- await withBusy(this.busyCount, () => this._sdToast.try(async () => {
43
- await this._sdSharedData.wait();
44
- await this.refresh();
45
- }));
46
- this.initialized.set(true);
47
- }
48
- catch (err) {
49
- this._errorHandler.handleError(err);
50
- }
51
- });
52
- });
53
- setupCanDeactivate(() => this.viewType() === "modal" || this.checkIgnoreChanges());
54
- }
55
- checkIgnoreChanges() {
56
- return (this._dataSnapshot == null ||
57
- obj.equal(this.data(), this._dataSnapshot) ||
58
- confirm(TXT_CHANGE_IGNORE_CONFIRM));
59
- }
60
- async doRefresh() {
61
- if (this.busyCount() > 0)
62
- return;
63
- if (!this.canUse())
64
- return;
65
- if (!this.checkIgnoreChanges())
66
- return;
67
- await withBusy(this.busyCount, () => this._sdToast.try(async () => {
68
- await this.refresh();
69
- }));
70
- }
71
- async refresh() {
72
- const result = await this.load();
73
- this.data.set(result.data);
74
- this.dataInfo.set(result.info);
75
- if (!result.info.isNew) {
76
- this._dataSnapshot = obj.clone(result.data);
77
- }
78
- }
79
- async doToggleDelete(del) {
80
- if (this.busyCount() > 0)
81
- return;
82
- if (!this.canEdit())
83
- return;
84
- if (this.canDelete && !this.canDelete())
85
- return;
86
- if (!this.toggleDelete)
87
- return;
88
- await withBusy(this.busyCount, () => this._sdToast.try(async () => {
89
- const result = await this.toggleDelete(del);
90
- if (!result)
91
- return;
92
- this._sdToast.success(`${del ? "삭제" : "복구"}되었습니다.`);
93
- this.close.emit(result);
94
- }, (err) => getOrmDataEditToastErrorMessage(err)));
95
- }
96
- async doSubmit(opt) {
97
- if (this.busyCount() > 0)
98
- return;
99
- if (opt?.permCheck && !this.canEdit())
100
- return;
101
- if (!this.submit)
102
- return;
103
- const dataInfo = this.dataInfo();
104
- if (dataInfo == null)
105
- return;
106
- if (!dataInfo.isNew &&
107
- (this._dataSnapshot == null || obj.equal(this.data(), this._dataSnapshot))) {
108
- if (!opt?.hideNoChangeMessage) {
109
- this._sdToast.info("변경사항이 없습니다.");
110
- }
111
- return;
112
- }
113
- await withBusy(this.busyCount, () => this._sdToast.try(async () => {
114
- const result = await this.submit(this.data());
115
- if (!result)
116
- return;
117
- this._sdToast.success("저장되었습니다.");
118
- this.close.emit(result);
119
- await this.refresh();
120
- }, (err) => getOrmDataEditToastErrorMessage(err)));
121
- }
122
- static ɵfac = function SdDataDetailBase_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SdDataDetailBase)(); };
123
- static ɵdir = /*@__PURE__*/ i0.ɵɵdefineDirective({ type: SdDataDetailBase, outputs: { close: "close" } });
124
- }
125
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SdDataDetailBase, [{
126
- type: Directive
127
- }], () => [], { close: [{ type: i0.Output, args: ["close"] }] }); })();
@@ -1,30 +0,0 @@
1
- import { TemplateRef } from "@angular/core";
2
- import { SdForm } from "../../controls/form/sd-form";
3
- import { SdDataDetailBase } from "./sd-data-detail.base";
4
- import * as i0 from "@angular/core";
5
- import * as i1 from "../../core/commands/sd-command";
6
- export type { SdDataDetailDataInfo } from "./sd-data-detail.base";
7
- export declare class SdDataDetail {
8
- parent: SdDataDetailBase<any, boolean>;
9
- formCtrl: import("@angular/core").Signal<SdForm | undefined>;
10
- toolTplRef: import("@angular/core").Signal<TemplateRef<any> | undefined>;
11
- prevTplRef: import("@angular/core").Signal<TemplateRef<any> | undefined>;
12
- contentTplRef: import("@angular/core").Signal<TemplateRef<any>>;
13
- nextTplRef: import("@angular/core").Signal<TemplateRef<any> | undefined>;
14
- modalActionTplRef: import("@angular/core").Signal<TemplateRef<any> | undefined>;
15
- constructor();
16
- onRefreshButtonClick(): Promise<void>;
17
- onDeleteButtonClick(): Promise<void>;
18
- onRestoreButtonClick(): Promise<void>;
19
- onSubmitButtonClick(): void;
20
- onSubmit(): Promise<void>;
21
- protected readonly icons: {
22
- tablerDeviceFloppy: string;
23
- tablerRefresh: string;
24
- tablerRestore: string;
25
- tablerEraser: string;
26
- };
27
- static ɵfac: i0.ɵɵFactoryDeclaration<SdDataDetail, never>;
28
- static ɵcmp: i0.ɵɵComponentDeclaration<SdDataDetail, "sd-data-detail", never, {}, {}, ["toolTplRef", "prevTplRef", "contentTplRef", "nextTplRef"], never, true, [{ directive: typeof i1.SdCommandDirective; inputs: {}; outputs: { "sdRefreshCommand": "sdRefreshCommand"; "sdSaveCommand": "sdSaveCommand"; }; }]>;
29
- }
30
- //# sourceMappingURL=sd-data-detail.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sd-data-detail.d.ts","sourceRoot":"","sources":["../../../src/data/data-detail/sd-data-detail.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,WAAW,EAGZ,MAAM,eAAe,CAAC;AAKvB,OAAO,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AASrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;;;AAGzD,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAIlE,qBAgKa,YAAY;IACvB,MAAM,iCAAyC;IAE/C,QAAQ,qDAAiC;IAEzC,UAAU,+DAAkD;IAC5D,UAAU,+DAAkD;IAC5D,aAAa,mDAA8D;IAC3E,UAAU,+DAAkD;IAE5D,iBAAiB,+DAAsD;;IAQjE,oBAAoB;IAIpB,mBAAmB;IAInB,oBAAoB;IAI1B,mBAAmB;IAIb,QAAQ;IAId,SAAS,CAAC,QAAQ,CAAC,KAAK;;;;;MAKtB;yCA3CS,YAAY;2CAAZ,YAAY;CA4CxB"}