@simplysm/angular 14.0.85 → 14.0.87
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/pagination/sd-pagination.d.ts.map +1 -1
- package/dist/controls/pagination/sd-pagination.js +2 -0
- package/dist/controls/select/sd-select-item.js +1 -1
- package/dist/controls/select/sd-select.js +1 -1
- package/dist/core/app-structure/sd-app-structure.provider.d.ts +2 -3
- package/dist/core/app-structure/sd-app-structure.provider.d.ts.map +1 -1
- package/dist/core/app-structure/sd-app-structure.provider.js +5 -9
- package/dist/core/app-structure/sd-app-structure.utils.d.ts +2 -0
- package/dist/core/app-structure/sd-app-structure.utils.d.ts.map +1 -1
- package/dist/core/app-structure/sd-app-structure.utils.js +9 -1
- package/dist/core/busy/sd-busy-container.d.ts +1 -1
- package/dist/core/busy/sd-busy-container.d.ts.map +1 -1
- package/dist/core/busy/sd-busy-container.js +11 -11
- package/dist/core/busy/sd-busy.provider.d.ts.map +1 -1
- package/dist/core/busy/sd-busy.provider.js +3 -0
- package/dist/core/config/sd-system-config.provider.d.ts +4 -4
- package/dist/core/config/sd-system-config.provider.d.ts.map +1 -1
- package/dist/core/config/sd-system-config.provider.js +3 -0
- 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/file-dialog/sd-file-dialog.provider.d.ts.map +1 -1
- package/dist/core/file-dialog/sd-file-dialog.provider.js +4 -0
- package/dist/core/modal/sd-activated-modal.provider.d.ts +2 -1
- package/dist/core/modal/sd-activated-modal.provider.d.ts.map +1 -1
- package/dist/core/modal/sd-modal.d.ts.map +1 -1
- package/dist/core/modal/sd-modal.js +3 -3
- package/dist/core/modal/sd-modal.provider.d.ts.map +1 -1
- package/dist/core/modal/sd-modal.provider.js +8 -0
- package/dist/core/modal/sd-prompt-modal.d.ts +2 -2
- package/dist/core/modal/sd-prompt-modal.d.ts.map +1 -1
- package/dist/core/modal/sd-prompt-modal.js +32 -37
- package/dist/core/print/sd-print.provider.d.ts.map +1 -1
- package/dist/core/print/sd-print.provider.js +19 -6
- package/dist/core/provideSdAngular.d.ts.map +1 -1
- package/dist/core/provideSdAngular.js +4 -1
- package/dist/core/routing/injectViewTitleSignal.d.ts.map +1 -1
- package/dist/core/routing/injectViewTitleSignal.js +1 -6
- package/dist/core/shared-data/sd-shared-data.provider.d.ts +2 -1
- package/dist/core/shared-data/sd-shared-data.provider.d.ts.map +1 -1
- package/dist/core/shared-data/sd-shared-data.provider.js +3 -3
- package/dist/core/toast/sd-toast.provider.d.ts +1 -0
- package/dist/core/toast/sd-toast.provider.d.ts.map +1 -1
- package/dist/core/toast/sd-toast.provider.js +18 -4
- package/dist/data/crud/sd-base-container.d.ts.map +1 -1
- package/dist/data/crud/sd-base-container.js +56 -54
- package/dist/data/kanban/sd-kanban-lane.d.ts.map +1 -1
- package/dist/data/shared-data/sd-shared-data-select-button.d.ts +1 -2
- package/dist/data/shared-data/sd-shared-data-select-button.d.ts.map +1 -1
- package/dist/data/shared-data/sd-shared-data-select-button.js +18 -21
- package/dist/data/shared-data/sd-shared-data-select.d.ts +3 -2
- package/dist/data/shared-data/sd-shared-data-select.d.ts.map +1 -1
- package/dist/data/shared-data/sd-shared-data-select.js +10 -10
- package/dist/data/sheet/sd-sheet-config.modal.d.ts +3 -3
- package/dist/data/sheet/sd-sheet-config.modal.d.ts.map +1 -1
- package/dist/data/sheet/sd-sheet-config.modal.js +37 -34
- package/dist/data/sheet/sd-sheet.d.ts.map +1 -1
- package/dist/data/sheet/sd-sheet.js +5 -1
- package/dist/data/sheet/useSheetCellStyling.d.ts.map +1 -1
- package/dist/data/sheet/useSheetCellStyling.js +4 -22
- package/dist/data/state-preset/sd-state-preset.d.ts +10 -10
- package/dist/data/state-preset/sd-state-preset.d.ts.map +1 -1
- package/dist/data/state-preset/sd-state-preset.js +4 -4
- package/dist/features/address/sd-address-search.modal.js +1 -1
- package/dist/features/editor/sd-tiptap-editor.d.ts.map +1 -1
- package/dist/features/editor/sd-tiptap-editor.js +3 -2
- package/dist/features/theme/sd-theme-selector.d.ts +6 -8
- package/dist/features/theme/sd-theme-selector.d.ts.map +1 -1
- package/dist/features/theme/sd-theme-selector.js +54 -51
- package/dist/features/visual/sd-barcode.d.ts.map +1 -1
- package/dist/features/visual/sd-barcode.js +5 -10
- package/dist/layout/sidebar/sd-sidebar-user.d.ts.map +1 -1
- package/dist/layout/sidebar/sd-sidebar-user.js +26 -36
- package/package.json +28 -28
- package/src/controls/button/sd-modal-select-button.ts +1 -1
- package/src/controls/form/sd-form.ts +1 -1
- package/src/controls/input/sd-textfield-type-handlers.ts +2 -2
- package/src/controls/pagination/sd-pagination.ts +1 -0
- package/src/controls/select/sd-select-item.ts +1 -1
- package/src/controls/select/sd-select.ts +1 -1
- package/src/core/app-structure/sd-app-structure.provider.ts +7 -13
- package/src/core/app-structure/sd-app-structure.utils.ts +14 -2
- package/src/core/busy/sd-busy-container.ts +6 -13
- package/src/core/busy/sd-busy.provider.ts +4 -0
- package/src/core/config/injectSdSystemConfigResource.ts +1 -1
- package/src/core/config/sd-system-config.provider.ts +5 -3
- package/src/core/error-handler/sd-global-error-handler.plugin.ts +1 -1
- package/src/core/file-dialog/sd-file-dialog.provider.ts +5 -1
- package/src/core/modal/sd-activated-modal.provider.ts +2 -1
- package/src/core/modal/sd-modal.provider.ts +8 -0
- package/src/core/modal/sd-modal.ts +6 -3
- package/src/core/modal/sd-prompt-modal.ts +13 -23
- package/src/core/print/sd-print.provider.ts +21 -6
- package/src/core/provideSdAngular.ts +5 -1
- package/src/core/routing/injectViewTitleSignal.ts +1 -5
- package/src/core/shared-data/sd-shared-data.provider.ts +4 -4
- package/src/core/toast/sd-toast.provider.ts +35 -12
- package/src/data/crud/sd-base-container.ts +120 -118
- package/src/data/kanban/sd-kanban-lane.ts +2 -2
- package/src/data/shared-data/sd-shared-data-select-button.ts +15 -20
- package/src/data/shared-data/sd-shared-data-select-list.ts +4 -4
- package/src/data/shared-data/sd-shared-data-select.ts +10 -12
- package/src/data/sheet/sd-sheet-column.ts +1 -1
- package/src/data/sheet/sd-sheet-config.modal.ts +39 -35
- package/src/data/sheet/sd-sheet.ts +6 -1
- package/src/data/sheet/useSheetCellStyling.ts +3 -20
- package/src/data/state-preset/sd-state-preset.ts +11 -11
- package/src/features/address/sd-address-search.modal.ts +1 -1
- package/src/features/editor/sd-tiptap-editor.ts +3 -2
- package/src/features/theme/sd-theme-selector.ts +77 -75
- package/src/features/visual/sd-barcode.ts +5 -9
- package/src/features/visual/sd-calendar.ts +1 -1
- package/src/layout/sidebar/sd-sidebar-user.ts +3 -5
|
@@ -7,45 +7,41 @@ import { SdListItem } from "../../controls/list/sd-list-item";
|
|
|
7
7
|
import * as i0 from "@angular/core";
|
|
8
8
|
const _c0 = ["*"];
|
|
9
9
|
const _forTrack0 = ($index, $item) => $item.title;
|
|
10
|
+
function SdSidebarUser_Conditional_2_For_6_Template(rf, ctx) { if (rf & 1) {
|
|
11
|
+
const _r3 = i0.ɵɵgetCurrentView();
|
|
12
|
+
i0.ɵɵelementStart(0, "sd-list-item", 5);
|
|
13
|
+
i0.ɵɵlistener("click", function SdSidebarUser_Conditional_2_For_6_Template_sd_list_item_click_0_listener() { const menu_r4 = i0.ɵɵrestoreView(_r3).$implicit; return i0.ɵɵresetView(menu_r4.onClick()); });
|
|
14
|
+
i0.ɵɵtext(1);
|
|
15
|
+
i0.ɵɵelementEnd();
|
|
16
|
+
} if (rf & 2) {
|
|
17
|
+
const menu_r4 = ctx.$implicit;
|
|
18
|
+
i0.ɵɵadvance();
|
|
19
|
+
i0.ɵɵtextInterpolate1(" ", menu_r4.title, " ");
|
|
20
|
+
} }
|
|
10
21
|
function SdSidebarUser_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
11
22
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
12
|
-
i0.ɵɵelementStart(0, "div",
|
|
23
|
+
i0.ɵɵelementStart(0, "div", 1);
|
|
13
24
|
i0.ɵɵlistener("click", function SdSidebarUser_Conditional_2_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onMenuOpenButtonClick()); })("keydown.enter", function SdSidebarUser_Conditional_2_Template_div_keydown_enter_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onMenuOpenButtonClick()); });
|
|
14
25
|
i0.ɵɵtext(1);
|
|
15
|
-
i0.ɵɵelement(2, "sd-collapse-icon",
|
|
26
|
+
i0.ɵɵelement(2, "sd-collapse-icon", 2);
|
|
16
27
|
i0.ɵɵelementEnd();
|
|
28
|
+
i0.ɵɵelementStart(3, "sd-collapse", 3)(4, "sd-list", 4);
|
|
29
|
+
i0.ɵɵrepeaterCreate(5, SdSidebarUser_Conditional_2_For_6_Template, 2, 1, "sd-list-item", null, _forTrack0);
|
|
30
|
+
i0.ɵɵelementEnd()();
|
|
17
31
|
} if (rf & 2) {
|
|
18
|
-
|
|
32
|
+
const _userMenu_r5 = ctx;
|
|
19
33
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
20
34
|
i0.ɵɵproperty("sdRipple", true);
|
|
21
35
|
i0.ɵɵadvance();
|
|
22
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
36
|
+
i0.ɵɵtextInterpolate1(" ", _userMenu_r5.title, " ");
|
|
23
37
|
i0.ɵɵadvance();
|
|
24
38
|
i0.ɵɵproperty("open", ctx_r1.menuOpen())("openRotate", 180);
|
|
25
|
-
} }
|
|
26
|
-
function SdSidebarUser_Conditional_3_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
27
|
-
const _r3 = i0.ɵɵgetCurrentView();
|
|
28
|
-
i0.ɵɵelementStart(0, "sd-list-item", 6);
|
|
29
|
-
i0.ɵɵlistener("click", function SdSidebarUser_Conditional_3_For_3_Template_sd_list_item_click_0_listener() { const menu_r4 = i0.ɵɵrestoreView(_r3).$implicit; return i0.ɵɵresetView(menu_r4.onClick()); });
|
|
30
|
-
i0.ɵɵtext(1);
|
|
31
|
-
i0.ɵɵelementEnd();
|
|
32
|
-
} if (rf & 2) {
|
|
33
|
-
const menu_r4 = ctx.$implicit;
|
|
34
39
|
i0.ɵɵadvance();
|
|
35
|
-
i0.ɵɵtextInterpolate1(" ", menu_r4.title, " ");
|
|
36
|
-
} }
|
|
37
|
-
function SdSidebarUser_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
38
|
-
i0.ɵɵelementStart(0, "sd-collapse", 2)(1, "sd-list", 5);
|
|
39
|
-
i0.ɵɵrepeaterCreate(2, SdSidebarUser_Conditional_3_For_3_Template, 2, 1, "sd-list-item", null, _forTrack0);
|
|
40
|
-
i0.ɵɵelementEnd()();
|
|
41
|
-
} if (rf & 2) {
|
|
42
|
-
let tmp_3_0;
|
|
43
|
-
const ctx_r1 = i0.ɵɵnextContext();
|
|
44
40
|
i0.ɵɵproperty("open", ctx_r1.menuOpen());
|
|
45
41
|
i0.ɵɵadvance();
|
|
46
42
|
i0.ɵɵproperty("inset", true);
|
|
47
43
|
i0.ɵɵadvance();
|
|
48
|
-
i0.ɵɵrepeater(
|
|
44
|
+
i0.ɵɵrepeater(_userMenu_r5.menus);
|
|
49
45
|
} }
|
|
50
46
|
export class SdSidebarUser {
|
|
51
47
|
userMenu = input(...(ngDevMode ? [undefined, { debugName: "userMenu" }] : /* istanbul ignore next */ []));
|
|
@@ -54,20 +50,16 @@ export class SdSidebarUser {
|
|
|
54
50
|
this.menuOpen.update((v) => !v);
|
|
55
51
|
}
|
|
56
52
|
static ɵfac = function SdSidebarUser_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SdSidebarUser)(); };
|
|
57
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SdSidebarUser, selectors: [["sd-sidebar-user"]], inputs: { userMenu: [1, "userMenu"] }, ngContentSelectors: _c0, decls:
|
|
53
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SdSidebarUser, selectors: [["sd-sidebar-user"]], inputs: { userMenu: [1, "userMenu"] }, ngContentSelectors: _c0, decls: 3, vars: 1, consts: [[1, "p-lg"], ["tabindex", "0", 1, "_menu-button", 3, "click", "keydown.enter", "sdRipple"], [2, "float", "right", 3, "open", "openRotate"], [3, "open"], [3, "inset"], [3, "click"]], template: function SdSidebarUser_Template(rf, ctx) { if (rf & 1) {
|
|
58
54
|
i0.ɵɵprojectionDef();
|
|
59
55
|
i0.ɵɵelementStart(0, "div", 0);
|
|
60
56
|
i0.ɵɵprojection(1);
|
|
61
57
|
i0.ɵɵelementEnd();
|
|
62
|
-
i0.ɵɵconditionalCreate(2, SdSidebarUser_Conditional_2_Template,
|
|
63
|
-
i0.ɵɵconditionalCreate(3, SdSidebarUser_Conditional_3_Template, 4, 2, "sd-collapse", 2);
|
|
58
|
+
i0.ɵɵconditionalCreate(2, SdSidebarUser_Conditional_2_Template, 7, 6);
|
|
64
59
|
} if (rf & 2) {
|
|
65
60
|
let tmp_0_0;
|
|
66
|
-
let tmp_1_0;
|
|
67
61
|
i0.ɵɵadvance(2);
|
|
68
|
-
i0.ɵɵconditional((
|
|
69
|
-
i0.ɵɵadvance();
|
|
70
|
-
i0.ɵɵconditional(((tmp_1_0 = ctx.userMenu()) == null ? null : tmp_1_0.title) ? 3 : -1);
|
|
62
|
+
i0.ɵɵconditional((tmp_0_0 = ctx.userMenu()) ? 2 : -1, tmp_0_0);
|
|
71
63
|
} }, dependencies: [SdCollapseIcon,
|
|
72
64
|
SdCollapse,
|
|
73
65
|
SdRipple,
|
|
@@ -86,17 +78,15 @@ export class SdSidebarUser {
|
|
|
86
78
|
<div class="p-lg">
|
|
87
79
|
<ng-content />
|
|
88
80
|
</div>
|
|
89
|
-
@if (userMenu()
|
|
81
|
+
@if (userMenu(); as _userMenu) {
|
|
90
82
|
<div class="_menu-button" tabindex="0" (click)="onMenuOpenButtonClick()" (keydown.enter)="onMenuOpenButtonClick()" [sdRipple]="true">
|
|
91
|
-
{{
|
|
83
|
+
{{ _userMenu.title }}
|
|
92
84
|
<sd-collapse-icon [open]="menuOpen()" style="float: right;" [openRotate]="180" />
|
|
93
85
|
</div>
|
|
94
|
-
}
|
|
95
86
|
|
|
96
|
-
@if (userMenu()?.title) {
|
|
97
87
|
<sd-collapse [open]="menuOpen()">
|
|
98
88
|
<sd-list [inset]="true">
|
|
99
|
-
@for (menu of
|
|
89
|
+
@for (menu of _userMenu.menus; track menu.title) {
|
|
100
90
|
<sd-list-item (click)="menu.onClick()">
|
|
101
91
|
{{ menu.title }}
|
|
102
92
|
</sd-list-item>
|
|
@@ -106,4 +96,4 @@ export class SdSidebarUser {
|
|
|
106
96
|
}
|
|
107
97
|
`, styles: ["sd-sidebar-user {\n display: block;\n}\nsd-sidebar-user > ._menu-button {\n display: block;\n cursor: pointer;\n user-select: none;\n padding: var(--gap-default);\n}\nsd-sidebar-user > ._menu-button:hover {\n background: var(--trans-lighter);\n}\nsd-sidebar-user > sd-collapse > ._content > sd-list {\n background: var(--trans-lightest);\n padding: var(--gap-xs) 0;\n}"] }]
|
|
108
98
|
}], null, { userMenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "userMenu", required: false }] }] }); })();
|
|
109
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SdSidebarUser, { className: "SdSidebarUser", filePath: "packages/angular/src/layout/sidebar/sd-sidebar-user.ts", lineNumber:
|
|
99
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SdSidebarUser, { className: "SdSidebarUser", filePath: "packages/angular/src/layout/sidebar/sd-sidebar-user.ts", lineNumber: 66 }); })();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplysm/angular",
|
|
3
|
-
"version": "14.0.
|
|
3
|
+
"version": "14.0.87",
|
|
4
4
|
"description": "심플리즘 패키지 - Angular",
|
|
5
5
|
"author": "심플리즘",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -24,40 +24,40 @@
|
|
|
24
24
|
"./dist/**/*.css"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@angular/animations": "^21.2.
|
|
28
|
-
"@angular/common": "^21.2.
|
|
29
|
-
"@angular/core": "^21.2.
|
|
30
|
-
"@angular/platform-browser": "^21.2.
|
|
31
|
-
"@angular/router": "^21.2.
|
|
32
|
-
"@angular/service-worker": "^21.2.
|
|
33
|
-
"@ng-icons/core": "^33.2.
|
|
34
|
-
"@ng-icons/tabler-icons": "^33.2.
|
|
35
|
-
"@tiptap/core": "^3.
|
|
36
|
-
"@tiptap/extension-color": "^3.
|
|
37
|
-
"@tiptap/extension-document": "^3.
|
|
38
|
-
"@tiptap/extension-highlight": "^3.
|
|
39
|
-
"@tiptap/extension-image": "^3.
|
|
40
|
-
"@tiptap/extension-paragraph": "^3.
|
|
41
|
-
"@tiptap/extension-placeholder": "^3.
|
|
42
|
-
"@tiptap/extension-text": "^3.
|
|
43
|
-
"@tiptap/extension-text-align": "^3.
|
|
44
|
-
"@tiptap/extension-text-style": "^3.
|
|
45
|
-
"@tiptap/extension-underline": "^3.
|
|
46
|
-
"@tiptap/starter-kit": "^3.
|
|
47
|
-
"bwip-js": "^4.
|
|
27
|
+
"@angular/animations": "^21.2.15",
|
|
28
|
+
"@angular/common": "^21.2.15",
|
|
29
|
+
"@angular/core": "^21.2.15",
|
|
30
|
+
"@angular/platform-browser": "^21.2.15",
|
|
31
|
+
"@angular/router": "^21.2.15",
|
|
32
|
+
"@angular/service-worker": "^21.2.15",
|
|
33
|
+
"@ng-icons/core": "^33.2.3",
|
|
34
|
+
"@ng-icons/tabler-icons": "^33.2.3",
|
|
35
|
+
"@tiptap/core": "^3.24.0",
|
|
36
|
+
"@tiptap/extension-color": "^3.24.0",
|
|
37
|
+
"@tiptap/extension-document": "^3.24.0",
|
|
38
|
+
"@tiptap/extension-highlight": "^3.24.0",
|
|
39
|
+
"@tiptap/extension-image": "^3.24.0",
|
|
40
|
+
"@tiptap/extension-paragraph": "^3.24.0",
|
|
41
|
+
"@tiptap/extension-placeholder": "^3.24.0",
|
|
42
|
+
"@tiptap/extension-text": "^3.24.0",
|
|
43
|
+
"@tiptap/extension-text-align": "^3.24.0",
|
|
44
|
+
"@tiptap/extension-text-style": "^3.24.0",
|
|
45
|
+
"@tiptap/extension-underline": "^3.24.0",
|
|
46
|
+
"@tiptap/starter-kit": "^3.24.0",
|
|
47
|
+
"bwip-js": "^4.11.1",
|
|
48
48
|
"echarts": "^6.1.0",
|
|
49
49
|
"html-to-image": "^1.11.13",
|
|
50
50
|
"jspdf": "^4.2.1",
|
|
51
51
|
"rxjs": "^7.8.2",
|
|
52
52
|
"tabbable": "^6.4.0",
|
|
53
|
-
"@simplysm/core-
|
|
54
|
-
"@simplysm/
|
|
55
|
-
"@simplysm/service-client": "14.0.
|
|
56
|
-
"@simplysm/
|
|
53
|
+
"@simplysm/core-browser": "14.0.87",
|
|
54
|
+
"@simplysm/core-common": "14.0.87",
|
|
55
|
+
"@simplysm/service-client": "14.0.87",
|
|
56
|
+
"@simplysm/service-common": "14.0.87"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"@angular/compiler": "^21.2.
|
|
60
|
-
"@angular/platform-browser-dynamic": "^21.2.
|
|
59
|
+
"@angular/compiler": "^21.2.15",
|
|
60
|
+
"@angular/platform-browser-dynamic": "^21.2.15"
|
|
61
61
|
},
|
|
62
62
|
"scripts": {}
|
|
63
63
|
}
|
|
@@ -184,7 +184,7 @@ export class SdModalSelectButton<
|
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
onEraseClick(): void {
|
|
187
|
-
this.value.set((this.selectMode() === "multi" ? [] : undefined) as
|
|
187
|
+
this.value.set((this.selectMode() === "multi" ? [] : undefined) as SelectModeValue<K>[M]);
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
async onSearchClick(event: MouseEvent): Promise<void> {
|
|
@@ -409,10 +409,10 @@ function createTimeHandler(withSeconds: boolean): TextfieldTypeHandler {
|
|
|
409
409
|
}
|
|
410
410
|
},
|
|
411
411
|
toControlValue(value) {
|
|
412
|
-
return (value as
|
|
412
|
+
return (value as Time).toFormatString(controlFormat);
|
|
413
413
|
},
|
|
414
414
|
toDisplayText(value) {
|
|
415
|
-
return (value as
|
|
415
|
+
return (value as Time).toFormatString(displayFormat);
|
|
416
416
|
},
|
|
417
417
|
validate(value, opts) {
|
|
418
418
|
const errors: string[] = [];
|
|
@@ -101,7 +101,7 @@ export class SdSelectItem<T> {
|
|
|
101
101
|
const itemValue = this.value();
|
|
102
102
|
if (this._parentControl.selectMode() === "multi") {
|
|
103
103
|
const arr = parentValue as T[] | undefined;
|
|
104
|
-
return arr != null && arr.
|
|
104
|
+
return arr != null && arr.some((x) => x === itemValue);
|
|
105
105
|
}
|
|
106
106
|
return parentValue === itemValue;
|
|
107
107
|
});
|
|
@@ -404,7 +404,7 @@ export class SdSelect<M extends "single" | "multi", T> {
|
|
|
404
404
|
} else {
|
|
405
405
|
this.value.update((v) => {
|
|
406
406
|
const arr: T[] = Array.isArray(v) ? v : [];
|
|
407
|
-
if (arr.
|
|
407
|
+
if (arr.some((x) => x === itemValue)) {
|
|
408
408
|
return arr.filter((item) => item !== itemValue);
|
|
409
409
|
} else {
|
|
410
410
|
return [...arr, itemValue];
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { computed, inject, Injectable, signal } from "@angular/core";
|
|
2
2
|
import type { Signal } from "@angular/core";
|
|
3
|
-
import type { AppStructureItem
|
|
3
|
+
import type { AppStructureItem } from "@simplysm/service-common";
|
|
4
4
|
import type { SdFlatMenu } from "./sd-app-structure.types";
|
|
5
5
|
import { SdAppStructureUtils } from "./sd-app-structure.utils";
|
|
6
|
-
import { SdServiceClientFactoryProvider } from "../service-client/sd-service-client-factory.provider";
|
|
7
|
-
import { SdAngularConfigProvider } from "../config/sd-angular-config.provider";
|
|
8
6
|
|
|
9
7
|
export function injectPermsSignal<K extends string>(viewCodes: string[], keys: K[]): Signal<K[]> {
|
|
10
8
|
const sdAppStructure = inject(SdAppStructureProvider);
|
|
@@ -15,20 +13,12 @@ export function injectPermsSignal<K extends string>(viewCodes: string[], keys: K
|
|
|
15
13
|
// 메뉴는 모듈/권한 모두 체크함
|
|
16
14
|
@Injectable({ providedIn: "root" })
|
|
17
15
|
export class SdAppStructureProvider<TModule = unknown> {
|
|
18
|
-
private readonly _sdServiceClientFactory = inject(SdServiceClientFactoryProvider);
|
|
19
|
-
private readonly _sdAngularConfig = inject(SdAngularConfigProvider);
|
|
20
|
-
|
|
21
16
|
readonly usableModules = signal<TModule[] | undefined>(undefined);
|
|
22
17
|
readonly permRecord = signal<Record<string, boolean> | undefined>(undefined);
|
|
23
18
|
readonly items = signal<AppStructureItem<TModule>[]>([]);
|
|
24
19
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const svc = client.getService<AppStructureService>("AppStructure");
|
|
28
|
-
const itemsMap = await svc.getItems();
|
|
29
|
-
this.items.set(
|
|
30
|
-
(itemsMap[this._sdAngularConfig.clientName] ?? []) as AppStructureItem<TModule>[],
|
|
31
|
-
);
|
|
20
|
+
initialize(items: AppStructureItem<TModule>[]): void {
|
|
21
|
+
this.items.set(items);
|
|
32
22
|
}
|
|
33
23
|
|
|
34
24
|
usableMenus = computed(() =>
|
|
@@ -46,6 +36,10 @@ export class SdAppStructureProvider<TModule = unknown> {
|
|
|
46
36
|
return SdAppStructureUtils.getTitleByFullCode(this.items(), fullCode);
|
|
47
37
|
}
|
|
48
38
|
|
|
39
|
+
findTitleByFullCode(fullCode: string) {
|
|
40
|
+
return SdAppStructureUtils.findTitleByFullCode(this.items(), fullCode);
|
|
41
|
+
}
|
|
42
|
+
|
|
49
43
|
getItemChainByFullCode(fullCode: string) {
|
|
50
44
|
return SdAppStructureUtils.getItemChainByFullCode(this.items(), fullCode);
|
|
51
45
|
}
|
|
@@ -9,10 +9,22 @@ import type { SdMenu, SdFlatMenu, SdPermission } from "./sd-app-structure.types"
|
|
|
9
9
|
export abstract class SdAppStructureUtils {
|
|
10
10
|
//---------- Info
|
|
11
11
|
|
|
12
|
-
static getTitleByFullCode<TModule>(items: AppStructureItem<TModule>[], fullCode: string) {
|
|
12
|
+
static getTitleByFullCode<TModule>(items: AppStructureItem<TModule>[], fullCode: string): string {
|
|
13
|
+
const title = this.findTitleByFullCode(items, fullCode);
|
|
14
|
+
if (title == null) {
|
|
15
|
+
throw new Error(`Item not found for fullCode: ${fullCode}`);
|
|
16
|
+
}
|
|
17
|
+
return title;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** 항목을 못 찾으면 throw 대신 undefined 반환 (결측 보존). */
|
|
21
|
+
static findTitleByFullCode<TModule>(
|
|
22
|
+
items: AppStructureItem<TModule>[],
|
|
23
|
+
fullCode: string,
|
|
24
|
+
): string | undefined {
|
|
13
25
|
const itemChain = this.getItemChainByFullCode(items, fullCode);
|
|
14
26
|
if (itemChain.length === 0) {
|
|
15
|
-
|
|
27
|
+
return undefined;
|
|
16
28
|
}
|
|
17
29
|
const parent = itemChain
|
|
18
30
|
.slice(0, -1)
|
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
ChangeDetectionStrategy,
|
|
4
4
|
Component,
|
|
5
5
|
computed,
|
|
6
|
-
ElementRef,
|
|
7
6
|
inject,
|
|
8
7
|
input,
|
|
9
8
|
ViewEncapsulation,
|
|
@@ -18,6 +17,7 @@ import { SdBusyProvider, type SdBusyType } from "./sd-busy.provider";
|
|
|
18
17
|
host: {
|
|
19
18
|
"[attr.data-sd-busy]": "busy() || undefined",
|
|
20
19
|
"[attr.data-sd-type]": "currType()",
|
|
20
|
+
"(keydown.capture)": "onKeydownCapture($event)",
|
|
21
21
|
},
|
|
22
22
|
template: `
|
|
23
23
|
<div class="_screen">
|
|
@@ -339,17 +339,10 @@ export class SdBusyContainer {
|
|
|
339
339
|
|
|
340
340
|
currType = computed(() => this.type() ?? this._sdBusy.type());
|
|
341
341
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
if (this.busy()) {
|
|
348
|
-
event.preventDefault();
|
|
349
|
-
event.stopPropagation();
|
|
350
|
-
}
|
|
351
|
-
},
|
|
352
|
-
true,
|
|
353
|
-
);
|
|
342
|
+
onKeydownCapture(event: Event): void {
|
|
343
|
+
if (this.busy()) {
|
|
344
|
+
event.preventDefault();
|
|
345
|
+
event.stopPropagation();
|
|
346
|
+
}
|
|
354
347
|
}
|
|
355
348
|
}
|
|
@@ -44,6 +44,10 @@ export class SdBusyProvider {
|
|
|
44
44
|
constructor() {
|
|
45
45
|
effect(() => {
|
|
46
46
|
const busy = this.globalBusyCount() > 0;
|
|
47
|
+
|
|
48
|
+
// busy 가 처음 true 가 되기 전엔 컨테이너를 생성하지 않음 (lazy)
|
|
49
|
+
if (!busy && this._containerRef == null) return;
|
|
50
|
+
|
|
47
51
|
const ref = this.containerRef;
|
|
48
52
|
const el = ref.location.nativeElement as HTMLElement;
|
|
49
53
|
|
|
@@ -20,7 +20,7 @@ export function injectSdSystemConfigResource<T>(options: { key: Signal<string |
|
|
|
20
20
|
const key = options.key();
|
|
21
21
|
if (key == null) return;
|
|
22
22
|
queueMicrotask(() => {
|
|
23
|
-
sdSystemConfig.setAsync(`${elTag}.${key}`, value
|
|
23
|
+
sdSystemConfig.setAsync(`${elTag}.${key}`, value).catch((err) => {
|
|
24
24
|
errorHandler.handleError(err);
|
|
25
25
|
});
|
|
26
26
|
});
|
|
@@ -6,13 +6,15 @@ export class SdSystemConfigProvider<T> {
|
|
|
6
6
|
private readonly _sdLocalStorage = inject<SdLocalStorageProvider<T>>(SdLocalStorageProvider);
|
|
7
7
|
|
|
8
8
|
fn?: {
|
|
9
|
-
set<K extends keyof T & string>(key: K, data: T[K]): Promise<void> | void;
|
|
10
|
-
get(key: keyof T & string): PromiseLike<
|
|
9
|
+
set<K extends keyof T & string>(key: K, data: T[K] | undefined): Promise<void> | void;
|
|
10
|
+
get(key: keyof T & string): PromiseLike<unknown>;
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
async setAsync<K extends keyof T & string>(key: K, data: T[K]) {
|
|
13
|
+
async setAsync<K extends keyof T & string>(key: K, data: T[K] | undefined) {
|
|
14
14
|
if (this.fn) {
|
|
15
15
|
await this.fn.set(key, data);
|
|
16
|
+
} else if (data == null) {
|
|
17
|
+
this._sdLocalStorage.remove(key);
|
|
16
18
|
} else {
|
|
17
19
|
this._sdLocalStorage.set(key, data);
|
|
18
20
|
}
|
|
@@ -17,7 +17,7 @@ export class SdGlobalErrorHandlerPlugin implements ErrorHandler {
|
|
|
17
17
|
private readonly _sdSystemLog = inject(SdSystemLogProvider);
|
|
18
18
|
private _hasDisplayedError = false;
|
|
19
19
|
|
|
20
|
-
handleError(event:
|
|
20
|
+
handleError(event: unknown) {
|
|
21
21
|
try {
|
|
22
22
|
if (event instanceof PromiseRejectionEvent) {
|
|
23
23
|
const reason = event.reason;
|
|
@@ -23,7 +23,11 @@ export class SdFileDialogProvider {
|
|
|
23
23
|
}
|
|
24
24
|
inputEl.onchange = (event: Event): void => {
|
|
25
25
|
cleanup();
|
|
26
|
-
const files = (event.target as HTMLInputElement).files
|
|
26
|
+
const files = (event.target as HTMLInputElement).files;
|
|
27
|
+
if (files == null) {
|
|
28
|
+
resolve(undefined);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
27
31
|
resolve(multiple ? Array.from(files) : files[0]);
|
|
28
32
|
};
|
|
29
33
|
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { Injectable, signal } from "@angular/core";
|
|
2
2
|
import type { SdModalContentDef } from "./sd-modal.provider";
|
|
3
|
+
import type { SdModal } from "./sd-modal";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* 모달 내부에서 inject하여 사용하는 프로바이더
|
|
6
7
|
*/
|
|
7
8
|
@Injectable()
|
|
8
9
|
export class SdActivatedModalProvider<T extends SdModalContentDef<any> = SdModalContentDef<any>> {
|
|
9
|
-
modalComponent = signal<
|
|
10
|
+
modalComponent = signal<SdModal | undefined>(undefined);
|
|
10
11
|
contentComponent = signal<T | undefined>(undefined);
|
|
11
12
|
canDeactivateFn: () => boolean = () => true;
|
|
12
13
|
}
|
|
@@ -195,7 +195,12 @@ export class SdModalProvider {
|
|
|
195
195
|
|
|
196
196
|
const modalEl = modalRef.location.nativeElement as HTMLElement;
|
|
197
197
|
|
|
198
|
+
let destroyed = false;
|
|
198
199
|
const doDestroy = () => {
|
|
200
|
+
// transitionend 와 setTimeout 폴백 중 먼저 도달한 쪽에서 1회만 실행
|
|
201
|
+
if (destroyed) return;
|
|
202
|
+
destroyed = true;
|
|
203
|
+
|
|
199
204
|
// DOM에서 제거
|
|
200
205
|
if (modalEl.parentNode != null) {
|
|
201
206
|
modalEl.parentNode.removeChild(modalEl);
|
|
@@ -221,7 +226,10 @@ export class SdModalProvider {
|
|
|
221
226
|
// transition duration 확인 후 대기 또는 즉시 destroy
|
|
222
227
|
const duration = parseFloat(getComputedStyle(modalEl).transitionDuration || "0");
|
|
223
228
|
if (duration > 0) {
|
|
229
|
+
// transitionend 가 정상 경로. 단 백그라운드 탭·transition 인터럽트 시 미발화하므로
|
|
230
|
+
// duration(초→ms) + 여유 100ms 후 발화하는 setTimeout 폴백을 함께 걸어 destroy 누락을 방지.
|
|
224
231
|
modalEl.addEventListener("transitionend", doDestroy, { once: true });
|
|
232
|
+
setTimeout(doDestroy, duration * 1000 + 100);
|
|
225
233
|
} else {
|
|
226
234
|
doDestroy();
|
|
227
235
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
afterNextRender,
|
|
2
3
|
ChangeDetectionStrategy,
|
|
3
4
|
Component,
|
|
4
5
|
effect,
|
|
@@ -323,7 +324,9 @@ import "@simplysm/core-browser";
|
|
|
323
324
|
export class SdModal {
|
|
324
325
|
private readonly _elRef = inject(ElementRef<HTMLElement>);
|
|
325
326
|
private readonly _sdActivatedModal = inject(SdActivatedModalProvider, { optional: true });
|
|
326
|
-
private readonly _sdSystemConfig = inject
|
|
327
|
+
private readonly _sdSystemConfig = inject<
|
|
328
|
+
SdSystemConfigProvider<Record<string, Record<string, string>>>
|
|
329
|
+
>(SdSystemConfigProvider, { optional: true });
|
|
327
330
|
private readonly _errorHandler = inject(ErrorHandler);
|
|
328
331
|
private readonly _focusTrap = injectFocusTrap();
|
|
329
332
|
|
|
@@ -359,7 +362,7 @@ export class SdModal {
|
|
|
359
362
|
|
|
360
363
|
constructor() {
|
|
361
364
|
// data-sd-init: 첫 렌더 후 설정하여 CSS transition 트리거 허용
|
|
362
|
-
|
|
365
|
+
afterNextRender(() => {
|
|
363
366
|
this._elRef.nativeElement.setAttribute("data-sd-init", "");
|
|
364
367
|
});
|
|
365
368
|
|
|
@@ -508,7 +511,7 @@ export class SdModal {
|
|
|
508
511
|
if (dialogEl.style.left !== "") config["left"] = dialogEl.style.left;
|
|
509
512
|
if (dialogEl.style.top !== "") config["top"] = dialogEl.style.top;
|
|
510
513
|
|
|
511
|
-
await this._sdSystemConfig.setAsync(`sd-modal.${k}
|
|
514
|
+
await this._sdSystemConfig.setAsync(`sd-modal.${k}`, config);
|
|
512
515
|
}
|
|
513
516
|
|
|
514
517
|
private async _restoreConfig(k: string): Promise<void> {
|
|
@@ -9,35 +9,33 @@ import {
|
|
|
9
9
|
import type { SdModalContentDef } from "./sd-modal.provider";
|
|
10
10
|
import { SdButton } from "../../controls/button/sd-button";
|
|
11
11
|
import { SdTextfield } from "../../controls/input/sd-textfield";
|
|
12
|
+
import { SdForm } from "../../controls/form/sd-form";
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* 범용 프롬프트 모달.
|
|
15
16
|
* SdModalContentDef<string> 구현. message를 표시하고, 텍스트 입력 후 확인/취소.
|
|
16
17
|
* 확인 시 입력값 emit, 취소 시 undefined emit.
|
|
18
|
+
* 입력값은 필수(required)이며, 빈 값으로 확인 시 sd-form 네이티브 검증으로 차단된다.
|
|
17
19
|
*/
|
|
18
20
|
@Component({
|
|
19
21
|
selector: "sd-prompt-modal",
|
|
20
22
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
21
23
|
encapsulation: ViewEncapsulation.None,
|
|
22
24
|
standalone: true,
|
|
23
|
-
imports: [SdButton, SdTextfield],
|
|
25
|
+
imports: [SdForm, SdButton, SdTextfield],
|
|
24
26
|
host: {
|
|
25
27
|
style: "display: block",
|
|
26
28
|
class: "p-default",
|
|
27
29
|
},
|
|
28
30
|
template: `
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
[type]="'text'"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<div class="flex-row main-align-end gap-sm">
|
|
38
|
-
<sd-button [theme]="'primary'" (click)="onConfirm()">확인</sd-button>
|
|
39
|
-
<sd-button (click)="onCancel()">취소</sd-button>
|
|
40
|
-
</div>
|
|
31
|
+
<sd-form (formSubmit)="onConfirm()">
|
|
32
|
+
<p class="mb-default" [innerHTML]="message()"></p>
|
|
33
|
+
<sd-textfield [type]="'text'" [(value)]="_inputValue" [required]="true" class="mb-default" />
|
|
34
|
+
<div class="flex-row main-align-end gap-sm">
|
|
35
|
+
<sd-button [type]="'submit'" [theme]="'primary'">확인</sd-button>
|
|
36
|
+
<sd-button (click)="onCancel()">취소</sd-button>
|
|
37
|
+
</div>
|
|
38
|
+
</sd-form>
|
|
41
39
|
`,
|
|
42
40
|
})
|
|
43
41
|
export class SdPromptModal implements SdModalContentDef<string> {
|
|
@@ -46,18 +44,10 @@ export class SdPromptModal implements SdModalContentDef<string> {
|
|
|
46
44
|
|
|
47
45
|
message = input.required<string>();
|
|
48
46
|
|
|
49
|
-
_inputValue = signal(
|
|
50
|
-
|
|
51
|
-
onInputChange(event: Event): void {
|
|
52
|
-
const inputEl = event.target as HTMLInputElement;
|
|
53
|
-
this._inputValue.set(inputEl.value);
|
|
54
|
-
}
|
|
47
|
+
_inputValue = signal<string | undefined>(undefined);
|
|
55
48
|
|
|
56
49
|
onConfirm(): void {
|
|
57
|
-
|
|
58
|
-
if (val !== "") {
|
|
59
|
-
this.close.emit(val);
|
|
60
|
-
}
|
|
50
|
+
this.close.emit(this._inputValue());
|
|
61
51
|
}
|
|
62
52
|
|
|
63
53
|
onCancel(): void {
|
|
@@ -9,10 +9,12 @@ import {
|
|
|
9
9
|
} from "@angular/core";
|
|
10
10
|
import type { DirectiveInputSignals, WithOptional } from "../directive-input-signals";
|
|
11
11
|
import { SdBusyProvider } from "../busy/sd-busy.provider";
|
|
12
|
-
import { wait } from "@simplysm/core-common";
|
|
12
|
+
import { createLogger, wait } from "@simplysm/core-common";
|
|
13
13
|
import { jsPDF } from "jspdf";
|
|
14
14
|
import * as htmlToImage from "html-to-image";
|
|
15
15
|
|
|
16
|
+
const logger = createLogger("angular:print");
|
|
17
|
+
|
|
16
18
|
export interface SdPrint {
|
|
17
19
|
initialized: Signal<boolean>;
|
|
18
20
|
readonly _optionalPrintInputs?: string;
|
|
@@ -175,6 +177,7 @@ export class SdPrintProvider {
|
|
|
175
177
|
|
|
176
178
|
private async _waitForAllImagesLoadedAsync(container: HTMLElement): Promise<void> {
|
|
177
179
|
const imgs = Array.from(container.querySelectorAll("img"));
|
|
180
|
+
const failedSrcs: string[] = [];
|
|
178
181
|
|
|
179
182
|
await Promise.all(
|
|
180
183
|
imgs.map((img) => {
|
|
@@ -182,16 +185,28 @@ export class SdPrintProvider {
|
|
|
182
185
|
if (img.complete && img.naturalWidth !== 0) {
|
|
183
186
|
resolve();
|
|
184
187
|
} else {
|
|
185
|
-
const
|
|
186
|
-
img.removeEventListener("load",
|
|
187
|
-
img.removeEventListener("error",
|
|
188
|
+
const cleanup = () => {
|
|
189
|
+
img.removeEventListener("load", onLoad);
|
|
190
|
+
img.removeEventListener("error", onError);
|
|
191
|
+
};
|
|
192
|
+
const onLoad = () => {
|
|
193
|
+
cleanup();
|
|
194
|
+
resolve();
|
|
195
|
+
};
|
|
196
|
+
const onError = () => {
|
|
197
|
+
failedSrcs.push(img.src);
|
|
198
|
+
cleanup();
|
|
188
199
|
resolve();
|
|
189
200
|
};
|
|
190
|
-
img.addEventListener("load",
|
|
191
|
-
img.addEventListener("error",
|
|
201
|
+
img.addEventListener("load", onLoad);
|
|
202
|
+
img.addEventListener("error", onError);
|
|
192
203
|
}
|
|
193
204
|
});
|
|
194
205
|
}),
|
|
195
206
|
);
|
|
207
|
+
|
|
208
|
+
if (failedSrcs.length > 0) {
|
|
209
|
+
logger.error(`인쇄/PDF: 이미지 ${failedSrcs.length}건 로드 실패`, failedSrcs);
|
|
210
|
+
}
|
|
196
211
|
}
|
|
197
212
|
}
|