@simplysm/angular 14.0.86 → 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.
Files changed (109) hide show
  1. package/dist/controls/pagination/sd-pagination.d.ts.map +1 -1
  2. package/dist/controls/pagination/sd-pagination.js +2 -0
  3. package/dist/controls/select/sd-select-item.js +1 -1
  4. package/dist/controls/select/sd-select.js +1 -1
  5. package/dist/core/app-structure/sd-app-structure.provider.d.ts +1 -0
  6. package/dist/core/app-structure/sd-app-structure.provider.d.ts.map +1 -1
  7. package/dist/core/app-structure/sd-app-structure.provider.js +3 -0
  8. package/dist/core/app-structure/sd-app-structure.utils.d.ts +2 -0
  9. package/dist/core/app-structure/sd-app-structure.utils.d.ts.map +1 -1
  10. package/dist/core/app-structure/sd-app-structure.utils.js +9 -1
  11. package/dist/core/busy/sd-busy-container.d.ts +1 -1
  12. package/dist/core/busy/sd-busy-container.d.ts.map +1 -1
  13. package/dist/core/busy/sd-busy-container.js +11 -11
  14. package/dist/core/busy/sd-busy.provider.d.ts.map +1 -1
  15. package/dist/core/busy/sd-busy.provider.js +3 -0
  16. package/dist/core/config/sd-system-config.provider.d.ts +4 -4
  17. package/dist/core/config/sd-system-config.provider.d.ts.map +1 -1
  18. package/dist/core/config/sd-system-config.provider.js +3 -0
  19. package/dist/core/error-handler/sd-global-error-handler.plugin.d.ts +1 -1
  20. package/dist/core/error-handler/sd-global-error-handler.plugin.d.ts.map +1 -1
  21. package/dist/core/file-dialog/sd-file-dialog.provider.d.ts.map +1 -1
  22. package/dist/core/file-dialog/sd-file-dialog.provider.js +4 -0
  23. package/dist/core/modal/sd-activated-modal.provider.d.ts +2 -1
  24. package/dist/core/modal/sd-activated-modal.provider.d.ts.map +1 -1
  25. package/dist/core/modal/sd-modal.d.ts.map +1 -1
  26. package/dist/core/modal/sd-modal.js +3 -3
  27. package/dist/core/modal/sd-modal.provider.d.ts.map +1 -1
  28. package/dist/core/modal/sd-modal.provider.js +8 -0
  29. package/dist/core/modal/sd-prompt-modal.d.ts +2 -2
  30. package/dist/core/modal/sd-prompt-modal.d.ts.map +1 -1
  31. package/dist/core/modal/sd-prompt-modal.js +32 -37
  32. package/dist/core/print/sd-print.provider.d.ts.map +1 -1
  33. package/dist/core/print/sd-print.provider.js +19 -6
  34. package/dist/core/provideSdAngular.d.ts.map +1 -1
  35. package/dist/core/provideSdAngular.js +4 -1
  36. package/dist/core/routing/injectViewTitleSignal.d.ts.map +1 -1
  37. package/dist/core/routing/injectViewTitleSignal.js +1 -6
  38. package/dist/core/shared-data/sd-shared-data.provider.d.ts +2 -1
  39. package/dist/core/shared-data/sd-shared-data.provider.d.ts.map +1 -1
  40. package/dist/core/shared-data/sd-shared-data.provider.js +1 -1
  41. package/dist/core/toast/sd-toast.provider.d.ts +1 -0
  42. package/dist/core/toast/sd-toast.provider.d.ts.map +1 -1
  43. package/dist/core/toast/sd-toast.provider.js +18 -4
  44. package/dist/data/kanban/sd-kanban-lane.d.ts.map +1 -1
  45. package/dist/data/shared-data/sd-shared-data-select-button.d.ts +1 -2
  46. package/dist/data/shared-data/sd-shared-data-select-button.d.ts.map +1 -1
  47. package/dist/data/shared-data/sd-shared-data-select-button.js +18 -21
  48. package/dist/data/shared-data/sd-shared-data-select.d.ts +3 -2
  49. package/dist/data/shared-data/sd-shared-data-select.d.ts.map +1 -1
  50. package/dist/data/shared-data/sd-shared-data-select.js +10 -10
  51. package/dist/data/sheet/sd-sheet-config.modal.d.ts +3 -3
  52. package/dist/data/sheet/sd-sheet-config.modal.d.ts.map +1 -1
  53. package/dist/data/sheet/sd-sheet-config.modal.js +37 -34
  54. package/dist/data/sheet/sd-sheet.d.ts.map +1 -1
  55. package/dist/data/sheet/sd-sheet.js +5 -1
  56. package/dist/data/sheet/useSheetCellStyling.d.ts.map +1 -1
  57. package/dist/data/sheet/useSheetCellStyling.js +4 -22
  58. package/dist/data/state-preset/sd-state-preset.d.ts +10 -10
  59. package/dist/data/state-preset/sd-state-preset.d.ts.map +1 -1
  60. package/dist/data/state-preset/sd-state-preset.js +4 -4
  61. package/dist/features/address/sd-address-search.modal.js +1 -1
  62. package/dist/features/editor/sd-tiptap-editor.d.ts.map +1 -1
  63. package/dist/features/editor/sd-tiptap-editor.js +3 -2
  64. package/dist/features/theme/sd-theme-selector.d.ts +6 -8
  65. package/dist/features/theme/sd-theme-selector.d.ts.map +1 -1
  66. package/dist/features/theme/sd-theme-selector.js +54 -51
  67. package/dist/features/visual/sd-barcode.d.ts.map +1 -1
  68. package/dist/features/visual/sd-barcode.js +5 -10
  69. package/dist/layout/sidebar/sd-sidebar-user.d.ts.map +1 -1
  70. package/dist/layout/sidebar/sd-sidebar-user.js +26 -36
  71. package/package.json +5 -5
  72. package/src/controls/button/sd-modal-select-button.ts +1 -1
  73. package/src/controls/form/sd-form.ts +1 -1
  74. package/src/controls/input/sd-textfield-type-handlers.ts +2 -2
  75. package/src/controls/pagination/sd-pagination.ts +1 -0
  76. package/src/controls/select/sd-select-item.ts +1 -1
  77. package/src/controls/select/sd-select.ts +1 -1
  78. package/src/core/app-structure/sd-app-structure.provider.ts +4 -0
  79. package/src/core/app-structure/sd-app-structure.utils.ts +14 -2
  80. package/src/core/busy/sd-busy-container.ts +6 -13
  81. package/src/core/busy/sd-busy.provider.ts +4 -0
  82. package/src/core/config/injectSdSystemConfigResource.ts +1 -1
  83. package/src/core/config/sd-system-config.provider.ts +5 -3
  84. package/src/core/error-handler/sd-global-error-handler.plugin.ts +1 -1
  85. package/src/core/file-dialog/sd-file-dialog.provider.ts +5 -1
  86. package/src/core/modal/sd-activated-modal.provider.ts +2 -1
  87. package/src/core/modal/sd-modal.provider.ts +8 -0
  88. package/src/core/modal/sd-modal.ts +6 -3
  89. package/src/core/modal/sd-prompt-modal.ts +13 -23
  90. package/src/core/print/sd-print.provider.ts +21 -6
  91. package/src/core/provideSdAngular.ts +5 -1
  92. package/src/core/routing/injectViewTitleSignal.ts +1 -5
  93. package/src/core/shared-data/sd-shared-data.provider.ts +2 -2
  94. package/src/core/toast/sd-toast.provider.ts +35 -12
  95. package/src/data/kanban/sd-kanban-lane.ts +2 -2
  96. package/src/data/shared-data/sd-shared-data-select-button.ts +15 -20
  97. package/src/data/shared-data/sd-shared-data-select-list.ts +4 -4
  98. package/src/data/shared-data/sd-shared-data-select.ts +10 -12
  99. package/src/data/sheet/sd-sheet-column.ts +1 -1
  100. package/src/data/sheet/sd-sheet-config.modal.ts +39 -35
  101. package/src/data/sheet/sd-sheet.ts +6 -1
  102. package/src/data/sheet/useSheetCellStyling.ts +3 -20
  103. package/src/data/state-preset/sd-state-preset.ts +11 -11
  104. package/src/features/address/sd-address-search.modal.ts +1 -1
  105. package/src/features/editor/sd-tiptap-editor.ts +3 -2
  106. package/src/features/theme/sd-theme-selector.ts +77 -75
  107. package/src/features/visual/sd-barcode.ts +5 -9
  108. package/src/features/visual/sd-calendar.ts +1 -1
  109. package/src/layout/sidebar/sd-sidebar-user.ts +3 -5
@@ -1,14 +1,16 @@
1
1
  import {
2
2
  ChangeDetectionStrategy,
3
3
  Component,
4
- effect,
5
4
  forwardRef,
5
+ inject,
6
6
  input,
7
+ linkedSignal,
7
8
  output,
8
9
  signal,
9
10
  ViewEncapsulation,
10
11
  } from "@angular/core";
11
- import type { SdModalContentDef } from "../../core/modal/sd-modal.provider";
12
+ import { SdModalProvider, type SdModalContentDef } from "../../core/modal/sd-modal.provider";
13
+ import { SdConfirmModal } from "../../core/modal/sd-confirm-modal";
12
14
  import type { SdSheetConfig } from "./types";
13
15
  import type { SdSheetColumn } from "./sd-sheet-column";
14
16
  import { SdSheet } from "./sd-sheet";
@@ -178,14 +180,36 @@ interface ConfigItem {
178
180
  `,
179
181
  })
180
182
  export class SdSheetConfigModal implements SdModalContentDef<SdSheetConfig | undefined> {
181
- initialized = signal(false);
183
+ private readonly _sdModal = inject(SdModalProvider);
184
+
185
+ initialized = signal(true);
182
186
  close = output<SdSheetConfig | undefined>();
183
187
 
184
188
  sheetKey = input.required<string>();
185
189
  controls = input.required<readonly SdSheetColumn[]>();
186
190
  config = input.required<SdSheetConfig | undefined>();
187
191
 
188
- items = signal<ConfigItem[]>([]);
192
+ items = linkedSignal<ConfigItem[]>(() => {
193
+ const cfg = this.config();
194
+ return this.controls()
195
+ .map((ctrl): ConfigItem => {
196
+ const key = ctrl.key();
197
+ const cfgCol = cfg?.columnRecord[key];
198
+ return {
199
+ key,
200
+ header: Array.isArray(ctrl.header())
201
+ ? (ctrl.header() as string[]).join(" > ")
202
+ : (ctrl.header() as string),
203
+ disableResizing: ctrl.disableResizing(),
204
+ fixed: cfgCol?.fixed ?? ctrl.fixed(),
205
+ hidden: cfgCol?.hidden ?? ctrl.hidden(),
206
+ width: cfgCol?.width ?? ctrl.width(),
207
+ ordering: cfgCol?.ordering ?? ctrl.ordering(),
208
+ };
209
+ })
210
+ .orderBy((i) => i.ordering ?? 0)
211
+ .orderBy((i) => (i.fixed ? 0 : 1));
212
+ });
189
213
 
190
214
  trackByFn = (item: ConfigItem): string => item.key;
191
215
 
@@ -194,33 +218,6 @@ export class SdSheetConfigModal implements SdModalContentDef<SdSheetConfig | und
194
218
  protected readonly tablerX = tablerX;
195
219
  protected readonly mark = mark;
196
220
 
197
- constructor() {
198
- effect(() => {
199
- const cfg = this.config();
200
- const items = this.controls()
201
- .map((ctrl): ConfigItem => {
202
- const key = ctrl.key();
203
- const cfgCol = cfg?.columnRecord[key];
204
- return {
205
- key,
206
- header: Array.isArray(ctrl.header())
207
- ? (ctrl.header() as string[]).join(" > ")
208
- : (ctrl.header() as string),
209
- disableResizing: ctrl.disableResizing(),
210
- fixed: cfgCol?.fixed ?? ctrl.fixed(),
211
- hidden: cfgCol?.hidden ?? ctrl.hidden(),
212
- width: cfgCol?.width ?? ctrl.width(),
213
- ordering: cfgCol?.ordering ?? ctrl.ordering(),
214
- };
215
- })
216
- .orderBy((i) => i.ordering ?? 0)
217
- .orderBy((i) => (i.fixed ? 0 : 1));
218
-
219
- this.items.set(items);
220
- this.initialized.set(true);
221
- });
222
- }
223
-
224
221
  onMoveUp(item: ConfigItem): void {
225
222
  this.items.update((v) => {
226
223
  const r = [...v];
@@ -264,9 +261,16 @@ export class SdSheetConfigModal implements SdModalContentDef<SdSheetConfig | und
264
261
  this.close.emit(undefined);
265
262
  }
266
263
 
267
- onResetClick(): void {
268
- if (confirm("설정값이 모두 초기화 됩니다.")) {
269
- this.close.emit({ columnRecord: {} });
270
- }
264
+ async onResetClick(): Promise<void> {
265
+ const confirmed = await this._sdModal.showAsync(
266
+ {
267
+ title: "설정 초기화",
268
+ type: SdConfirmModal,
269
+ inputs: { message: "설정값이 모두 초기화 됩니다." },
270
+ },
271
+ { useCloseByBackdrop: false },
272
+ );
273
+ if (confirmed !== true) return;
274
+ this.close.emit({ columnRecord: {} });
271
275
  }
272
276
  }
@@ -927,11 +927,16 @@ export class SdSheet<TItem> {
927
927
  }
928
928
 
929
929
  async onConfigButtonClick(): Promise<void> {
930
+ const key = this.key();
931
+ if (key == null) {
932
+ throw new Error("시트 설정을 사용하려면 'key'가 지정되어야 합니다.");
933
+ }
934
+
930
935
  const result = await this._sdModal.showAsync({
931
936
  title: "시트 설정",
932
937
  type: SdSheetConfigModal,
933
938
  inputs: {
934
- sheetKey: this.key()!,
939
+ sheetKey: key,
935
940
  controls: this._effectiveColumnControls(),
936
941
  config: this._configResource.value(),
937
942
  },
@@ -28,24 +28,7 @@ export function useSheetCellStyling<T>(options: {
28
28
  return `left: ${leftValue}px`;
29
29
  }
30
30
 
31
- const headerColumnStyles = computed(() => {
32
- const map = new Map<string, string | null>();
33
- const defs = options.columnDefs();
34
- for (let i = 0; i < defs.length; i++) {
35
- const colDef = defs[i];
36
- const parts: string[] = [];
37
- const colStyle = getColDefStyle(colDef);
38
- if (colStyle != null) parts.push(colStyle);
39
- if (colDef.fixed) {
40
- const fixedStyle = getFixedLeftStyle(i);
41
- if (fixedStyle != null) parts.push(fixedStyle);
42
- }
43
- map.set(colDef.key, parts.length > 0 ? parts.join("; ") : null);
44
- }
45
- return map;
46
- });
47
-
48
- const dataColumnBaseStyles = computed(() => {
31
+ const columnBaseStyles = computed(() => {
49
32
  const map = new Map<string, string | null>();
50
33
  const defs = options.columnDefs();
51
34
  for (let i = 0; i < defs.length; i++) {
@@ -65,14 +48,14 @@ export function useSheetCellStyling<T>(options: {
65
48
  function getHeaderCellStyle(cell: SdSheetHeaderDef): string | null {
66
49
  if (cell.colDef == null) return null;
67
50
  const parts: string[] = [];
68
- const baseStyle = headerColumnStyles().get(cell.colDef.key);
51
+ const baseStyle = columnBaseStyles().get(cell.colDef.key);
69
52
  if (baseStyle != null) parts.push(baseStyle);
70
53
  if (cell.colDef.headerStyle != null) parts.push(cell.colDef.headerStyle);
71
54
  return parts.length > 0 ? parts.join("; ") : null;
72
55
  }
73
56
 
74
57
  function getCellStyle(item: T, colDef: SdSheetColumnDef): string | null {
75
- const baseStyle = dataColumnBaseStyles().get(colDef.key) ?? null;
58
+ const baseStyle = columnBaseStyles().get(colDef.key) ?? null;
76
59
  const styleFn = options.getItemCellStyleFn();
77
60
  const customStyle = styleFn != null ? styleFn(item, colDef.key) : undefined;
78
61
  if (baseStyle != null && customStyle != null) return `${baseStyle}; ${customStyle}`;
@@ -17,9 +17,9 @@ import { NgIcon } from "@ng-icons/core";
17
17
  import { tablerStar, tablerDeviceFloppy, tablerX } from "@ng-icons/tabler-icons";
18
18
  import { obj } from "@simplysm/core-common";
19
19
 
20
- export interface SdStatePresetDef {
20
+ export interface SdStatePresetDef<TState> {
21
21
  name: string;
22
- state: any;
22
+ state: TState;
23
23
  }
24
24
 
25
25
  @Component({
@@ -112,19 +112,19 @@ export interface SdStatePresetDef {
112
112
  "[attr.data-sd-size]": "size()",
113
113
  },
114
114
  })
115
- export class SdStatePreset {
115
+ export class SdStatePreset<TState> {
116
116
  private readonly _sdModal = inject(SdModalProvider);
117
117
  private readonly _sdToast = inject(SdToastProvider);
118
118
 
119
119
  key = input.required<string>();
120
- state = model<any>();
120
+ state = model.required<TState>();
121
121
  size = input<"sm" | "lg">();
122
122
 
123
123
  protected readonly tablerStar = tablerStar;
124
124
  protected readonly tablerDeviceFloppy = tablerDeviceFloppy;
125
125
  protected readonly tablerX = tablerX;
126
126
 
127
- private readonly _configResource = injectSdSystemConfigResource<SdStatePresetDef[]>({
127
+ private readonly _configResource = injectSdSystemConfigResource<SdStatePresetDef<TState>[]>({
128
128
  key: this.key,
129
129
  });
130
130
 
@@ -149,31 +149,31 @@ export class SdStatePreset {
149
149
  return;
150
150
  }
151
151
 
152
- const newPreset: SdStatePresetDef = {
152
+ const newPreset: SdStatePresetDef<TState> = {
153
153
  name,
154
154
  state: obj.clone(this.state()),
155
155
  };
156
156
 
157
157
  this._configResource.set([...currentPresets, newPreset]);
158
- this._sdToast.info(`현재 상태가 '${name}'에 저장되었습니다.`);
158
+ this._sdToast.success(`현재 상태가 '${name}'에 저장되었습니다.`);
159
159
  }
160
160
 
161
- onPresetClick(preset: SdStatePresetDef): void {
161
+ onPresetClick(preset: SdStatePresetDef<TState>): void {
162
162
  const currentState = this.state();
163
163
  if (obj.equal(currentState, preset.state)) return;
164
164
  this.state.set(obj.clone(preset.state));
165
165
  }
166
166
 
167
- onSaveClick(preset: SdStatePresetDef): void {
167
+ onSaveClick(preset: SdStatePresetDef<TState>): void {
168
168
  const currentPresets = this._presets();
169
169
  const updated = currentPresets.map((p) =>
170
170
  p.name === preset.name ? { ...p, state: obj.clone(this.state()) } : p,
171
171
  );
172
172
  this._configResource.set(updated);
173
- this._sdToast.info(`현재 상태가 ${preset.name}에 저장되었습니다.`);
173
+ this._sdToast.success(`현재 상태가 ${preset.name}에 저장되었습니다.`);
174
174
  }
175
175
 
176
- async onDeleteClick(preset: SdStatePresetDef): Promise<void> {
176
+ async onDeleteClick(preset: SdStatePresetDef<TState>): Promise<void> {
177
177
  const confirmed = await this._sdModal.showAsync(
178
178
  {
179
179
  title: "프리셋 삭제",
@@ -151,7 +151,7 @@ export class SdAddressSearchModal implements SdModalContentDef<Address>, OnInit
151
151
  this.close.emit({
152
152
  postNumber: data.zonecode,
153
153
  address: addr + extraAddr,
154
- buildingName: data.buildingName,
154
+ buildingName: data.buildingName !== "" ? data.buildingName : undefined,
155
155
  });
156
156
  },
157
157
  onresize: (size: { height: number }): void => {
@@ -323,8 +323,9 @@ export class SdTiptapEditor {
323
323
  }
324
324
  }
325
325
 
326
- if (this.validatorFn()) {
327
- const message = this.validatorFn()!(this.value());
326
+ const validatorFn = this.validatorFn();
327
+ if (validatorFn != null) {
328
+ const message = validatorFn(this.value());
328
329
  if (message != null) {
329
330
  errorMessages.push(message);
330
331
  }
@@ -1,75 +1,77 @@
1
- import {
2
- ChangeDetectionStrategy,
3
- Component,
4
- computed,
5
- inject,
6
- ViewEncapsulation,
7
- } from "@angular/core";
8
- import { SdDropdown } from "../../controls/dropdown/sd-dropdown";
9
- import { SdDropdownPopup } from "../../controls/dropdown/sd-dropdown-popup";
10
- import { SdButton } from "../../controls/button/sd-button";
11
- import { SdSwitch } from "../../controls/checkbox/sd-switch";
12
- import { NgIcon } from "@ng-icons/core";
13
- import { tablerMinus, tablerPalette, tablerPlus } from "@ng-icons/tabler-icons";
14
- import { SdThemeProvider } from "./sd-theme-provider";
15
-
16
- @Component({
17
- selector: "sd-theme-selector",
18
- changeDetection: ChangeDetectionStrategy.OnPush,
19
- encapsulation: ViewEncapsulation.None,
20
- standalone: true,
21
- imports: [SdDropdown, SdDropdownPopup, SdButton, SdSwitch, NgIcon],
22
- template: `
23
- <sd-dropdown>
24
- <sd-button [inline]="true" [theme]="'link-gray'">
25
- <ng-icon [svg]="icons.tablerPalette" />
26
- </sd-button>
27
- <sd-dropdown-popup>
28
- <div class="p-default">
29
- <div class="flex-row gap-sm cross-align-center">
30
- <span>글자 크기</span>
31
- <div class="flex-row gap-xs cross-align-center">
32
- <sd-button
33
- [inline]="true"
34
- [theme]="'link-gray'"
35
- [size]="'sm'"
36
- [disabled]="isMinFontSize()"
37
- (click)="sdTheme.decreaseFontSize()"
38
- >
39
- <ng-icon [svg]="icons.tablerMinus" />
40
- </sd-button>
41
- <span>{{ sdTheme.fontSize() }}px</span>
42
- <sd-button
43
- [inline]="true"
44
- [theme]="'link-gray'"
45
- [size]="'sm'"
46
- [disabled]="isMaxFontSize()"
47
- (click)="sdTheme.increaseFontSize()"
48
- >
49
- <ng-icon [svg]="icons.tablerPlus" />
50
- </sd-button>
51
- </div>
52
- </div>
53
- <div class="flex-row gap-sm cross-align-center">
54
- <span>다크 모드</span>
55
- <sd-switch [(value)]="sdTheme.dark" />
56
- </div>
57
- </div>
58
- </sd-dropdown-popup>
59
- </sd-dropdown>
60
- `,
61
- styles: [],
62
- })
63
- export class SdThemeSelector {
64
- protected readonly icons = { tablerPalette, tablerMinus, tablerPlus };
65
- protected readonly sdTheme = inject(SdThemeProvider);
66
-
67
- protected readonly isMinFontSize = computed(
68
- () => this.sdTheme.fontSize() <= this.sdTheme.fontSizePresets[0],
69
- );
70
-
71
- protected readonly isMaxFontSize = computed(
72
- () =>
73
- this.sdTheme.fontSize() >= this.sdTheme.fontSizePresets[this.sdTheme.fontSizePresets.length - 1],
74
- );
75
- }
1
+ import {
2
+ ChangeDetectionStrategy,
3
+ Component,
4
+ computed,
5
+ inject,
6
+ ViewEncapsulation,
7
+ } from "@angular/core";
8
+ import { SdDropdown } from "../../controls/dropdown/sd-dropdown";
9
+ import { SdDropdownPopup } from "../../controls/dropdown/sd-dropdown-popup";
10
+ import { SdButton } from "../../controls/button/sd-button";
11
+ import { SdSwitch } from "../../controls/checkbox/sd-switch";
12
+ import { NgIcon } from "@ng-icons/core";
13
+ import { SdThemeProvider } from "./sd-theme-provider";
14
+ import { tablerMinus, tablerPalette, tablerPlus } from "@ng-icons/tabler-icons";
15
+
16
+ @Component({
17
+ selector: "sd-theme-selector",
18
+ changeDetection: ChangeDetectionStrategy.OnPush,
19
+ encapsulation: ViewEncapsulation.None,
20
+ standalone: true,
21
+ imports: [SdDropdown, SdDropdownPopup, SdButton, SdSwitch, NgIcon],
22
+ template: `
23
+ <sd-dropdown>
24
+ <sd-button [inline]="true" [theme]="'link-gray'">
25
+ <ng-icon [svg]="tablerPalette" />
26
+ </sd-button>
27
+ <sd-dropdown-popup>
28
+ <div class="p-default">
29
+ <div class="flex-row gap-sm cross-align-center">
30
+ <span>글자 크기</span>
31
+ <div class="flex-row gap-xs cross-align-center">
32
+ <sd-button
33
+ [inline]="true"
34
+ [theme]="'link-gray'"
35
+ [size]="'sm'"
36
+ [disabled]="isMinFontSize()"
37
+ (click)="_sdTheme.decreaseFontSize()"
38
+ >
39
+ <ng-icon [svg]="tablerMinus" />
40
+ </sd-button>
41
+ <span>{{ _sdTheme.fontSize() }}px</span>
42
+ <sd-button
43
+ [inline]="true"
44
+ [theme]="'link-gray'"
45
+ [size]="'sm'"
46
+ [disabled]="isMaxFontSize()"
47
+ (click)="_sdTheme.increaseFontSize()"
48
+ >
49
+ <ng-icon [svg]="tablerPlus" />
50
+ </sd-button>
51
+ </div>
52
+ </div>
53
+ <div class="flex-row gap-sm cross-align-center">
54
+ <span>다크 모드</span>
55
+ <sd-switch [(value)]="_sdTheme.dark" />
56
+ </div>
57
+ </div>
58
+ </sd-dropdown-popup>
59
+ </sd-dropdown>
60
+ `,
61
+ styles: [],
62
+ })
63
+ export class SdThemeSelector {
64
+ protected readonly _sdTheme = inject(SdThemeProvider);
65
+
66
+ isMinFontSize = computed(() => this._sdTheme.fontSize() <= this._sdTheme.fontSizePresets[0]);
67
+
68
+ isMaxFontSize = computed(
69
+ () =>
70
+ this._sdTheme.fontSize() >=
71
+ this._sdTheme.fontSizePresets[this._sdTheme.fontSizePresets.length - 1],
72
+ );
73
+
74
+ protected readonly tablerPlus = tablerPlus;
75
+ protected readonly tablerMinus = tablerMinus;
76
+ protected readonly tablerPalette = tablerPalette;
77
+ }
@@ -32,15 +32,11 @@ export class SdBarcode {
32
32
  if (text == null || text === "") {
33
33
  return "";
34
34
  }
35
- try {
36
- const svg = bwipjs.toSVG({
37
- bcid: this.type(),
38
- text,
39
- });
40
- return this._sanitizer.bypassSecurityTrustHtml(svg);
41
- } catch {
42
- return "";
43
- }
35
+ const svg = bwipjs.toSVG({
36
+ bcid: this.type(),
37
+ text,
38
+ });
39
+ return this._sanitizer.bypassSecurityTrustHtml(svg);
44
40
  });
45
41
  }
46
42
 
@@ -134,7 +134,7 @@ export class SdCalendar<T> {
134
134
 
135
135
  yearMonth = input(new DateOnly().setDay(1));
136
136
 
137
- itemTplRef = contentChild.required<any, TemplateRef<SdItemOfTemplateContext<T>>>(
137
+ itemTplRef = contentChild.required<SdItemOfTemplate<T>, TemplateRef<SdItemOfTemplateContext<T>>>(
138
138
  SdItemOfTemplate,
139
139
  { read: TemplateRef },
140
140
  );
@@ -21,17 +21,15 @@ import { SdListItem } from "../../controls/list/sd-list-item";
21
21
  <div class="p-lg">
22
22
  <ng-content />
23
23
  </div>
24
- @if (userMenu()?.title) {
24
+ @if (userMenu(); as _userMenu) {
25
25
  <div class="_menu-button" tabindex="0" (click)="onMenuOpenButtonClick()" (keydown.enter)="onMenuOpenButtonClick()" [sdRipple]="true">
26
- {{ userMenu()?.title }}
26
+ {{ _userMenu.title }}
27
27
  <sd-collapse-icon [open]="menuOpen()" style="float: right;" [openRotate]="180" />
28
28
  </div>
29
- }
30
29
 
31
- @if (userMenu()?.title) {
32
30
  <sd-collapse [open]="menuOpen()">
33
31
  <sd-list [inset]="true">
34
- @for (menu of userMenu()?.menus; track menu.title) {
32
+ @for (menu of _userMenu.menus; track menu.title) {
35
33
  <sd-list-item (click)="menu.onClick()">
36
34
  {{ menu.title }}
37
35
  </sd-list-item>