@simplysm/angular 14.0.5 → 14.0.7
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/core/directives/sd-router-link.directive.d.ts.map +1 -1
- package/dist/core/directives/sd-router-link.directive.js +5 -10
- package/dist/core/plugins/events/sd-resize-event.plugin.d.ts.map +1 -1
- package/dist/core/plugins/events/sd-resize-event.plugin.js +3 -0
- package/dist/core/plugins/sd-global-error-handler.plugin.d.ts +1 -0
- package/dist/core/plugins/sd-global-error-handler.plugin.d.ts.map +1 -1
- package/dist/core/plugins/sd-global-error-handler.plugin.js +4 -0
- package/dist/core/providers/sd-app-structure.provider.d.ts.map +1 -1
- package/dist/core/providers/sd-app-structure.provider.js +4 -1
- package/dist/core/providers/sd-navigate-window.provider.d.ts +2 -1
- package/dist/core/providers/sd-navigate-window.provider.d.ts.map +1 -1
- package/dist/core/providers/sd-navigate-window.provider.js +13 -10
- package/dist/core/utils/setups/setupCanDeactivate.d.ts.map +1 -1
- package/dist/core/utils/setups/setupCanDeactivate.js +9 -2
- package/dist/core/utils/setups/setupInvalid.d.ts.map +1 -1
- package/dist/core/utils/setups/setupInvalid.js +4 -0
- package/dist/core/utils/setups/setupModelHook.d.ts +1 -1
- package/dist/core/utils/setups/setupModelHook.d.ts.map +1 -1
- package/dist/core/utils/setups/setupModelHook.js +5 -1
- package/dist/core/utils/setups/setupRipple.d.ts.map +1 -1
- package/dist/core/utils/setups/setupRipple.js +3 -2
- package/dist/core/utils/useExpandingManager.d.ts.map +1 -1
- package/dist/core/utils/useExpandingManager.js +2 -1
- package/dist/core/utils/useSdSystemConfigResource.d.ts.map +1 -1
- package/dist/core/utils/useSdSystemConfigResource.js +6 -3
- package/dist/ui/form/editor/sd-tiptap-editor.control.d.ts +5 -5
- package/dist/ui/form/editor/sd-tiptap-editor.control.d.ts.map +1 -1
- package/dist/ui/form/editor/sd-tiptap-editor.control.js +79 -78
- package/dist/ui/form/input/sd-date-range.picker.d.ts.map +1 -1
- package/dist/ui/form/input/sd-date-range.picker.js +4 -3
- package/dist/ui/form/input/sd-textfield-type-handlers.d.ts.map +1 -1
- package/dist/ui/form/input/sd-textfield-type-handlers.js +21 -2
- package/dist/ui/form/input/sd-textfield.control.d.ts.map +1 -1
- package/dist/ui/form/input/sd-textfield.control.js +1 -0
- package/dist/ui/overlay/modal/sd-modal.control.js +1 -1
- package/dist/ui/overlay/modal/sd-modal.provider.d.ts +1 -1
- package/dist/ui/overlay/modal/sd-modal.provider.js +1 -1
- package/docs/providers.md +1 -1
- package/docs/setup-functions.md +1 -1
- package/package.json +7 -10
- package/src/core/directives/sd-router-link.directive.ts +5 -13
- package/src/core/plugins/events/sd-resize-event.plugin.ts +3 -0
- package/src/core/plugins/sd-global-error-handler.plugin.ts +4 -0
- package/src/core/providers/sd-app-structure.provider.ts +4 -1
- package/src/core/providers/sd-navigate-window.provider.ts +12 -13
- package/src/core/utils/setups/setupCanDeactivate.ts +10 -2
- package/src/core/utils/setups/setupInvalid.ts +5 -0
- package/src/core/utils/setups/setupModelHook.ts +5 -2
- package/src/core/utils/setups/setupRipple.ts +3 -2
- package/src/core/utils/useExpandingManager.ts +2 -1
- package/src/core/utils/useSdSystemConfigResource.ts +6 -3
- package/src/ui/form/editor/sd-tiptap-editor.control.ts +64 -61
- package/src/ui/form/input/sd-date-range.picker.ts +4 -3
- package/src/ui/form/input/sd-textfield-type-handlers.ts +25 -5
- package/src/ui/form/input/sd-textfield.control.ts +1 -0
- package/src/ui/overlay/modal/sd-modal.control.ts +1 -1
- package/src/ui/overlay/modal/sd-modal.provider.ts +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { booleanAttribute, ChangeDetectionStrategy, Component, computed, DestroyRef, effect, ElementRef, inject, input, model, untracked, ViewEncapsulation, } from "@angular/core";
|
|
1
|
+
import { booleanAttribute, ChangeDetectionStrategy, Component, computed, DestroyRef, effect, ElementRef, inject, input, model, signal, untracked, ViewEncapsulation, } from "@angular/core";
|
|
2
2
|
import { setupInvalid } from "../../../core/utils/setups/setupInvalid";
|
|
3
3
|
import { Editor } from "@tiptap/core";
|
|
4
4
|
import StarterKit from "@tiptap/starter-kit";
|
|
@@ -116,37 +116,37 @@ function SdTiptapEditorControl_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
|
116
116
|
} if (rf & 2) {
|
|
117
117
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
118
118
|
i0.ɵɵadvance(2);
|
|
119
|
-
i0.ɵɵclassProp("_active", ctx_r1.activeStates.h1);
|
|
119
|
+
i0.ɵɵclassProp("_active", ctx_r1.activeStates().h1);
|
|
120
120
|
i0.ɵɵadvance(2);
|
|
121
|
-
i0.ɵɵclassProp("_active", ctx_r1.activeStates.h2);
|
|
121
|
+
i0.ɵɵclassProp("_active", ctx_r1.activeStates().h2);
|
|
122
122
|
i0.ɵɵadvance(3);
|
|
123
|
-
i0.ɵɵclassProp("_active", ctx_r1.activeStates.bold);
|
|
123
|
+
i0.ɵɵclassProp("_active", ctx_r1.activeStates().bold);
|
|
124
124
|
i0.ɵɵadvance(2);
|
|
125
|
-
i0.ɵɵclassProp("_active", ctx_r1.activeStates.italic);
|
|
125
|
+
i0.ɵɵclassProp("_active", ctx_r1.activeStates().italic);
|
|
126
126
|
i0.ɵɵadvance(2);
|
|
127
|
-
i0.ɵɵclassProp("_active", ctx_r1.activeStates.underline);
|
|
127
|
+
i0.ɵɵclassProp("_active", ctx_r1.activeStates().underline);
|
|
128
128
|
i0.ɵɵadvance(2);
|
|
129
|
-
i0.ɵɵclassProp("_active", ctx_r1.activeStates.strike);
|
|
129
|
+
i0.ɵɵclassProp("_active", ctx_r1.activeStates().strike);
|
|
130
130
|
i0.ɵɵadvance(4);
|
|
131
|
-
i0.ɵɵstyleProp("background-color", ctx_r1.activeColor);
|
|
131
|
+
i0.ɵɵstyleProp("background-color", ctx_r1.activeColor());
|
|
132
132
|
i0.ɵɵadvance(3);
|
|
133
|
-
i0.ɵɵstyleProp("background-color", ctx_r1.activeBgColor);
|
|
133
|
+
i0.ɵɵstyleProp("background-color", ctx_r1.activeBgColor());
|
|
134
134
|
i0.ɵɵadvance(3);
|
|
135
|
-
i0.ɵɵclassProp("_active", ctx_r1.activeStates.bulletList);
|
|
135
|
+
i0.ɵɵclassProp("_active", ctx_r1.activeStates().bulletList);
|
|
136
136
|
i0.ɵɵadvance(2);
|
|
137
|
-
i0.ɵɵclassProp("_active", ctx_r1.activeStates.orderedList);
|
|
137
|
+
i0.ɵɵclassProp("_active", ctx_r1.activeStates().orderedList);
|
|
138
138
|
i0.ɵɵadvance(7);
|
|
139
|
-
i0.ɵɵclassProp("_active", ctx_r1.activeStates.blockquote);
|
|
139
|
+
i0.ɵɵclassProp("_active", ctx_r1.activeStates().blockquote);
|
|
140
140
|
i0.ɵɵadvance(2);
|
|
141
|
-
i0.ɵɵclassProp("_active", ctx_r1.activeStates.codeBlock);
|
|
141
|
+
i0.ɵɵclassProp("_active", ctx_r1.activeStates().codeBlock);
|
|
142
142
|
i0.ɵɵadvance(3);
|
|
143
|
-
i0.ɵɵclassProp("_active", ctx_r1.activeStates.alignLeft);
|
|
143
|
+
i0.ɵɵclassProp("_active", ctx_r1.activeStates().alignLeft);
|
|
144
144
|
i0.ɵɵadvance(2);
|
|
145
|
-
i0.ɵɵclassProp("_active", ctx_r1.activeStates.alignCenter);
|
|
145
|
+
i0.ɵɵclassProp("_active", ctx_r1.activeStates().alignCenter);
|
|
146
146
|
i0.ɵɵadvance(2);
|
|
147
|
-
i0.ɵɵclassProp("_active", ctx_r1.activeStates.alignRight);
|
|
147
|
+
i0.ɵɵclassProp("_active", ctx_r1.activeStates().alignRight);
|
|
148
148
|
i0.ɵɵadvance(2);
|
|
149
|
-
i0.ɵɵclassProp("_active", ctx_r1.activeStates.alignJustify);
|
|
149
|
+
i0.ɵɵclassProp("_active", ctx_r1.activeStates().alignJustify);
|
|
150
150
|
i0.ɵɵadvance(5);
|
|
151
151
|
i0.ɵɵconditional(ctx_r1.colorPickerMode !== undefined ? 48 : -1);
|
|
152
152
|
} }
|
|
@@ -175,12 +175,12 @@ export class SdTiptapEditorControl {
|
|
|
175
175
|
"#d9ead3", "#d0e0e3", "#c9daf8", "#cfe2f3", "#d9d2e9", "#ead1dc", "#dd7e6b", "#ea9999",
|
|
176
176
|
"#f9cb9c", "#ffe599", "#b6d7a8", "#a2c4c9", "#a4c2f4", "#9fc5e8", "#b4a7d6", "#d5a6bd",
|
|
177
177
|
];
|
|
178
|
-
activeStates = {};
|
|
179
|
-
activeColor = "";
|
|
180
|
-
activeBgColor = "";
|
|
178
|
+
activeStates = signal({}, ...(ngDevMode ? [{ debugName: "activeStates" }] : /* istanbul ignore next */ []));
|
|
179
|
+
activeColor = signal("", ...(ngDevMode ? [{ debugName: "activeColor" }] : /* istanbul ignore next */ []));
|
|
180
|
+
activeBgColor = signal("", ...(ngDevMode ? [{ debugName: "activeBgColor" }] : /* istanbul ignore next */ []));
|
|
181
181
|
colorPickerMode;
|
|
182
182
|
/** @internal -- TipTap Editor 인스턴스. 테스트 및 고급 사용자용 */
|
|
183
|
-
editor;
|
|
183
|
+
editor = signal(undefined, ...(ngDevMode ? [{ debugName: "editor" }] : /* istanbul ignore next */ []));
|
|
184
184
|
updatingFromEditor = false;
|
|
185
185
|
lastExtensions;
|
|
186
186
|
resolvedExtensions = computed(() => {
|
|
@@ -209,19 +209,21 @@ export class SdTiptapEditorControl {
|
|
|
209
209
|
return;
|
|
210
210
|
}
|
|
211
211
|
// Sync value to existing editor
|
|
212
|
-
|
|
212
|
+
const currentEditor = untracked(() => this.editor());
|
|
213
|
+
if (currentEditor == null)
|
|
213
214
|
return;
|
|
214
|
-
const currentHtml = this.
|
|
215
|
+
const currentHtml = this.getEditorHtmlFrom(currentEditor);
|
|
215
216
|
if (currentHtml === val)
|
|
216
217
|
return;
|
|
217
|
-
|
|
218
|
+
currentEditor.commands.setContent(val ?? "", { emitUpdate: false });
|
|
218
219
|
});
|
|
219
220
|
// disabled/readonly → editor.setEditable()
|
|
220
221
|
effect(() => {
|
|
221
|
-
|
|
222
|
+
const ed = this.editor();
|
|
223
|
+
if (ed == null)
|
|
222
224
|
return;
|
|
223
225
|
const editable = !this.disabled() && !this.readonly();
|
|
224
|
-
|
|
226
|
+
ed.setEditable(editable);
|
|
225
227
|
});
|
|
226
228
|
// setupInvalid for form validation
|
|
227
229
|
setupInvalid(() => {
|
|
@@ -247,7 +249,7 @@ export class SdTiptapEditorControl {
|
|
|
247
249
|
const container = this.elRef.nativeElement.querySelector("._editor-container");
|
|
248
250
|
if (container == null)
|
|
249
251
|
return;
|
|
250
|
-
this.editor
|
|
252
|
+
this.editor.set(new Editor({
|
|
251
253
|
element: container,
|
|
252
254
|
extensions,
|
|
253
255
|
content: initialContent ?? "",
|
|
@@ -261,19 +263,15 @@ export class SdTiptapEditorControl {
|
|
|
261
263
|
onTransaction: () => {
|
|
262
264
|
this.refreshActiveStates();
|
|
263
265
|
},
|
|
264
|
-
});
|
|
266
|
+
}));
|
|
265
267
|
}
|
|
266
268
|
destroyEditor() {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
269
|
+
const ed = untracked(() => this.editor());
|
|
270
|
+
if (ed != null) {
|
|
271
|
+
ed.destroy();
|
|
272
|
+
this.editor.set(undefined);
|
|
270
273
|
}
|
|
271
274
|
}
|
|
272
|
-
getEditorHtml() {
|
|
273
|
-
if (this.editor == null)
|
|
274
|
-
return undefined;
|
|
275
|
-
return this.getEditorHtmlFrom(this.editor);
|
|
276
|
-
}
|
|
277
275
|
getEditorHtmlFrom(editor) {
|
|
278
276
|
const html = editor.getHTML();
|
|
279
277
|
if (editor.isEmpty)
|
|
@@ -281,9 +279,10 @@ export class SdTiptapEditorControl {
|
|
|
281
279
|
return html;
|
|
282
280
|
}
|
|
283
281
|
execCmd(cmd) {
|
|
284
|
-
|
|
282
|
+
const ed = this.editor();
|
|
283
|
+
if (ed == null)
|
|
285
284
|
return;
|
|
286
|
-
const chain =
|
|
285
|
+
const chain = ed.chain().focus();
|
|
287
286
|
switch (cmd) {
|
|
288
287
|
case "bold":
|
|
289
288
|
chain.toggleBold().run();
|
|
@@ -342,9 +341,10 @@ export class SdTiptapEditorControl {
|
|
|
342
341
|
this.colorPickerMode = this.colorPickerMode === mode ? undefined : mode;
|
|
343
342
|
}
|
|
344
343
|
applyColor(color) {
|
|
345
|
-
|
|
344
|
+
const ed = this.editor();
|
|
345
|
+
if (ed == null)
|
|
346
346
|
return;
|
|
347
|
-
const chain =
|
|
347
|
+
const chain = ed.chain().focus();
|
|
348
348
|
if (this.colorPickerMode === "text") {
|
|
349
349
|
if (color !== undefined) {
|
|
350
350
|
chain.setColor(color).run();
|
|
@@ -364,28 +364,29 @@ export class SdTiptapEditorControl {
|
|
|
364
364
|
this.colorPickerMode = undefined;
|
|
365
365
|
}
|
|
366
366
|
refreshActiveStates() {
|
|
367
|
-
|
|
367
|
+
const ed = this.editor();
|
|
368
|
+
if (ed == null)
|
|
368
369
|
return;
|
|
369
|
-
this.activeStates
|
|
370
|
-
bold:
|
|
371
|
-
italic:
|
|
372
|
-
underline:
|
|
373
|
-
strike:
|
|
374
|
-
h1:
|
|
375
|
-
h2:
|
|
376
|
-
bulletList:
|
|
377
|
-
orderedList:
|
|
378
|
-
blockquote:
|
|
379
|
-
codeBlock:
|
|
380
|
-
alignLeft:
|
|
381
|
-
alignCenter:
|
|
382
|
-
alignRight:
|
|
383
|
-
alignJustify:
|
|
384
|
-
};
|
|
385
|
-
const textColor =
|
|
386
|
-
this.activeColor
|
|
387
|
-
const bgColor =
|
|
388
|
-
this.activeBgColor
|
|
370
|
+
this.activeStates.set({
|
|
371
|
+
bold: ed.isActive("bold"),
|
|
372
|
+
italic: ed.isActive("italic"),
|
|
373
|
+
underline: ed.isActive("underline"),
|
|
374
|
+
strike: ed.isActive("strike"),
|
|
375
|
+
h1: ed.isActive("heading", { level: 1 }),
|
|
376
|
+
h2: ed.isActive("heading", { level: 2 }),
|
|
377
|
+
bulletList: ed.isActive("bulletList"),
|
|
378
|
+
orderedList: ed.isActive("orderedList"),
|
|
379
|
+
blockquote: ed.isActive("blockquote"),
|
|
380
|
+
codeBlock: ed.isActive("codeBlock"),
|
|
381
|
+
alignLeft: ed.isActive({ textAlign: "left" }),
|
|
382
|
+
alignCenter: ed.isActive({ textAlign: "center" }),
|
|
383
|
+
alignRight: ed.isActive({ textAlign: "right" }),
|
|
384
|
+
alignJustify: ed.isActive({ textAlign: "justify" }),
|
|
385
|
+
});
|
|
386
|
+
const textColor = ed.getAttributes("textStyle")["color"];
|
|
387
|
+
this.activeColor.set(typeof textColor === "string" ? textColor : "");
|
|
388
|
+
const bgColor = ed.getAttributes("highlight")["color"];
|
|
389
|
+
this.activeBgColor.set(typeof bgColor === "string" ? bgColor : "");
|
|
389
390
|
}
|
|
390
391
|
static ɵfac = function SdTiptapEditorControl_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SdTiptapEditorControl)(); };
|
|
391
392
|
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SdTiptapEditorControl, selectors: [["sd-tiptap-editor"]], hostVars: 2, hostBindings: function SdTiptapEditorControl_HostBindings(rf, ctx) { if (rf & 2) {
|
|
@@ -403,55 +404,55 @@ export class SdTiptapEditorControl {
|
|
|
403
404
|
@if (!disabled()) {
|
|
404
405
|
<div class="_toolbar">
|
|
405
406
|
<div class="_btn-group">
|
|
406
|
-
<button type="button" data-cmd="h1" [class._active]="activeStates.h1"
|
|
407
|
+
<button type="button" data-cmd="h1" [class._active]="activeStates().h1"
|
|
407
408
|
(click)="execCmd('h1')">H1</button>
|
|
408
|
-
<button type="button" data-cmd="h2" [class._active]="activeStates.h2"
|
|
409
|
+
<button type="button" data-cmd="h2" [class._active]="activeStates().h2"
|
|
409
410
|
(click)="execCmd('h2')">H2</button>
|
|
410
411
|
</div>
|
|
411
412
|
<div class="_btn-group">
|
|
412
|
-
<button type="button" data-cmd="bold" [class._active]="activeStates.bold"
|
|
413
|
+
<button type="button" data-cmd="bold" [class._active]="activeStates().bold"
|
|
413
414
|
(click)="execCmd('bold')">B</button>
|
|
414
|
-
<button type="button" data-cmd="italic" [class._active]="activeStates.italic"
|
|
415
|
+
<button type="button" data-cmd="italic" [class._active]="activeStates().italic"
|
|
415
416
|
(click)="execCmd('italic')">I</button>
|
|
416
|
-
<button type="button" data-cmd="underline" [class._active]="activeStates.underline"
|
|
417
|
+
<button type="button" data-cmd="underline" [class._active]="activeStates().underline"
|
|
417
418
|
(click)="execCmd('underline')">U</button>
|
|
418
|
-
<button type="button" data-cmd="strike" [class._active]="activeStates.strike"
|
|
419
|
+
<button type="button" data-cmd="strike" [class._active]="activeStates().strike"
|
|
419
420
|
(click)="execCmd('strike')">S</button>
|
|
420
421
|
</div>
|
|
421
422
|
<div class="_btn-group">
|
|
422
423
|
<button type="button" data-cmd="textColor" class="_color-btn"
|
|
423
424
|
(click)="toggleColorPicker('text')">
|
|
424
|
-
<span class="_color-indicator" [style.background-color]="activeColor"></span>
|
|
425
|
+
<span class="_color-indicator" [style.background-color]="activeColor()"></span>
|
|
425
426
|
A
|
|
426
427
|
</button>
|
|
427
428
|
<button type="button" data-cmd="bgColor" class="_color-btn"
|
|
428
429
|
(click)="toggleColorPicker('bg')">
|
|
429
|
-
<span class="_color-indicator" [style.background-color]="activeBgColor"></span>
|
|
430
|
+
<span class="_color-indicator" [style.background-color]="activeBgColor()"></span>
|
|
430
431
|
BG
|
|
431
432
|
</button>
|
|
432
433
|
</div>
|
|
433
434
|
<div class="_btn-group">
|
|
434
|
-
<button type="button" data-cmd="bulletList" [class._active]="activeStates.bulletList"
|
|
435
|
+
<button type="button" data-cmd="bulletList" [class._active]="activeStates().bulletList"
|
|
435
436
|
(click)="execCmd('bulletList')">UL</button>
|
|
436
|
-
<button type="button" data-cmd="orderedList" [class._active]="activeStates.orderedList"
|
|
437
|
+
<button type="button" data-cmd="orderedList" [class._active]="activeStates().orderedList"
|
|
437
438
|
(click)="execCmd('orderedList')">OL</button>
|
|
438
439
|
<button type="button" data-cmd="indent" (click)="execCmd('indent')">→</button>
|
|
439
440
|
<button type="button" data-cmd="outdent" (click)="execCmd('outdent')">←</button>
|
|
440
441
|
</div>
|
|
441
442
|
<div class="_btn-group">
|
|
442
|
-
<button type="button" data-cmd="blockquote" [class._active]="activeStates.blockquote"
|
|
443
|
+
<button type="button" data-cmd="blockquote" [class._active]="activeStates().blockquote"
|
|
443
444
|
(click)="execCmd('blockquote')">❝</button>
|
|
444
|
-
<button type="button" data-cmd="codeBlock" [class._active]="activeStates.codeBlock"
|
|
445
|
+
<button type="button" data-cmd="codeBlock" [class._active]="activeStates().codeBlock"
|
|
445
446
|
(click)="execCmd('codeBlock')"></></button>
|
|
446
447
|
</div>
|
|
447
448
|
<div class="_btn-group">
|
|
448
|
-
<button type="button" data-cmd="alignLeft" [class._active]="activeStates.alignLeft"
|
|
449
|
+
<button type="button" data-cmd="alignLeft" [class._active]="activeStates().alignLeft"
|
|
449
450
|
(click)="execCmd('alignLeft')">≡L</button>
|
|
450
|
-
<button type="button" data-cmd="alignCenter" [class._active]="activeStates.alignCenter"
|
|
451
|
+
<button type="button" data-cmd="alignCenter" [class._active]="activeStates().alignCenter"
|
|
451
452
|
(click)="execCmd('alignCenter')">≡C</button>
|
|
452
|
-
<button type="button" data-cmd="alignRight" [class._active]="activeStates.alignRight"
|
|
453
|
+
<button type="button" data-cmd="alignRight" [class._active]="activeStates().alignRight"
|
|
453
454
|
(click)="execCmd('alignRight')">≡R</button>
|
|
454
|
-
<button type="button" data-cmd="alignJustify" [class._active]="activeStates.alignJustify"
|
|
455
|
+
<button type="button" data-cmd="alignJustify" [class._active]="activeStates().alignJustify"
|
|
455
456
|
(click)="execCmd('alignJustify')">≡J</button>
|
|
456
457
|
</div>
|
|
457
458
|
<div class="_btn-group">
|
|
@@ -477,4 +478,4 @@ export class SdTiptapEditorControl {
|
|
|
477
478
|
"[attr.data-sd-readonly]": "readonly()",
|
|
478
479
|
}, styles: ["sd-tiptap-editor {\n display: block;\n position: relative;\n border: 1px solid var(--trans-lighter);\n border-radius: var(--border-radius-default);\n background: var(--theme-secondary-lightest);\n}\nsd-tiptap-editor > ._toolbar {\n display: flex;\n flex-wrap: wrap;\n gap: var(--gap-xs);\n padding: var(--gap-xs);\n border-bottom: 1px solid var(--trans-lighter);\n}\nsd-tiptap-editor > ._toolbar > ._btn-group {\n display: flex;\n gap: 1px;\n}\nsd-tiptap-editor > ._toolbar > ._btn-group > button {\n padding: var(--gap-xs) var(--gap-sm);\n border: 1px solid var(--trans-lighter);\n border-radius: var(--border-radius-default);\n background: transparent;\n cursor: pointer;\n font-size: var(--font-size-default);\n line-height: 1;\n}\nsd-tiptap-editor > ._toolbar > ._btn-group > button._active {\n background: var(--theme-primary-default);\n color: var(--text-trans-rev-default);\n}\nsd-tiptap-editor > ._toolbar > ._btn-group > button:hover {\n background: var(--trans-lighter);\n}\nsd-tiptap-editor > ._toolbar > ._btn-group > button._active:hover {\n background: var(--theme-primary-default);\n}\nsd-tiptap-editor > ._color-picker {\n display: flex;\n flex-wrap: wrap;\n gap: 2px;\n padding: var(--gap-xs);\n border-bottom: 1px solid var(--trans-lighter);\n}\nsd-tiptap-editor > ._color-picker > ._color-swatch {\n width: 1.25rem;\n height: 1.25rem;\n border: 1px solid var(--trans-lighter);\n border-radius: 2px;\n cursor: pointer;\n padding: 0;\n}\nsd-tiptap-editor > ._color-picker > ._color-swatch._no-color {\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--control-color);\n font-size: 0.625rem;\n}\nsd-tiptap-editor > ._editor-container {\n padding: var(--gap-sm);\n min-height: 6.25rem;\n}\nsd-tiptap-editor > ._editor-container > .tiptap {\n outline: none;\n}\nsd-tiptap-editor > ._editor-container > .tiptap:focus {\n outline: none;\n}\nsd-tiptap-editor[data-sd-disabled=true] {\n background: var(--theme-gray-lightest);\n color: var(--text-trans-light);\n}\nsd-tiptap-editor[data-sd-disabled=true] > ._editor-container > .tiptap {\n cursor: not-allowed;\n}\nsd-tiptap-editor[data-sd-readonly=true] > ._editor-container > .tiptap {\n cursor: default;\n}\nsd-tiptap-editor ._color-btn {\n position: relative;\n}\nsd-tiptap-editor ._color-btn > ._color-indicator {\n display: block;\n height: 2px;\n width: 100%;\n position: absolute;\n bottom: 2px;\n left: 0;\n}"] }]
|
|
479
480
|
}], () => [], { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], validatorFn: [{ type: i0.Input, args: [{ isSignal: true, alias: "validatorFn", required: false }] }], extensions: [{ type: i0.Input, args: [{ isSignal: true, alias: "extensions", required: false }] }] }); })();
|
|
480
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SdTiptapEditorControl, { className: "SdTiptapEditorControl", filePath: "packages/angular/src/ui/form/editor/sd-tiptap-editor.control.ts", lineNumber:
|
|
481
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SdTiptapEditorControl, { className: "SdTiptapEditorControl", filePath: "packages/angular/src/ui/form/editor/sd-tiptap-editor.control.ts", lineNumber: 234 }); })();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sd-date-range.picker.d.ts","sourceRoot":"","sources":["..\\..\\..\\..\\src\\ui\\form\\input\\sd-date-range.picker.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;;AAEjD,qBA+Ca,iBAAiB;IAC5B,UAAU,wDAAiC;IAC3C,IAAI,4DAAqB;IACzB,EAAE,4DAAqB;IAEvB,QAAQ,qEAAiD;IAEzD,2BAA2B,IAAI,IAAI;
|
|
1
|
+
{"version":3,"file":"sd-date-range.picker.d.ts","sourceRoot":"","sources":["..\\..\\..\\..\\src\\ui\\form\\input\\sd-date-range.picker.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;;AAEjD,qBA+Ca,iBAAiB;IAC5B,UAAU,wDAAiC;IAC3C,IAAI,4DAAqB;IACzB,EAAE,4DAAqB;IAEvB,QAAQ,qEAAiD;IAEzD,2BAA2B,IAAI,IAAI;IAenC,qBAAqB,IAAI,IAAI;yCAtBlB,iBAAiB;2CAAjB,iBAAiB;CAqC7B"}
|
|
@@ -37,8 +37,9 @@ export class SdDateRangePicker {
|
|
|
37
37
|
if (this.periodType() === "월") {
|
|
38
38
|
const fromDate = this.from();
|
|
39
39
|
if (fromDate) {
|
|
40
|
-
|
|
41
|
-
this.
|
|
40
|
+
const firstOfMonth = fromDate.setDay(1);
|
|
41
|
+
this.from.set(firstOfMonth);
|
|
42
|
+
this.to.set(firstOfMonth.addMonths(1).addDays(-1));
|
|
42
43
|
}
|
|
43
44
|
else {
|
|
44
45
|
this.to.set(undefined);
|
|
@@ -51,7 +52,7 @@ export class SdDateRangePicker {
|
|
|
51
52
|
handleFromDateChanged() {
|
|
52
53
|
if (this.periodType() === "월") {
|
|
53
54
|
const fromDate = this.from();
|
|
54
|
-
this.to.set(fromDate?.
|
|
55
|
+
this.to.set(fromDate?.setDay(1).addMonths(1).addDays(-1));
|
|
55
56
|
}
|
|
56
57
|
else if (this.periodType() === "일") {
|
|
57
58
|
this.to.set(this.from());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sd-textfield-type-handlers.d.ts","sourceRoot":"","sources":["..\\..\\..\\..\\src\\ui\\form\\input\\sd-textfield-type-handlers.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,QAAQ,EAER,IAAI,EACL,MAAM,uBAAuB,CAAC;AAI/B,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,QAAQ,CAAC;IACjB,OAAO,EAAE,QAAQ,CAAC;IAClB,MAAM,EAAE,QAAQ,CAAC;IACjB,UAAU,EAAE,QAAQ,CAAC;IACrB,cAAc,EAAE,QAAQ,CAAC;IACzB,MAAM,EAAE,IAAI,CAAC;IACb,UAAU,EAAE,IAAI,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,CAAC,MAAM,iBAAiB,CAAC,EAcvD,CAAC;AAMF,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;IAClE,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC;IACvD,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,oBAAoB,GAAG,MAAM,CAAC;IACnE,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,qBAAqB,GAAG,MAAM,GAAG,SAAS,CAAC;IAC/E,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,sBAAsB,GAAG,MAAM,EAAE,CAAC;CAClE;
|
|
1
|
+
{"version":3,"file":"sd-textfield-type-handlers.d.ts","sourceRoot":"","sources":["..\\..\\..\\..\\src\\ui\\form\\input\\sd-textfield-type-handlers.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,QAAQ,EAER,IAAI,EACL,MAAM,uBAAuB,CAAC;AAI/B,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,QAAQ,CAAC;IACjB,OAAO,EAAE,QAAQ,CAAC;IAClB,MAAM,EAAE,QAAQ,CAAC;IACjB,UAAU,EAAE,QAAQ,CAAC;IACrB,cAAc,EAAE,QAAQ,CAAC;IACzB,MAAM,EAAE,IAAI,CAAC;IACb,UAAU,EAAE,IAAI,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,CAAC,MAAM,iBAAiB,CAAC,EAcvD,CAAC;AAMF,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;IAClE,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC;IACvD,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,oBAAoB,GAAG,MAAM,CAAC;IACnE,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,qBAAqB,GAAG,MAAM,GAAG,SAAS,CAAC;IAC/E,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,sBAAsB,GAAG,MAAM,EAAE,CAAC;CAClE;AAqXD,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,MAAM,iBAAiB,EAAE,qBAAqB,CAcxF,CAAC"}
|
|
@@ -39,7 +39,7 @@ function createStringHandler(type) {
|
|
|
39
39
|
}
|
|
40
40
|
return errors;
|
|
41
41
|
}
|
|
42
|
-
if (type
|
|
42
|
+
if (type !== "color") {
|
|
43
43
|
const str = value;
|
|
44
44
|
if (opts.minlength !== undefined && opts.minlength > str.length) {
|
|
45
45
|
errors.push(`문자의 길이가 ${opts.minlength}보다 길거나 같아야 합니다.`);
|
|
@@ -135,7 +135,8 @@ function createFormatHandler() {
|
|
|
135
135
|
return raw;
|
|
136
136
|
const nonFormatChars = format.match(/[^X]/g)?.filter((v, i, a) => a.indexOf(v) === i);
|
|
137
137
|
if (nonFormatChars != null && nonFormatChars.length > 0) {
|
|
138
|
-
|
|
138
|
+
const escaped = nonFormatChars.map((ch) => ch === "]" || ch === "\\" || ch === "^" || ch === "-" ? "\\" + ch : ch).join("");
|
|
139
|
+
return raw.replace(new RegExp(`[${escaped}]`, "g"), "");
|
|
139
140
|
}
|
|
140
141
|
return raw;
|
|
141
142
|
},
|
|
@@ -272,6 +273,15 @@ function createDateTimeHandler(withSeconds) {
|
|
|
272
273
|
}
|
|
273
274
|
if (!(value instanceof DateTime)) {
|
|
274
275
|
errors.push("날짜 및 시간을 입력하세요");
|
|
276
|
+
return errors;
|
|
277
|
+
}
|
|
278
|
+
const min = opts.min;
|
|
279
|
+
const max = opts.max;
|
|
280
|
+
if (min instanceof DateTime && min.tick > value.tick) {
|
|
281
|
+
errors.push(`${min}보다 크거나 같아야 합니다.`);
|
|
282
|
+
}
|
|
283
|
+
if (max instanceof DateTime && max.tick < value.tick) {
|
|
284
|
+
errors.push(`${max}보다 작거나 같아야 합니다.`);
|
|
275
285
|
}
|
|
276
286
|
return errors;
|
|
277
287
|
},
|
|
@@ -311,6 +321,15 @@ function createTimeHandler(withSeconds) {
|
|
|
311
321
|
}
|
|
312
322
|
if (!(value instanceof Time)) {
|
|
313
323
|
errors.push("시간을 입력하세요");
|
|
324
|
+
return errors;
|
|
325
|
+
}
|
|
326
|
+
const min = opts.min;
|
|
327
|
+
const max = opts.max;
|
|
328
|
+
if (min instanceof Time && min.tick > value.tick) {
|
|
329
|
+
errors.push(`${min}보다 크거나 같아야 합니다.`);
|
|
330
|
+
}
|
|
331
|
+
if (max instanceof Time && max.tick < value.tick) {
|
|
332
|
+
errors.push(`${max}보다 작거나 같아야 합니다.`);
|
|
314
333
|
}
|
|
315
334
|
return errors;
|
|
316
335
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sd-textfield.control.d.ts","sourceRoot":"","sources":["..\\..\\..\\..\\src\\ui\\form\\input\\sd-textfield.control.ts"],"names":[],"mappings":"AAUA,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,8BAA8B,CAAC;;AAEtC,qBA8Qa,kBAAkB,CAAC,CAAC,SAAS,MAAM,iBAAiB;IAC/D,KAAK,wEAAiC;IAEtC,IAAI,yCAAuB;IAC3B,WAAW,0DAAmB;IAC9B,KAAK,0DAAmB;IACxB,UAAU,0DAAmB;IAC7B,UAAU,0DAAmB;IAE7B,QAAQ,qEAAiD;IACzD,QAAQ,qEAAiD;IAEzD,QAAQ,qEAAiD;IACzD,GAAG,wEAAiC;IACpC,GAAG,wEAAiC;IACpC,SAAS,0DAAmB;IAC5B,SAAS,0DAAmB;IAC5B,OAAO,0DAAmB;IAC1B,WAAW,+CAAiB,iBAAiB,CAAC,CAAC,CAAC,GAAG,SAAS,KAAK,MAAM,GAAG,SAAS,eAAI;IACvF,MAAM,0DAAmB;IAEzB,IAAI,0DAAmB;IACvB,YAAY,0DAAmB;IAC/B,cAAc,qEAAgD;IAC9D,SAAS,0DAAmB;IAE5B,MAAM,qEAAiD;IACvD,KAAK,qEAAiD;IACtD,IAAI,+DAAwB;IAC5B,KAAK,8IAED;IAEJ,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsD;IAE9E,WAAW,yCAA8C;IAEzD,WAAW,kDAA8D;IAEzE,YAAY,yCAOT;IAEH,gBAAgB,qDAMb;;IA4BH,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAa3B,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;yCA/F9B,kBAAkB;2CAAlB,kBAAkB;
|
|
1
|
+
{"version":3,"file":"sd-textfield.control.d.ts","sourceRoot":"","sources":["..\\..\\..\\..\\src\\ui\\form\\input\\sd-textfield.control.ts"],"names":[],"mappings":"AAUA,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,8BAA8B,CAAC;;AAEtC,qBA8Qa,kBAAkB,CAAC,CAAC,SAAS,MAAM,iBAAiB;IAC/D,KAAK,wEAAiC;IAEtC,IAAI,yCAAuB;IAC3B,WAAW,0DAAmB;IAC9B,KAAK,0DAAmB;IACxB,UAAU,0DAAmB;IAC7B,UAAU,0DAAmB;IAE7B,QAAQ,qEAAiD;IACzD,QAAQ,qEAAiD;IAEzD,QAAQ,qEAAiD;IACzD,GAAG,wEAAiC;IACpC,GAAG,wEAAiC;IACpC,SAAS,0DAAmB;IAC5B,SAAS,0DAAmB;IAC5B,OAAO,0DAAmB;IAC1B,WAAW,+CAAiB,iBAAiB,CAAC,CAAC,CAAC,GAAG,SAAS,KAAK,MAAM,GAAG,SAAS,eAAI;IACvF,MAAM,0DAAmB;IAEzB,IAAI,0DAAmB;IACvB,YAAY,0DAAmB;IAC/B,cAAc,qEAAgD;IAC9D,SAAS,0DAAmB;IAE5B,MAAM,qEAAiD;IACvD,KAAK,qEAAiD;IACtD,IAAI,+DAAwB;IAC5B,KAAK,8IAED;IAEJ,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsD;IAE9E,WAAW,yCAA8C;IAEzD,WAAW,kDAA8D;IAEzE,YAAY,yCAOT;IAEH,gBAAgB,qDAMb;;IA4BH,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAa3B,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;yCA/F9B,kBAAkB;2CAAlB,kBAAkB;CA8G9B"}
|
|
@@ -128,6 +128,7 @@ export class SdTextfieldControl {
|
|
|
128
128
|
this.value.set(parsed);
|
|
129
129
|
}
|
|
130
130
|
onInputPaste(event) {
|
|
131
|
+
event.preventDefault();
|
|
131
132
|
const text = event.clipboardData?.getData("text/plain").trim();
|
|
132
133
|
if (text == null || text === "") {
|
|
133
134
|
this.value.set(undefined);
|
|
@@ -195,7 +195,7 @@ export class SdModalControl {
|
|
|
195
195
|
this._bringToFront();
|
|
196
196
|
}
|
|
197
197
|
_requestClose() {
|
|
198
|
-
if (this._activatedModal !== null && !this._activatedModal.
|
|
198
|
+
if (this._activatedModal !== null && !this._activatedModal.canDeactiveFn()) {
|
|
199
199
|
return;
|
|
200
200
|
}
|
|
201
201
|
void this._saveConfig();
|
|
@@ -45,7 +45,7 @@ export interface ISdModalOptions {
|
|
|
45
45
|
export declare class SdActivatedModalProvider<T extends ISdModal<any> = ISdModal<any>> {
|
|
46
46
|
modalComponent: import("@angular/core").WritableSignal<any>;
|
|
47
47
|
contentComponent: import("@angular/core").WritableSignal<T | undefined>;
|
|
48
|
-
|
|
48
|
+
canDeactiveFn: () => boolean;
|
|
49
49
|
static ɵfac: i0.ɵɵFactoryDeclaration<SdActivatedModalProvider<any>, never>;
|
|
50
50
|
static ɵprov: i0.ɵɵInjectableDeclaration<SdActivatedModalProvider<any>>;
|
|
51
51
|
}
|
|
@@ -10,7 +10,7 @@ import * as i0 from "@angular/core";
|
|
|
10
10
|
export class SdActivatedModalProvider {
|
|
11
11
|
modalComponent = signal(undefined, ...(ngDevMode ? [{ debugName: "modalComponent" }] : /* istanbul ignore next */ []));
|
|
12
12
|
contentComponent = signal(undefined, ...(ngDevMode ? [{ debugName: "contentComponent" }] : /* istanbul ignore next */ []));
|
|
13
|
-
|
|
13
|
+
canDeactiveFn = () => true;
|
|
14
14
|
static ɵfac = function SdActivatedModalProvider_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SdActivatedModalProvider)(); };
|
|
15
15
|
static ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: SdActivatedModalProvider, factory: SdActivatedModalProvider.ɵfac });
|
|
16
16
|
}
|
package/docs/providers.md
CHANGED
|
@@ -343,7 +343,7 @@ Injectable. Available inside modal content components via DI. Provides access to
|
|
|
343
343
|
class SdActivatedModalProvider<T extends ISdModal<any> = ISdModal<any>> {
|
|
344
344
|
modalComponent: WritableSignal<any>;
|
|
345
345
|
contentComponent: WritableSignal<T | undefined>;
|
|
346
|
-
|
|
346
|
+
canDeactiveFn: () => boolean;
|
|
347
347
|
}
|
|
348
348
|
```
|
|
349
349
|
|
package/docs/setup-functions.md
CHANGED
|
@@ -59,7 +59,7 @@ function setupModelHook<T, S extends WritableSignal<T>>(
|
|
|
59
59
|
|
|
60
60
|
## `setupCanDeactivate`
|
|
61
61
|
|
|
62
|
-
Registers a route or modal can-deactivate guard. When inside a modal, sets `SdActivatedModalProvider.
|
|
62
|
+
Registers a route or modal can-deactivate guard. When inside a modal, sets `SdActivatedModalProvider.canDeactiveFn`. When inside a route, pushes a `CanDeactivateFn` to the route config.
|
|
63
63
|
|
|
64
64
|
```typescript
|
|
65
65
|
function setupCanDeactivate(fn: () => boolean): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplysm/angular",
|
|
3
|
-
"version": "14.0.
|
|
3
|
+
"version": "14.0.7",
|
|
4
4
|
"description": "심플리즘 패키지 - Angular",
|
|
5
5
|
"author": "심플리즘",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -34,18 +34,15 @@
|
|
|
34
34
|
"@ng-icons/core": "^33.2.0",
|
|
35
35
|
"@ng-icons/tabler-icons": "^33.2.0",
|
|
36
36
|
"@tiptap/core": "^3.21.0",
|
|
37
|
-
"@tiptap/extension-bold": "^3.21.0",
|
|
38
37
|
"@tiptap/extension-color": "^3.21.0",
|
|
39
38
|
"@tiptap/extension-document": "^3.21.0",
|
|
39
|
+
"@tiptap/extension-paragraph": "^3.21.0",
|
|
40
|
+
"@tiptap/extension-text": "^3.21.0",
|
|
40
41
|
"@tiptap/extension-highlight": "^3.21.0",
|
|
41
42
|
"@tiptap/extension-image": "^3.21.0",
|
|
42
|
-
"@tiptap/extension-paragraph": "^3.21.0",
|
|
43
43
|
"@tiptap/extension-placeholder": "^3.21.0",
|
|
44
|
-
"@tiptap/extension-text": "^3.21.0",
|
|
45
44
|
"@tiptap/extension-text-align": "^3.21.0",
|
|
46
45
|
"@tiptap/extension-text-style": "^3.21.0",
|
|
47
|
-
"@tiptap/extension-underline": "^3.21.0",
|
|
48
|
-
"@tiptap/pm": "^3.21.0",
|
|
49
46
|
"@tiptap/starter-kit": "^3.21.0",
|
|
50
47
|
"bwip-js": "^4.8.0",
|
|
51
48
|
"echarts": "^6.0.0",
|
|
@@ -53,10 +50,10 @@
|
|
|
53
50
|
"jspdf": "^4.2.1",
|
|
54
51
|
"rxjs": "^7.8.2",
|
|
55
52
|
"tabbable": "^6.4.0",
|
|
56
|
-
"@simplysm/
|
|
57
|
-
"@simplysm/
|
|
58
|
-
"@simplysm/
|
|
59
|
-
"@simplysm/
|
|
53
|
+
"@simplysm/core-browser": "14.0.7",
|
|
54
|
+
"@simplysm/service-client": "14.0.7",
|
|
55
|
+
"@simplysm/core-common": "14.0.7",
|
|
56
|
+
"@simplysm/service-common": "14.0.7"
|
|
60
57
|
},
|
|
61
58
|
"devDependencies": {
|
|
62
59
|
"@angular/compiler": "^21.2.6",
|
|
@@ -33,6 +33,9 @@ export class SdRouterLinkDirective {
|
|
|
33
33
|
|
|
34
34
|
if (!option) return;
|
|
35
35
|
|
|
36
|
+
// Alt+click → 무시 (Chrome 표준: 다운로드, SPA에서는 해당 없음)
|
|
37
|
+
if (event.altKey) return;
|
|
38
|
+
|
|
36
39
|
event.preventDefault();
|
|
37
40
|
event.stopPropagation();
|
|
38
41
|
|
|
@@ -47,22 +50,11 @@ export class SdRouterLinkDirective {
|
|
|
47
50
|
option.params,
|
|
48
51
|
`width=${width},height=${height}`,
|
|
49
52
|
);
|
|
50
|
-
} else if (event.ctrlKey || event.
|
|
51
|
-
const qp = option.queryParams
|
|
52
|
-
? "?" + new URLSearchParams(option.queryParams).toString()
|
|
53
|
-
: "";
|
|
54
|
-
this._navWindow.open(option.link + qp, option.params, "_blank");
|
|
55
|
-
} else if (event.shiftKey) {
|
|
56
|
-
const width = option.window?.width ?? 800;
|
|
57
|
-
const height = option.window?.height ?? 800;
|
|
53
|
+
} else if (event.ctrlKey || event.shiftKey) {
|
|
58
54
|
const qp = option.queryParams
|
|
59
55
|
? "?" + new URLSearchParams(option.queryParams).toString()
|
|
60
56
|
: "";
|
|
61
|
-
this._navWindow.open(
|
|
62
|
-
option.link + qp,
|
|
63
|
-
option.params,
|
|
64
|
-
`width=${width},height=${height}`,
|
|
65
|
-
);
|
|
57
|
+
this._navWindow.open(option.link + qp, option.params);
|
|
66
58
|
} else if (option.outletName === undefined) {
|
|
67
59
|
await this._router.navigate(
|
|
68
60
|
[option.link, ...(option.params ? [option.params] : [])],
|
|
@@ -12,6 +12,7 @@ import { SdSystemLogProvider } from "../providers/sd-system-log.provider";
|
|
|
12
12
|
export class SdGlobalErrorHandlerPlugin implements ErrorHandler {
|
|
13
13
|
private readonly _envInjector = inject(EnvironmentInjector);
|
|
14
14
|
private readonly _systemLog = inject(SdSystemLogProvider);
|
|
15
|
+
private _hasDisplayedError = false;
|
|
15
16
|
|
|
16
17
|
handleError(event: any) {
|
|
17
18
|
try {
|
|
@@ -82,6 +83,9 @@ export class SdGlobalErrorHandlerPlugin implements ErrorHandler {
|
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
private _displayErrorMessage(title: string, param: Record<string, string>) {
|
|
86
|
+
if (this._hasDisplayedError) return;
|
|
87
|
+
this._hasDisplayedError = true;
|
|
88
|
+
|
|
85
89
|
const paramLines = Object.keys(param).map((key) => key + ": " + param[key]);
|
|
86
90
|
|
|
87
91
|
void this._systemLog.writeAsync("error", `[${title}]\n${paramLines.join("\n")}`);
|
|
@@ -48,6 +48,9 @@ export abstract class SdAppStructureUtils {
|
|
|
48
48
|
|
|
49
49
|
static getTitleByFullCode<TModule>(items: TSdAppStructureItem<TModule>[], fullCode: string) {
|
|
50
50
|
const itemChain = this.getItemChainByFullCode(items, fullCode);
|
|
51
|
+
if (itemChain.length === 0) {
|
|
52
|
+
throw new Error(`Item not found for fullCode: ${fullCode}`);
|
|
53
|
+
}
|
|
51
54
|
const parent = itemChain
|
|
52
55
|
.slice(0, -1)
|
|
53
56
|
.map((item) => item.title)
|
|
@@ -72,7 +75,7 @@ export abstract class SdAppStructureUtils {
|
|
|
72
75
|
else if (
|
|
73
76
|
fullCodes.every((fullCode) => {
|
|
74
77
|
const item = this.getItemChainByFullCode(items, fullCode).last();
|
|
75
|
-
return
|
|
78
|
+
return item != null && !("perms" in item);
|
|
76
79
|
})
|
|
77
80
|
) {
|
|
78
81
|
result.push(permKey);
|
|
@@ -2,7 +2,8 @@ import { Injectable } from "@angular/core";
|
|
|
2
2
|
|
|
3
3
|
@Injectable({ providedIn: "root" })
|
|
4
4
|
export class SdNavigateWindowProvider {
|
|
5
|
-
private
|
|
5
|
+
private readonly _openedWindows = new Set<Window>();
|
|
6
|
+
private _beforeUnloadRegistered = false;
|
|
6
7
|
|
|
7
8
|
get isWindow(): boolean {
|
|
8
9
|
const urlSearchParams = new URLSearchParams(
|
|
@@ -19,21 +20,19 @@ export class SdNavigateWindowProvider {
|
|
|
19
20
|
features,
|
|
20
21
|
);
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
this._beforeUnloadController.abort();
|
|
23
|
+
if (newWindow) {
|
|
24
|
+
this._openedWindows.add(newWindow);
|
|
25
25
|
}
|
|
26
|
-
this._beforeUnloadController = new AbortController();
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
() => {
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
if (!this._beforeUnloadRegistered) {
|
|
28
|
+
this._beforeUnloadRegistered = true;
|
|
29
|
+
window.addEventListener("beforeunload", () => {
|
|
30
|
+
for (const w of this._openedWindows) {
|
|
31
|
+
w.close();
|
|
33
32
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
this._openedWindows.clear();
|
|
34
|
+
});
|
|
35
|
+
}
|
|
37
36
|
} else {
|
|
38
37
|
window.open(
|
|
39
38
|
`${location.pathname}#${navigate};${new URLSearchParams(params).toString()}`,
|