@simplysm/angular 14.1.14 → 14.1.17

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.
@@ -5,7 +5,8 @@ const _c0 = ["contentEl"];
5
5
  const _c1 = ["*"];
6
6
  export class SdCollapse {
7
7
  open = input(false, { ...(ngDevMode ? { debugName: "open" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
8
- _contentElRef = viewChild.required("contentEl");
8
+ _contentElRef = viewChild.required("contentEl", /* @ts-ignore */
9
+ ...(ngDevMode ? [{ debugName: "_contentElRef" }] : /* istanbul ignore next */ []));
9
10
  contentHeight = signal(0, /* @ts-ignore */
10
11
  ...(ngDevMode ? [{ debugName: "contentHeight" }] : /* istanbul ignore next */ []));
11
12
  _initialized = signal(false, /* @ts-ignore */
@@ -9,9 +9,7 @@ export class SdDropdown {
9
9
  open = model(false, /* @ts-ignore */
10
10
  ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
11
11
  disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
12
- popupElRef = contentChild.required(SdDropdownPopup, {
13
- read: ElementRef,
14
- });
12
+ popupElRef = contentChild.required(SdDropdownPopup, { ...(ngDevMode ? { debugName: "popupElRef" } : /* istanbul ignore next */ {}), read: ElementRef });
15
13
  _popupEl;
16
14
  _mouseoverEl;
17
15
  _backdropEl;
@@ -3,9 +3,7 @@ import * as i0 from "@angular/core";
3
3
  const _c0 = ["formEl"];
4
4
  const _c1 = ["*"];
5
5
  export class SdForm {
6
- formElRef = viewChild.required("formEl", {
7
- read: ElementRef,
8
- });
6
+ formElRef = viewChild.required("formEl", { ...(ngDevMode ? { debugName: "formElRef" } : /* istanbul ignore next */ {}), read: ElementRef });
9
7
  get formEl() {
10
8
  return this.formElRef().nativeElement;
11
9
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sd-textfield.d.ts","sourceRoot":"","sources":["../../../src/controls/input/sd-textfield.ts"],"names":[],"mappings":"AAiBA,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAC;;AAEtC,qBAqRa,WAAW,CAAC,CAAC,SAAS,MAAM,gBAAgB;IACvD,KAAK,uEAAgC;IAErC,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,uEAAgC;IACnC,GAAG,uEAAgC;IACnC,SAAS,0DAAmB;IAC5B,SAAS,0DAAmB;IAC5B,OAAO,0DAAmB;IAC1B,WAAW,+CAAiB,gBAAgB,CAAC,CAAC,CAAC,GAAG,SAAS,KAAK,MAAM,GAAG,SAAS,eAAI;IACtF,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,WAAW,CAAsD;IAGlF,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAc;IAGpD,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsD;IAE/E,WAAW,yCAA+C;IAE1D,WAAW,kDAA+D;IAE1E,YAAY,yCAOT;IAEH,gBAAgB,qDAMb;;IAmEH,kBAAkB,IAAI,IAAI;IAI1B,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAK/C,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAM3B,OAAO,CAAC,WAAW;IAiBnB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAQ/B,OAAO,CAAC,mBAAmB;yCAzKhB,WAAW;2CAAX,WAAW;CA6KvB"}
1
+ {"version":3,"file":"sd-textfield.d.ts","sourceRoot":"","sources":["../../../src/controls/input/sd-textfield.ts"],"names":[],"mappings":"AAiBA,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAC;;AAEtC,qBAqRa,WAAW,CAAC,CAAC,SAAS,MAAM,gBAAgB;IACvD,KAAK,uEAAgC;IAErC,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,uEAAgC;IACnC,GAAG,uEAAgC;IACnC,SAAS,0DAAmB;IAC5B,SAAS,0DAAmB;IAC5B,OAAO,0DAAmB;IAC1B,WAAW,+CAAiB,gBAAgB,CAAC,CAAC,CAAC,GAAG,SAAS,KAAK,MAAM,GAAG,SAAS,eAAI;IACtF,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,WAAW,CAAsD;IAGlF,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAc;IAGpD,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsD;IAE/E,WAAW,yCAA+C;IAE1D,WAAW,kDAA+D;IAE1E,YAAY,yCAOT;IAEH,gBAAgB,qDAMb;;IAuEH,kBAAkB,IAAI,IAAI;IAI1B,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAK/C,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAO3B,OAAO,CAAC,WAAW;IAiBnB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAU/B,OAAO,CAAC,mBAAmB;yCAhLhB,WAAW;2CAAX,WAAW;CAoLvB"}
@@ -132,6 +132,10 @@ export class SdTextfield {
132
132
  const inputEl = this._inputElRef()?.nativeElement;
133
133
  if (inputEl == null)
134
134
  return;
135
+ // IME 조합 중에는 DOM 을 되쓰지 않는다. 되쓰면 진행 중 조합이 깨진다.
136
+ // 조합이 끝나면 onCompositionEnd → value.set 이 controlValue 를 바꿔 effect 가 다시 돌아 최종값을 반영한다.
137
+ if (this._composing)
138
+ return;
135
139
  // 편집(포커스) 중이라도 변경 origin 을 구분한다.
136
140
  // 사용자 입력이 만든 DOM(정규화 차이·진행 중 입력 포함)은 보호하고,
137
141
  // 모델만 외부에서 바뀐 경우(프로그래밍적 리셋·prefill·표시옵션 변경)는 되써서 반영한다.
@@ -191,7 +195,8 @@ export class SdTextfield {
191
195
  }
192
196
  onInput(event) {
193
197
  // 조합 중 input 은 무시하고, 완성 시 onCompositionEnd 에서 한 번만 반영
194
- if (this._composing)
198
+ // isComposing 은 compositionstart 가 늦거나 누락된 IME 에서도 브라우저가 조합 구간 input 에 직접 실어주는 신호
199
+ if (event.isComposing || this._composing)
195
200
  return;
196
201
  this._applyInput(event.target);
197
202
  }
@@ -216,6 +221,8 @@ export class SdTextfield {
216
221
  onBlur(event) {
217
222
  // 편집 종료 시 모델 기준값으로 동기화 (number 콤마 포맷 반영, date 미완성 입력 정리)
218
223
  // date 미완성 입력은 input.value 가 "" 라 비교 없이 무조건 되써야 남은 세그먼트가 정리됨
224
+ // compositionend 가 스킵된 채 blur 되면 _composing 이 true 로 고착되므로 여기서 리셋한다.
225
+ this._composing = false;
219
226
  const inputEl = event.target;
220
227
  inputEl.value = this.controlValue();
221
228
  this._syncNativeValidity(inputEl);
@@ -129,8 +129,9 @@ export class SdSelect {
129
129
  tablerCaretDown = tablerCaretDown;
130
130
  _itemControls = contentChildren(SdSelectItem, /* @ts-ignore */
131
131
  ...(ngDevMode ? [{ debugName: "_itemControls" }] : /* istanbul ignore next */ []));
132
- _dropdownControl = viewChild.required(SdDropdown);
133
- _dropdownElRef = viewChild.required(SdDropdown, { read: ElementRef });
132
+ _dropdownControl = viewChild.required(SdDropdown, /* @ts-ignore */
133
+ ...(ngDevMode ? [{ debugName: "_dropdownControl" }] : /* istanbul ignore next */ []));
134
+ _dropdownElRef = viewChild.required(SdDropdown, { ...(ngDevMode ? { debugName: "_dropdownElRef" } : /* istanbul ignore next */ {}), read: ElementRef });
134
135
  _headerTpl = contentChild("headerTpl", /* @ts-ignore */
135
136
  ...(ngDevMode ? [{ debugName: "_headerTpl" }] : /* istanbul ignore next */ []));
136
137
  _beforeTpl = contentChild("beforeTpl", /* @ts-ignore */
@@ -35,7 +35,7 @@ export class SdSharedDataSelectButton {
35
35
  inset = input(false, { ...(ngDevMode ? { debugName: "inset" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
36
36
  size = input(/* @ts-ignore */
37
37
  ...(ngDevMode ? [undefined, { debugName: "size" }] : /* istanbul ignore next */ []));
38
- itemTplRef = contentChild.required(SdItemOfTemplate, { read: TemplateRef });
38
+ itemTplRef = contentChild.required(SdItemOfTemplate, { ...(ngDevMode ? { debugName: "itemTplRef" } : /* istanbul ignore next */ {}), read: TemplateRef });
39
39
  _selectedItems = computed(() => {
40
40
  const v = this.value();
41
41
  const items = this.items();
@@ -21,7 +21,7 @@ export class SdSheetColumn {
21
21
  disableResizing = input(false, { ...(ngDevMode ? { debugName: "disableResizing" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
22
22
  ordering = input(0, /* @ts-ignore */
23
23
  ...(ngDevMode ? [{ debugName: "ordering" }] : /* istanbul ignore next */ []));
24
- cellTplRef = contentChild.required(SdSheetColumnCellTemplate, { read: TemplateRef });
24
+ cellTplRef = contentChild.required(SdSheetColumnCellTemplate, { ...(ngDevMode ? { debugName: "cellTplRef" } : /* istanbul ignore next */ {}), read: TemplateRef });
25
25
  headerTplRef = contentChild("headerTpl", /* @ts-ignore */
26
26
  ...(ngDevMode ? [{ debugName: "headerTplRef" }] : /* istanbul ignore next */ []));
27
27
  summaryTplRef = contentChild("summaryTpl", /* @ts-ignore */
@@ -71,48 +71,48 @@ export class SdThemeSelector {
71
71
  }
72
72
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SdThemeSelector, [{
73
73
  type: Component,
74
- args: [{ selector: "sd-theme-selector", changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, standalone: true, imports: [SdDropdown, SdDropdownPopup, SdButton, SdSwitch, NgIcon], template: `
75
- <sd-dropdown>
76
- <sd-button [inline]="true" [theme]="'link-gray'">
77
- <ng-icon [svg]="tablerPalette" />
78
- </sd-button>
79
- <sd-dropdown-popup>
80
- <div class="p-default">
81
- <div class="flex-row gap-sm cross-align-center">
82
- <span>글자 크기</span>
83
- <div class="flex-row gap-xs cross-align-center">
84
- <sd-button
85
- [inline]="true"
86
- [theme]="'link-gray'"
87
- [size]="'sm'"
88
- [disabled]="isMinFontSize()"
89
- (click)="_sdTheme.decreaseFontSize()"
90
- >
91
- <ng-icon [svg]="tablerMinus" />
92
- </sd-button>
93
- <span>{{ _sdTheme.fontSize() }}px</span>
94
- <sd-button
95
- [inline]="true"
96
- [theme]="'link-gray'"
97
- [size]="'sm'"
98
- [disabled]="isMaxFontSize()"
99
- (click)="_sdTheme.increaseFontSize()"
100
- >
101
- <ng-icon [svg]="tablerPlus" />
102
- </sd-button>
103
- </div>
104
- </div>
105
- <div class="flex-row gap-sm cross-align-center">
106
- <span>다크 모드</span>
107
- <sd-switch [(value)]="_sdTheme.dark" />
108
- </div>
109
- <div class="flex-row gap-sm cross-align-center">
110
- <span>블루프린트</span>
111
- <sd-switch [(value)]="_sdTheme.blueprint" />
112
- </div>
113
- </div>
114
- </sd-dropdown-popup>
115
- </sd-dropdown>
74
+ args: [{ selector: "sd-theme-selector", changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, standalone: true, imports: [SdDropdown, SdDropdownPopup, SdButton, SdSwitch, NgIcon], template: `
75
+ <sd-dropdown>
76
+ <sd-button [inline]="true" [theme]="'link-gray'">
77
+ <ng-icon [svg]="tablerPalette" />
78
+ </sd-button>
79
+ <sd-dropdown-popup>
80
+ <div class="p-default">
81
+ <div class="flex-row gap-sm cross-align-center">
82
+ <span>글자 크기</span>
83
+ <div class="flex-row gap-xs cross-align-center">
84
+ <sd-button
85
+ [inline]="true"
86
+ [theme]="'link-gray'"
87
+ [size]="'sm'"
88
+ [disabled]="isMinFontSize()"
89
+ (click)="_sdTheme.decreaseFontSize()"
90
+ >
91
+ <ng-icon [svg]="tablerMinus" />
92
+ </sd-button>
93
+ <span>{{ _sdTheme.fontSize() }}px</span>
94
+ <sd-button
95
+ [inline]="true"
96
+ [theme]="'link-gray'"
97
+ [size]="'sm'"
98
+ [disabled]="isMaxFontSize()"
99
+ (click)="_sdTheme.increaseFontSize()"
100
+ >
101
+ <ng-icon [svg]="tablerPlus" />
102
+ </sd-button>
103
+ </div>
104
+ </div>
105
+ <div class="flex-row gap-sm cross-align-center">
106
+ <span>다크 모드</span>
107
+ <sd-switch [(value)]="_sdTheme.dark" />
108
+ </div>
109
+ <div class="flex-row gap-sm cross-align-center">
110
+ <span>블루프린트</span>
111
+ <sd-switch [(value)]="_sdTheme.blueprint" />
112
+ </div>
113
+ </div>
114
+ </sd-dropdown-popup>
115
+ </sd-dropdown>
116
116
  ` }]
117
117
  }], null, null); })();
118
118
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SdThemeSelector, { className: "SdThemeSelector", filePath: "packages/angular/src/features/theme/sd-theme-selector.ts", lineNumber: 67 }); })();
@@ -48,7 +48,7 @@ export class SdCalendar {
48
48
  ...(ngDevMode ? [{ debugName: "getItemDateFn" }] : /* istanbul ignore next */ []));
49
49
  yearMonth = input(new DateOnly().setDay(1), /* @ts-ignore */
50
50
  ...(ngDevMode ? [{ debugName: "yearMonth" }] : /* istanbul ignore next */ []));
51
- itemTplRef = contentChild.required(SdItemOfTemplate, { read: TemplateRef });
51
+ itemTplRef = contentChild.required(SdItemOfTemplate, { ...(ngDevMode ? { debugName: "itemTplRef" } : /* istanbul ignore next */ {}), read: TemplateRef });
52
52
  weekStartDay = input(0, /* @ts-ignore */
53
53
  ...(ngDevMode ? [{ debugName: "weekStartDay" }] : /* istanbul ignore next */ []));
54
54
  minDaysInFirstWeek = input(1, /* @ts-ignore */
@@ -12,7 +12,7 @@ export class SdSidebar {
12
12
  } }, ngContentSelectors: _c0, decls: 1, vars: 0, template: function SdSidebar_Template(rf, ctx) { if (rf & 1) {
13
13
  i0.ɵɵprojectionDef();
14
14
  i0.ɵɵprojection(0);
15
- } }, styles: ["/*@function to-rgb($oklch-color) {\n @return color.to-space($oklch-color, rgb);\n}*/\n/*$colors: (\n red: to-rgb(oklch(0.704 0.191 22.216)),\n orange: to-rgb(oklch(0.75 0.183 55.934)),\n amber: to-rgb(oklch(0.828 0.189 84.429)),\n yellow: to-rgb(oklch(0.852 0.199 91.936)),\n lime: to-rgb(oklch(0.841 0.238 128.85)),\n green: to-rgb(oklch(0.792 0.209 151.711)),\n emerald: to-rgb(oklch(0.765 0.177 163.223)),\n teal: to-rgb(oklch(0.777 0.152 181.912)),\n cyan: to-rgb(oklch(0.789 0.154 211.53)),\n sky: to-rgb(oklch(0.746 0.16 232.661)),\n blue: to-rgb(oklch(0.707 0.165 254.624)),\n indigo: to-rgb(oklch(0.673 0.182 276.935)),\n violet: to-rgb(oklch(0.702 0.183 293.541)),\n purple: to-rgb(oklch(0.714 0.203 305.504)),\n fuchsia: to-rgb(oklch(0.74 0.238 322.16)),\n pink: to-rgb(oklch(0.718 0.202 349.761)),\n rose: to-rgb(oklch(0.712 0.194 13.428)),\n slate: to-rgb(oklch(0.704 0.04 256.788)),\n gray: to-rgb(oklch(0.707 0.022 261.325)),\n zinc: to-rgb(oklch(0.705 0.015 286.067)),\n neutral: to-rgb(oklch(0.708 0 0)),\n stone: to-rgb(oklch(0.709 0.01 56.259)),\n);*/\nsd-sidebar {\n position: absolute;\n z-index: var(--z-index-sidebar);\n top: 0;\n left: 0;\n width: var(--sidebar-width);\n height: 100%;\n}\n@media not all and (max-width: 520px) {\n sd-sidebar {\n transition: transform var(--animation-duration) ease-out;\n }\n sd-sidebar[data-sd-toggle=true] {\n transform: translateX(-100%);\n transition: transform var(--animation-duration) ease-in;\n }\n}\n@media all and (max-width: 520px) {\n sd-sidebar {\n transition: transform var(--animation-duration) ease-in;\n transform: translateX(-100%);\n }\n sd-sidebar[data-sd-toggle=true] {\n transform: none;\n transition: transform var(--animation-duration) ease-out;\n box-shadow: 0 calc(16 * var(--elevation-size)) calc(16 * 4 * var(--elevation-size) * var(--elevation-blur-mult)) var(--trans-lighter), 0 var(--elevation-size) calc(var(--elevation-size) * var(--elevation-blur-mult)) var(--trans-lighter);\n }\n}"], encapsulation: 2 });
15
+ } }, styles: ["/*@function to-rgb($oklch-color) {\n @return color.to-space($oklch-color, rgb);\n}*/\n/*$colors: (\n red: to-rgb(oklch(0.704 0.191 22.216)),\n orange: to-rgb(oklch(0.75 0.183 55.934)),\n amber: to-rgb(oklch(0.828 0.189 84.429)),\n yellow: to-rgb(oklch(0.852 0.199 91.936)),\n lime: to-rgb(oklch(0.841 0.238 128.85)),\n green: to-rgb(oklch(0.792 0.209 151.711)),\n emerald: to-rgb(oklch(0.765 0.177 163.223)),\n teal: to-rgb(oklch(0.777 0.152 181.912)),\n cyan: to-rgb(oklch(0.789 0.154 211.53)),\n sky: to-rgb(oklch(0.746 0.16 232.661)),\n blue: to-rgb(oklch(0.707 0.165 254.624)),\n indigo: to-rgb(oklch(0.673 0.182 276.935)),\n violet: to-rgb(oklch(0.702 0.183 293.541)),\n purple: to-rgb(oklch(0.714 0.203 305.504)),\n fuchsia: to-rgb(oklch(0.74 0.238 322.16)),\n pink: to-rgb(oklch(0.718 0.202 349.761)),\n rose: to-rgb(oklch(0.712 0.194 13.428)),\n slate: to-rgb(oklch(0.704 0.04 256.788)),\n gray: to-rgb(oklch(0.707 0.022 261.325)),\n zinc: to-rgb(oklch(0.705 0.015 286.067)),\n neutral: to-rgb(oklch(0.708 0 0)),\n stone: to-rgb(oklch(0.709 0.01 56.259)),\n);*/\nsd-sidebar {\n position: absolute;\n z-index: var(--z-index-sidebar);\n top: 0;\n left: 0;\n width: var(--sidebar-width);\n height: 100%;\n border-right: 1px solid var(--border-color-lighter);\n}\n@media not all and (max-width: 520px) {\n sd-sidebar {\n transition: transform var(--animation-duration) ease-out;\n }\n sd-sidebar[data-sd-toggle=true] {\n transform: translateX(-100%);\n transition: transform var(--animation-duration) ease-in;\n }\n}\n@media all and (max-width: 520px) {\n sd-sidebar {\n transition: transform var(--animation-duration) ease-in;\n transform: translateX(-100%);\n }\n sd-sidebar[data-sd-toggle=true] {\n transform: none;\n transition: transform var(--animation-duration) ease-out;\n box-shadow: 0 calc(16 * var(--elevation-size)) calc(16 * 4 * var(--elevation-size) * var(--elevation-blur-mult)) var(--trans-lighter), 0 var(--elevation-size) calc(var(--elevation-size) * var(--elevation-blur-mult)) var(--trans-lighter);\n }\n}"], encapsulation: 2 });
16
16
  }
17
17
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SdSidebar, [{
18
18
  type: Component,
@@ -20,6 +20,6 @@ export class SdSidebar {
20
20
  "[attr.data-sd-toggle]": "toggle()",
21
21
  }, template: `
22
22
  <ng-content />
23
- `, styles: ["/*@function to-rgb($oklch-color) {\n @return color.to-space($oklch-color, rgb);\n}*/\n/*$colors: (\n red: to-rgb(oklch(0.704 0.191 22.216)),\n orange: to-rgb(oklch(0.75 0.183 55.934)),\n amber: to-rgb(oklch(0.828 0.189 84.429)),\n yellow: to-rgb(oklch(0.852 0.199 91.936)),\n lime: to-rgb(oklch(0.841 0.238 128.85)),\n green: to-rgb(oklch(0.792 0.209 151.711)),\n emerald: to-rgb(oklch(0.765 0.177 163.223)),\n teal: to-rgb(oklch(0.777 0.152 181.912)),\n cyan: to-rgb(oklch(0.789 0.154 211.53)),\n sky: to-rgb(oklch(0.746 0.16 232.661)),\n blue: to-rgb(oklch(0.707 0.165 254.624)),\n indigo: to-rgb(oklch(0.673 0.182 276.935)),\n violet: to-rgb(oklch(0.702 0.183 293.541)),\n purple: to-rgb(oklch(0.714 0.203 305.504)),\n fuchsia: to-rgb(oklch(0.74 0.238 322.16)),\n pink: to-rgb(oklch(0.718 0.202 349.761)),\n rose: to-rgb(oklch(0.712 0.194 13.428)),\n slate: to-rgb(oklch(0.704 0.04 256.788)),\n gray: to-rgb(oklch(0.707 0.022 261.325)),\n zinc: to-rgb(oklch(0.705 0.015 286.067)),\n neutral: to-rgb(oklch(0.708 0 0)),\n stone: to-rgb(oklch(0.709 0.01 56.259)),\n);*/\nsd-sidebar {\n position: absolute;\n z-index: var(--z-index-sidebar);\n top: 0;\n left: 0;\n width: var(--sidebar-width);\n height: 100%;\n}\n@media not all and (max-width: 520px) {\n sd-sidebar {\n transition: transform var(--animation-duration) ease-out;\n }\n sd-sidebar[data-sd-toggle=true] {\n transform: translateX(-100%);\n transition: transform var(--animation-duration) ease-in;\n }\n}\n@media all and (max-width: 520px) {\n sd-sidebar {\n transition: transform var(--animation-duration) ease-in;\n transform: translateX(-100%);\n }\n sd-sidebar[data-sd-toggle=true] {\n transform: none;\n transition: transform var(--animation-duration) ease-out;\n box-shadow: 0 calc(16 * var(--elevation-size)) calc(16 * 4 * var(--elevation-size) * var(--elevation-blur-mult)) var(--trans-lighter), 0 var(--elevation-size) calc(var(--elevation-size) * var(--elevation-blur-mult)) var(--trans-lighter);\n }\n}"] }]
23
+ `, styles: ["/*@function to-rgb($oklch-color) {\n @return color.to-space($oklch-color, rgb);\n}*/\n/*$colors: (\n red: to-rgb(oklch(0.704 0.191 22.216)),\n orange: to-rgb(oklch(0.75 0.183 55.934)),\n amber: to-rgb(oklch(0.828 0.189 84.429)),\n yellow: to-rgb(oklch(0.852 0.199 91.936)),\n lime: to-rgb(oklch(0.841 0.238 128.85)),\n green: to-rgb(oklch(0.792 0.209 151.711)),\n emerald: to-rgb(oklch(0.765 0.177 163.223)),\n teal: to-rgb(oklch(0.777 0.152 181.912)),\n cyan: to-rgb(oklch(0.789 0.154 211.53)),\n sky: to-rgb(oklch(0.746 0.16 232.661)),\n blue: to-rgb(oklch(0.707 0.165 254.624)),\n indigo: to-rgb(oklch(0.673 0.182 276.935)),\n violet: to-rgb(oklch(0.702 0.183 293.541)),\n purple: to-rgb(oklch(0.714 0.203 305.504)),\n fuchsia: to-rgb(oklch(0.74 0.238 322.16)),\n pink: to-rgb(oklch(0.718 0.202 349.761)),\n rose: to-rgb(oklch(0.712 0.194 13.428)),\n slate: to-rgb(oklch(0.704 0.04 256.788)),\n gray: to-rgb(oklch(0.707 0.022 261.325)),\n zinc: to-rgb(oklch(0.705 0.015 286.067)),\n neutral: to-rgb(oklch(0.708 0 0)),\n stone: to-rgb(oklch(0.709 0.01 56.259)),\n);*/\nsd-sidebar {\n position: absolute;\n z-index: var(--z-index-sidebar);\n top: 0;\n left: 0;\n width: var(--sidebar-width);\n height: 100%;\n border-right: 1px solid var(--border-color-lighter);\n}\n@media not all and (max-width: 520px) {\n sd-sidebar {\n transition: transform var(--animation-duration) ease-out;\n }\n sd-sidebar[data-sd-toggle=true] {\n transform: translateX(-100%);\n transition: transform var(--animation-duration) ease-in;\n }\n}\n@media all and (max-width: 520px) {\n sd-sidebar {\n transition: transform var(--animation-duration) ease-in;\n transform: translateX(-100%);\n }\n sd-sidebar[data-sd-toggle=true] {\n transform: none;\n transition: transform var(--animation-duration) ease-out;\n box-shadow: 0 calc(16 * var(--elevation-size)) calc(16 * 4 * var(--elevation-size) * var(--elevation-blur-mult)) var(--trans-lighter), 0 var(--elevation-size) calc(var(--elevation-size) * var(--elevation-blur-mult)) var(--trans-lighter);\n }\n}"] }]
24
24
  }], null, null); })();
25
25
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SdSidebar, { className: "SdSidebar", filePath: "packages/angular/src/layout/sidebar/sd-sidebar.ts", lineNumber: 62 }); })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/angular",
3
- "version": "14.1.14",
3
+ "version": "14.1.17",
4
4
  "description": "심플리즘 패키지 - Angular",
5
5
  "author": "심플리즘",
6
6
  "license": "Apache-2.0",
@@ -32,39 +32,39 @@
32
32
  "./styles.css"
33
33
  ],
34
34
  "dependencies": {
35
- "@angular/common": "^22.0.4",
36
- "@angular/core": "^22.0.4",
37
- "@angular/platform-browser": "^22.0.4",
38
- "@angular/router": "^22.0.4",
39
- "@angular/service-worker": "^22.0.4",
40
- "@ng-icons/core": "^33.3.0",
41
- "@ng-icons/tabler-icons": "^33.3.0",
42
- "@tiptap/core": "^3.27.1",
43
- "@tiptap/extension-color": "^3.27.1",
44
- "@tiptap/extension-document": "^3.27.1",
45
- "@tiptap/extension-highlight": "^3.27.1",
46
- "@tiptap/extension-image": "^3.27.1",
47
- "@tiptap/extension-paragraph": "^3.27.1",
48
- "@tiptap/extension-placeholder": "^3.27.1",
49
- "@tiptap/extension-text": "^3.27.1",
50
- "@tiptap/extension-text-align": "^3.27.1",
51
- "@tiptap/extension-text-style": "^3.27.1",
52
- "@tiptap/extension-underline": "^3.27.1",
53
- "@tiptap/markdown": "^3.27.1",
54
- "@tiptap/starter-kit": "^3.27.1",
55
- "bwip-js": "^4.11.1",
35
+ "@angular/common": "^22.0.6",
36
+ "@angular/core": "^22.0.6",
37
+ "@angular/platform-browser": "^22.0.6",
38
+ "@angular/router": "^22.0.6",
39
+ "@angular/service-worker": "^22.0.6",
40
+ "@ng-icons/core": "^33.4.0",
41
+ "@ng-icons/tabler-icons": "^33.4.0",
42
+ "@tiptap/core": "^3.27.4",
43
+ "@tiptap/extension-color": "^3.27.4",
44
+ "@tiptap/extension-document": "^3.27.4",
45
+ "@tiptap/extension-highlight": "^3.27.4",
46
+ "@tiptap/extension-image": "^3.27.4",
47
+ "@tiptap/extension-paragraph": "^3.27.4",
48
+ "@tiptap/extension-placeholder": "^3.27.4",
49
+ "@tiptap/extension-text": "^3.27.4",
50
+ "@tiptap/extension-text-align": "^3.27.4",
51
+ "@tiptap/extension-text-style": "^3.27.4",
52
+ "@tiptap/extension-underline": "^3.27.4",
53
+ "@tiptap/markdown": "^3.27.4",
54
+ "@tiptap/starter-kit": "^3.27.4",
55
+ "bwip-js": "^4.11.2",
56
56
  "echarts": "^6.1.0",
57
57
  "html-to-image": "^1.11.13",
58
58
  "jspdf": "^4.2.1",
59
59
  "rxjs": "^7.8.2",
60
60
  "tabbable": "^6.5.0",
61
- "@simplysm/service-client": "14.1.14",
62
- "@simplysm/core-browser": "14.1.14",
63
- "@simplysm/service-common": "14.1.14",
64
- "@simplysm/core-common": "14.1.14"
61
+ "@simplysm/core-browser": "14.1.17",
62
+ "@simplysm/service-common": "14.1.17",
63
+ "@simplysm/core-common": "14.1.17",
64
+ "@simplysm/service-client": "14.1.17"
65
65
  },
66
66
  "devDependencies": {
67
- "@angular/compiler": "^22.0.4"
67
+ "@angular/compiler": "^22.0.6"
68
68
  },
69
69
  "scripts": {}
70
70
  }
@@ -368,6 +368,10 @@ export class SdTextfield<K extends keyof SdTextfieldTypes> {
368
368
  const inputEl = this._inputElRef()?.nativeElement;
369
369
  if (inputEl == null) return;
370
370
 
371
+ // IME 조합 중에는 DOM 을 되쓰지 않는다. 되쓰면 진행 중 조합이 깨진다.
372
+ // 조합이 끝나면 onCompositionEnd → value.set 이 controlValue 를 바꿔 effect 가 다시 돌아 최종값을 반영한다.
373
+ if (this._composing) return;
374
+
371
375
  // 편집(포커스) 중이라도 변경 origin 을 구분한다.
372
376
  // 사용자 입력이 만든 DOM(정규화 차이·진행 중 입력 포함)은 보호하고,
373
377
  // 모델만 외부에서 바뀐 경우(프로그래밍적 리셋·prefill·표시옵션 변경)는 되써서 반영한다.
@@ -437,7 +441,8 @@ export class SdTextfield<K extends keyof SdTextfieldTypes> {
437
441
 
438
442
  onInput(event: Event): void {
439
443
  // 조합 중 input 은 무시하고, 완성 시 onCompositionEnd 에서 한 번만 반영
440
- if (this._composing) return;
444
+ // isComposing 은 compositionstart 가 늦거나 누락된 IME 에서도 브라우저가 조합 구간 input 에 직접 실어주는 신호
445
+ if ((event as InputEvent).isComposing || this._composing) return;
441
446
  this._applyInput(event.target as HTMLInputElement);
442
447
  }
443
448
 
@@ -461,6 +466,8 @@ export class SdTextfield<K extends keyof SdTextfieldTypes> {
461
466
  onBlur(event: FocusEvent): void {
462
467
  // 편집 종료 시 모델 기준값으로 동기화 (number 콤마 포맷 반영, date 미완성 입력 정리)
463
468
  // date 미완성 입력은 input.value 가 "" 라 비교 없이 무조건 되써야 남은 세그먼트가 정리됨
469
+ // compositionend 가 스킵된 채 blur 되면 _composing 이 true 로 고착되므로 여기서 리셋한다.
470
+ this._composing = false;
464
471
  const inputEl = event.target as HTMLInputElement;
465
472
  inputEl.value = this.controlValue();
466
473
  this._syncNativeValidity(inputEl);
@@ -1,81 +1,81 @@
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 class="flex-row gap-sm cross-align-center">
58
- <span>블루프린트</span>
59
- <sd-switch [(value)]="_sdTheme.blueprint" />
60
- </div>
61
- </div>
62
- </sd-dropdown-popup>
63
- </sd-dropdown>
64
- `,
65
- styles: [],
66
- })
67
- export class SdThemeSelector {
68
- protected readonly _sdTheme = inject(SdThemeProvider);
69
-
70
- isMinFontSize = computed(() => this._sdTheme.fontSize() <= this._sdTheme.fontSizePresets[0]);
71
-
72
- isMaxFontSize = computed(
73
- () =>
74
- this._sdTheme.fontSize() >=
75
- this._sdTheme.fontSizePresets[this._sdTheme.fontSizePresets.length - 1],
76
- );
77
-
78
- protected readonly tablerPlus = tablerPlus;
79
- protected readonly tablerMinus = tablerMinus;
80
- protected readonly tablerPalette = tablerPalette;
81
- }
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 class="flex-row gap-sm cross-align-center">
58
+ <span>블루프린트</span>
59
+ <sd-switch [(value)]="_sdTheme.blueprint" />
60
+ </div>
61
+ </div>
62
+ </sd-dropdown-popup>
63
+ </sd-dropdown>
64
+ `,
65
+ styles: [],
66
+ })
67
+ export class SdThemeSelector {
68
+ protected readonly _sdTheme = inject(SdThemeProvider);
69
+
70
+ isMinFontSize = computed(() => this._sdTheme.fontSize() <= this._sdTheme.fontSizePresets[0]);
71
+
72
+ isMaxFontSize = computed(
73
+ () =>
74
+ this._sdTheme.fontSize() >=
75
+ this._sdTheme.fontSizePresets[this._sdTheme.fontSizePresets.length - 1],
76
+ );
77
+
78
+ protected readonly tablerPlus = tablerPlus;
79
+ protected readonly tablerMinus = tablerMinus;
80
+ protected readonly tablerPalette = tablerPalette;
81
+ }
@@ -34,7 +34,7 @@ import { SdSidebarContainer } from "./sd-sidebar-container";
34
34
  height: 100%;
35
35
  //background: var(--control-color);
36
36
  //background: var(--theme-gray-lightest);
37
- //border-right: 1px solid var(--border-color-lighter);
37
+ border-right: 1px solid var(--border-color-lighter);
38
38
 
39
39
  @media not all and (max-width: variables.$breakpoint-mobile) {
40
40
  transition: transform var(--animation-duration) ease-out;