@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 { ElementRef, inject, reflectComponentType } from "@angular/core";
|
|
1
|
+
import { DestroyRef, ElementRef, inject, reflectComponentType } from "@angular/core";
|
|
2
2
|
import { ActivatedRoute, type CanDeactivateFn } from "@angular/router";
|
|
3
3
|
import { SdActivatedModalProvider } from "../../../ui/overlay/modal/sd-modal.provider";
|
|
4
4
|
|
|
@@ -8,7 +8,7 @@ export function setupCanDeactivate(fn: () => boolean): void {
|
|
|
8
8
|
const elRef = inject(ElementRef);
|
|
9
9
|
|
|
10
10
|
if (activatedModal != null) {
|
|
11
|
-
activatedModal.
|
|
11
|
+
activatedModal.canDeactiveFn = fn;
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -30,5 +30,13 @@ export function setupCanDeactivate(fn: () => boolean): void {
|
|
|
30
30
|
activatedRoute.routeConfig.canDeactivate = [];
|
|
31
31
|
}
|
|
32
32
|
activatedRoute.routeConfig.canDeactivate.push(canDeactivateFn);
|
|
33
|
+
|
|
34
|
+
const destroyRef = inject(DestroyRef);
|
|
35
|
+
destroyRef.onDestroy(() => {
|
|
36
|
+
const idx = activatedRoute.routeConfig!.canDeactivate!.indexOf(canDeactivateFn);
|
|
37
|
+
if (idx !== -1) {
|
|
38
|
+
activatedRoute.routeConfig!.canDeactivate!.splice(idx, 1);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
33
41
|
}
|
|
34
42
|
}
|
|
@@ -26,6 +26,11 @@ export function setupInvalid(getInvalidMessage: () => string): void {
|
|
|
26
26
|
setSafeStyle(renderer, indicatorEl, { display: isInvalid ? "block" : "none" });
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
+
destroyRef.onDestroy(() => {
|
|
30
|
+
indicatorEl.remove();
|
|
31
|
+
inputEl.remove();
|
|
32
|
+
});
|
|
33
|
+
|
|
29
34
|
const formEl = inputEl.form;
|
|
30
35
|
if (formEl == null) return;
|
|
31
36
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { ErrorHandler, inject, type Signal, type WritableSignal } from "@angular/core";
|
|
2
2
|
|
|
3
3
|
export function setupModelHook<T, S extends WritableSignal<T>>(
|
|
4
4
|
model: S,
|
|
5
5
|
canFn: Signal<(item: T) => boolean | Promise<boolean>>,
|
|
6
6
|
): void {
|
|
7
|
+
const errorHandler = inject(ErrorHandler);
|
|
7
8
|
const orgSet = model.set;
|
|
8
9
|
model.set = (value) => {
|
|
9
10
|
const canSet = canFn()(value);
|
|
@@ -21,6 +22,8 @@ export function setupModelHook<T, S extends WritableSignal<T>>(
|
|
|
21
22
|
if (allowed !== false) {
|
|
22
23
|
orgSet(value);
|
|
23
24
|
}
|
|
24
|
-
}).catch(() => {
|
|
25
|
+
}).catch((err) => {
|
|
26
|
+
errorHandler.handleError(err);
|
|
27
|
+
});
|
|
25
28
|
};
|
|
26
29
|
}
|
|
@@ -44,9 +44,10 @@ export function setupRipple(enableFn?: () => boolean): void {
|
|
|
44
44
|
});
|
|
45
45
|
el.appendChild(indicatorEl);
|
|
46
46
|
|
|
47
|
-
indicatorEl.ontransitionend = () => {
|
|
48
|
-
if (
|
|
47
|
+
indicatorEl.ontransitionend = (ev: TransitionEvent) => {
|
|
48
|
+
if (ev.propertyName === "opacity" && indicatorEl !== undefined) {
|
|
49
49
|
indicatorEl.remove();
|
|
50
|
+
indicatorEl = undefined;
|
|
50
51
|
}
|
|
51
52
|
};
|
|
52
53
|
|
|
@@ -86,9 +86,10 @@ export function useExpandingManager<T>(binding: {
|
|
|
86
86
|
const itemDef = map.get(item);
|
|
87
87
|
if (itemDef == null) return false;
|
|
88
88
|
|
|
89
|
+
const expandedSet = new Set(binding.expandedItems());
|
|
89
90
|
let current = itemDef.parentDef;
|
|
90
91
|
while (current != null) {
|
|
91
|
-
if (!
|
|
92
|
+
if (!expandedSet.has(current.item)) {
|
|
92
93
|
return false;
|
|
93
94
|
}
|
|
94
95
|
current = current.parentDef;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { ElementRef, inject, type ResourceRef, resource, type Signal } from "@angular/core";
|
|
1
|
+
import { ElementRef, ErrorHandler, inject, type ResourceRef, resource, type Signal } from "@angular/core";
|
|
2
2
|
import { SdSystemConfigProvider } from "../providers/sd-system-config.provider";
|
|
3
3
|
|
|
4
4
|
export function useSdSystemConfigResource<T>(options: { key: Signal<string | undefined> }) {
|
|
5
5
|
const sdSystemConfig = inject<SdSystemConfigProvider<Record<string, T>>>(SdSystemConfigProvider);
|
|
6
6
|
const elRef = inject(ElementRef);
|
|
7
|
+
const errorHandler = inject(ErrorHandler);
|
|
7
8
|
|
|
8
9
|
const elTag = elRef.nativeElement.tagName.toLowerCase();
|
|
9
10
|
|
|
@@ -24,8 +25,10 @@ export function useSdSystemConfigResource<T>(options: { key: Signal<string | und
|
|
|
24
25
|
res.set(value);
|
|
25
26
|
const key = options.key();
|
|
26
27
|
if (key == null) return;
|
|
27
|
-
queueMicrotask(
|
|
28
|
-
|
|
28
|
+
queueMicrotask(() => {
|
|
29
|
+
sdSystemConfig.setAsync(`${elTag}.${key}`, value as T).catch((err) => {
|
|
30
|
+
errorHandler.handleError(err);
|
|
31
|
+
});
|
|
29
32
|
});
|
|
30
33
|
},
|
|
31
34
|
update(fn: (prev: T | undefined) => T | undefined) {
|
|
@@ -9,8 +9,10 @@ import {
|
|
|
9
9
|
inject,
|
|
10
10
|
input,
|
|
11
11
|
model,
|
|
12
|
+
signal,
|
|
12
13
|
untracked,
|
|
13
14
|
ViewEncapsulation,
|
|
15
|
+
type WritableSignal,
|
|
14
16
|
} from "@angular/core";
|
|
15
17
|
import { setupInvalid } from "../../../core/utils/setups/setupInvalid";
|
|
16
18
|
import { Editor, type AnyExtension } from "@tiptap/core";
|
|
@@ -41,55 +43,55 @@ const DEFAULT_EXTENSIONS: AnyExtension[] = [
|
|
|
41
43
|
@if (!disabled()) {
|
|
42
44
|
<div class="_toolbar">
|
|
43
45
|
<div class="_btn-group">
|
|
44
|
-
<button type="button" data-cmd="h1" [class._active]="activeStates.h1"
|
|
46
|
+
<button type="button" data-cmd="h1" [class._active]="activeStates().h1"
|
|
45
47
|
(click)="execCmd('h1')">H1</button>
|
|
46
|
-
<button type="button" data-cmd="h2" [class._active]="activeStates.h2"
|
|
48
|
+
<button type="button" data-cmd="h2" [class._active]="activeStates().h2"
|
|
47
49
|
(click)="execCmd('h2')">H2</button>
|
|
48
50
|
</div>
|
|
49
51
|
<div class="_btn-group">
|
|
50
|
-
<button type="button" data-cmd="bold" [class._active]="activeStates.bold"
|
|
52
|
+
<button type="button" data-cmd="bold" [class._active]="activeStates().bold"
|
|
51
53
|
(click)="execCmd('bold')">B</button>
|
|
52
|
-
<button type="button" data-cmd="italic" [class._active]="activeStates.italic"
|
|
54
|
+
<button type="button" data-cmd="italic" [class._active]="activeStates().italic"
|
|
53
55
|
(click)="execCmd('italic')">I</button>
|
|
54
|
-
<button type="button" data-cmd="underline" [class._active]="activeStates.underline"
|
|
56
|
+
<button type="button" data-cmd="underline" [class._active]="activeStates().underline"
|
|
55
57
|
(click)="execCmd('underline')">U</button>
|
|
56
|
-
<button type="button" data-cmd="strike" [class._active]="activeStates.strike"
|
|
58
|
+
<button type="button" data-cmd="strike" [class._active]="activeStates().strike"
|
|
57
59
|
(click)="execCmd('strike')">S</button>
|
|
58
60
|
</div>
|
|
59
61
|
<div class="_btn-group">
|
|
60
62
|
<button type="button" data-cmd="textColor" class="_color-btn"
|
|
61
63
|
(click)="toggleColorPicker('text')">
|
|
62
|
-
<span class="_color-indicator" [style.background-color]="activeColor"></span>
|
|
64
|
+
<span class="_color-indicator" [style.background-color]="activeColor()"></span>
|
|
63
65
|
A
|
|
64
66
|
</button>
|
|
65
67
|
<button type="button" data-cmd="bgColor" class="_color-btn"
|
|
66
68
|
(click)="toggleColorPicker('bg')">
|
|
67
|
-
<span class="_color-indicator" [style.background-color]="activeBgColor"></span>
|
|
69
|
+
<span class="_color-indicator" [style.background-color]="activeBgColor()"></span>
|
|
68
70
|
BG
|
|
69
71
|
</button>
|
|
70
72
|
</div>
|
|
71
73
|
<div class="_btn-group">
|
|
72
|
-
<button type="button" data-cmd="bulletList" [class._active]="activeStates.bulletList"
|
|
74
|
+
<button type="button" data-cmd="bulletList" [class._active]="activeStates().bulletList"
|
|
73
75
|
(click)="execCmd('bulletList')">UL</button>
|
|
74
|
-
<button type="button" data-cmd="orderedList" [class._active]="activeStates.orderedList"
|
|
76
|
+
<button type="button" data-cmd="orderedList" [class._active]="activeStates().orderedList"
|
|
75
77
|
(click)="execCmd('orderedList')">OL</button>
|
|
76
78
|
<button type="button" data-cmd="indent" (click)="execCmd('indent')">→</button>
|
|
77
79
|
<button type="button" data-cmd="outdent" (click)="execCmd('outdent')">←</button>
|
|
78
80
|
</div>
|
|
79
81
|
<div class="_btn-group">
|
|
80
|
-
<button type="button" data-cmd="blockquote" [class._active]="activeStates.blockquote"
|
|
82
|
+
<button type="button" data-cmd="blockquote" [class._active]="activeStates().blockquote"
|
|
81
83
|
(click)="execCmd('blockquote')">❝</button>
|
|
82
|
-
<button type="button" data-cmd="codeBlock" [class._active]="activeStates.codeBlock"
|
|
84
|
+
<button type="button" data-cmd="codeBlock" [class._active]="activeStates().codeBlock"
|
|
83
85
|
(click)="execCmd('codeBlock')"></></button>
|
|
84
86
|
</div>
|
|
85
87
|
<div class="_btn-group">
|
|
86
|
-
<button type="button" data-cmd="alignLeft" [class._active]="activeStates.alignLeft"
|
|
88
|
+
<button type="button" data-cmd="alignLeft" [class._active]="activeStates().alignLeft"
|
|
87
89
|
(click)="execCmd('alignLeft')">≡L</button>
|
|
88
|
-
<button type="button" data-cmd="alignCenter" [class._active]="activeStates.alignCenter"
|
|
90
|
+
<button type="button" data-cmd="alignCenter" [class._active]="activeStates().alignCenter"
|
|
89
91
|
(click)="execCmd('alignCenter')">≡C</button>
|
|
90
|
-
<button type="button" data-cmd="alignRight" [class._active]="activeStates.alignRight"
|
|
92
|
+
<button type="button" data-cmd="alignRight" [class._active]="activeStates().alignRight"
|
|
91
93
|
(click)="execCmd('alignRight')">≡R</button>
|
|
92
|
-
<button type="button" data-cmd="alignJustify" [class._active]="activeStates.alignJustify"
|
|
94
|
+
<button type="button" data-cmd="alignJustify" [class._active]="activeStates().alignJustify"
|
|
93
95
|
(click)="execCmd('alignJustify')">≡J</button>
|
|
94
96
|
</div>
|
|
95
97
|
<div class="_btn-group">
|
|
@@ -249,13 +251,13 @@ export class SdTiptapEditorControl {
|
|
|
249
251
|
"#f9cb9c", "#ffe599", "#b6d7a8", "#a2c4c9", "#a4c2f4", "#9fc5e8", "#b4a7d6", "#d5a6bd",
|
|
250
252
|
];
|
|
251
253
|
|
|
252
|
-
activeStates: Record<string, boolean
|
|
253
|
-
activeColor = "";
|
|
254
|
-
activeBgColor = "";
|
|
254
|
+
activeStates: WritableSignal<Record<string, boolean>> = signal({});
|
|
255
|
+
activeColor = signal("");
|
|
256
|
+
activeBgColor = signal("");
|
|
255
257
|
colorPickerMode: "text" | "bg" | undefined;
|
|
256
258
|
|
|
257
259
|
/** @internal -- TipTap Editor 인스턴스. 테스트 및 고급 사용자용 */
|
|
258
|
-
editor: Editor | undefined;
|
|
260
|
+
editor: WritableSignal<Editor | undefined> = signal(undefined);
|
|
259
261
|
private updatingFromEditor = false;
|
|
260
262
|
private lastExtensions: AnyExtension[] | undefined;
|
|
261
263
|
|
|
@@ -288,17 +290,19 @@ export class SdTiptapEditorControl {
|
|
|
288
290
|
}
|
|
289
291
|
|
|
290
292
|
// Sync value to existing editor
|
|
291
|
-
|
|
292
|
-
|
|
293
|
+
const currentEditor = untracked(() => this.editor());
|
|
294
|
+
if (currentEditor == null) return;
|
|
295
|
+
const currentHtml = this.getEditorHtmlFrom(currentEditor);
|
|
293
296
|
if (currentHtml === val) return;
|
|
294
|
-
|
|
297
|
+
currentEditor.commands.setContent(val ?? "", { emitUpdate: false });
|
|
295
298
|
});
|
|
296
299
|
|
|
297
300
|
// disabled/readonly → editor.setEditable()
|
|
298
301
|
effect(() => {
|
|
299
|
-
|
|
302
|
+
const ed = this.editor();
|
|
303
|
+
if (ed == null) return;
|
|
300
304
|
const editable = !this.disabled() && !this.readonly();
|
|
301
|
-
|
|
305
|
+
ed.setEditable(editable);
|
|
302
306
|
});
|
|
303
307
|
|
|
304
308
|
// setupInvalid for form validation
|
|
@@ -329,7 +333,7 @@ export class SdTiptapEditorControl {
|
|
|
329
333
|
const container = this.elRef.nativeElement.querySelector("._editor-container");
|
|
330
334
|
if (container == null) return;
|
|
331
335
|
|
|
332
|
-
this.editor
|
|
336
|
+
this.editor.set(new Editor({
|
|
333
337
|
element: container,
|
|
334
338
|
extensions,
|
|
335
339
|
content: initialContent ?? "",
|
|
@@ -343,21 +347,17 @@ export class SdTiptapEditorControl {
|
|
|
343
347
|
onTransaction: () => {
|
|
344
348
|
this.refreshActiveStates();
|
|
345
349
|
},
|
|
346
|
-
});
|
|
350
|
+
}));
|
|
347
351
|
}
|
|
348
352
|
|
|
349
353
|
private destroyEditor(): void {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
354
|
+
const ed = untracked(() => this.editor());
|
|
355
|
+
if (ed != null) {
|
|
356
|
+
ed.destroy();
|
|
357
|
+
this.editor.set(undefined);
|
|
353
358
|
}
|
|
354
359
|
}
|
|
355
360
|
|
|
356
|
-
private getEditorHtml(): string | undefined {
|
|
357
|
-
if (this.editor == null) return undefined;
|
|
358
|
-
return this.getEditorHtmlFrom(this.editor);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
361
|
private getEditorHtmlFrom(editor: Editor): string | undefined {
|
|
362
362
|
const html = editor.getHTML();
|
|
363
363
|
if (editor.isEmpty) return undefined;
|
|
@@ -365,9 +365,10 @@ export class SdTiptapEditorControl {
|
|
|
365
365
|
}
|
|
366
366
|
|
|
367
367
|
execCmd(cmd: string): void {
|
|
368
|
-
|
|
368
|
+
const ed = this.editor();
|
|
369
|
+
if (ed == null) return;
|
|
369
370
|
|
|
370
|
-
const chain =
|
|
371
|
+
const chain = ed.chain().focus();
|
|
371
372
|
switch (cmd) {
|
|
372
373
|
case "bold":
|
|
373
374
|
chain.toggleBold().run();
|
|
@@ -428,9 +429,10 @@ export class SdTiptapEditorControl {
|
|
|
428
429
|
}
|
|
429
430
|
|
|
430
431
|
applyColor(color: string | undefined): void {
|
|
431
|
-
|
|
432
|
+
const ed = this.editor();
|
|
433
|
+
if (ed == null) return;
|
|
432
434
|
|
|
433
|
-
const chain =
|
|
435
|
+
const chain = ed.chain().focus();
|
|
434
436
|
if (this.colorPickerMode === "text") {
|
|
435
437
|
if (color !== undefined) {
|
|
436
438
|
chain.setColor(color).run();
|
|
@@ -448,27 +450,28 @@ export class SdTiptapEditorControl {
|
|
|
448
450
|
}
|
|
449
451
|
|
|
450
452
|
private refreshActiveStates(): void {
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
453
|
+
const ed = this.editor();
|
|
454
|
+
if (ed == null) return;
|
|
455
|
+
this.activeStates.set({
|
|
456
|
+
bold: ed.isActive("bold"),
|
|
457
|
+
italic: ed.isActive("italic"),
|
|
458
|
+
underline: ed.isActive("underline"),
|
|
459
|
+
strike: ed.isActive("strike"),
|
|
460
|
+
h1: ed.isActive("heading", { level: 1 }),
|
|
461
|
+
h2: ed.isActive("heading", { level: 2 }),
|
|
462
|
+
bulletList: ed.isActive("bulletList"),
|
|
463
|
+
orderedList: ed.isActive("orderedList"),
|
|
464
|
+
blockquote: ed.isActive("blockquote"),
|
|
465
|
+
codeBlock: ed.isActive("codeBlock"),
|
|
466
|
+
alignLeft: ed.isActive({ textAlign: "left" }),
|
|
467
|
+
alignCenter: ed.isActive({ textAlign: "center" }),
|
|
468
|
+
alignRight: ed.isActive({ textAlign: "right" }),
|
|
469
|
+
alignJustify: ed.isActive({ textAlign: "justify" }),
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
const textColor = ed.getAttributes("textStyle")["color"];
|
|
473
|
+
this.activeColor.set(typeof textColor === "string" ? textColor : "");
|
|
474
|
+
const bgColor = ed.getAttributes("highlight")["color"];
|
|
475
|
+
this.activeBgColor.set(typeof bgColor === "string" ? bgColor : "");
|
|
473
476
|
}
|
|
474
477
|
}
|
|
@@ -70,8 +70,9 @@ export class SdDateRangePicker {
|
|
|
70
70
|
if (this.periodType() === "월") {
|
|
71
71
|
const fromDate = this.from();
|
|
72
72
|
if (fromDate) {
|
|
73
|
-
|
|
74
|
-
this.
|
|
73
|
+
const firstOfMonth = fromDate.setDay(1);
|
|
74
|
+
this.from.set(firstOfMonth);
|
|
75
|
+
this.to.set(firstOfMonth.addMonths(1).addDays(-1));
|
|
75
76
|
} else {
|
|
76
77
|
this.to.set(undefined);
|
|
77
78
|
}
|
|
@@ -83,7 +84,7 @@ export class SdDateRangePicker {
|
|
|
83
84
|
handleFromDateChanged(): void {
|
|
84
85
|
if (this.periodType() === "월") {
|
|
85
86
|
const fromDate = this.from();
|
|
86
|
-
this.to.set(fromDate?.
|
|
87
|
+
this.to.set(fromDate?.setDay(1).addMonths(1).addDays(-1));
|
|
87
88
|
} else if (this.periodType() === "일") {
|
|
88
89
|
this.to.set(this.from());
|
|
89
90
|
} else if (
|
|
@@ -103,7 +103,7 @@ function createStringHandler(type: "text" | "password" | "email" | "color"): ITe
|
|
|
103
103
|
return errors;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
if (type
|
|
106
|
+
if (type !== "color") {
|
|
107
107
|
const str = value as string;
|
|
108
108
|
if (opts.minlength !== undefined && opts.minlength > str.length) {
|
|
109
109
|
errors.push(`문자의 길이가 ${opts.minlength}보다 길거나 같아야 합니다.`);
|
|
@@ -213,10 +213,10 @@ function createFormatHandler(): ITextfieldTypeHandler {
|
|
|
213
213
|
(v, i, a) => a.indexOf(v) === i,
|
|
214
214
|
);
|
|
215
215
|
if (nonFormatChars != null && nonFormatChars.length > 0) {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
);
|
|
216
|
+
const escaped = nonFormatChars.map((ch) =>
|
|
217
|
+
ch === "]" || ch === "\\" || ch === "^" || ch === "-" ? "\\" + ch : ch,
|
|
218
|
+
).join("");
|
|
219
|
+
return raw.replace(new RegExp(`[${escaped}]`, "g"), "");
|
|
220
220
|
}
|
|
221
221
|
return raw;
|
|
222
222
|
},
|
|
@@ -371,6 +371,16 @@ function createDateTimeHandler(withSeconds: boolean): ITextfieldTypeHandler {
|
|
|
371
371
|
|
|
372
372
|
if (!(value instanceof DateTime)) {
|
|
373
373
|
errors.push("날짜 및 시간을 입력하세요");
|
|
374
|
+
return errors;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const min = opts.min;
|
|
378
|
+
const max = opts.max;
|
|
379
|
+
if (min instanceof DateTime && min.tick > value.tick) {
|
|
380
|
+
errors.push(`${min}보다 크거나 같아야 합니다.`);
|
|
381
|
+
}
|
|
382
|
+
if (max instanceof DateTime && max.tick < value.tick) {
|
|
383
|
+
errors.push(`${max}보다 작거나 같아야 합니다.`);
|
|
374
384
|
}
|
|
375
385
|
|
|
376
386
|
return errors;
|
|
@@ -415,6 +425,16 @@ function createTimeHandler(withSeconds: boolean): ITextfieldTypeHandler {
|
|
|
415
425
|
|
|
416
426
|
if (!(value instanceof Time)) {
|
|
417
427
|
errors.push("시간을 입력하세요");
|
|
428
|
+
return errors;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const min = opts.min;
|
|
432
|
+
const max = opts.max;
|
|
433
|
+
if (min instanceof Time && min.tick > value.tick) {
|
|
434
|
+
errors.push(`${min}보다 크거나 같아야 합니다.`);
|
|
435
|
+
}
|
|
436
|
+
if (max instanceof Time && max.tick < value.tick) {
|
|
437
|
+
errors.push(`${max}보다 작거나 같아야 합니다.`);
|
|
418
438
|
}
|
|
419
439
|
|
|
420
440
|
return errors;
|
|
@@ -379,6 +379,7 @@ export class SdTextfieldControl<K extends keyof TSdTextfieldTypes> {
|
|
|
379
379
|
}
|
|
380
380
|
|
|
381
381
|
onInputPaste(event: ClipboardEvent): void {
|
|
382
|
+
event.preventDefault();
|
|
382
383
|
const text = event.clipboardData?.getData("text/plain").trim();
|
|
383
384
|
if (text == null || text === "") {
|
|
384
385
|
this.value.set(undefined);
|
|
@@ -208,7 +208,7 @@ export class SdModalControl {
|
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
private _requestClose(): void {
|
|
211
|
-
if (this._activatedModal !== null && !this._activatedModal.
|
|
211
|
+
if (this._activatedModal !== null && !this._activatedModal.canDeactiveFn()) {
|
|
212
212
|
return;
|
|
213
213
|
}
|
|
214
214
|
void this._saveConfig();
|
|
@@ -65,7 +65,7 @@ export interface ISdModalOptions {
|
|
|
65
65
|
export class SdActivatedModalProvider<T extends ISdModal<any> = ISdModal<any>> {
|
|
66
66
|
modalComponent = signal<any>(undefined);
|
|
67
67
|
contentComponent = signal<T | undefined>(undefined);
|
|
68
|
-
|
|
68
|
+
canDeactiveFn: () => boolean = () => true;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
/**
|