@simplysm/angular 14.0.100 → 14.0.101

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 (93) hide show
  1. package/dist/controls/button/sd-additional-button.js +2 -2
  2. package/dist/controls/button/sd-anchor.js +2 -2
  3. package/dist/controls/button/sd-button.js +2 -2
  4. package/dist/controls/button/sd-modal-select-button.js +2 -2
  5. package/dist/controls/checkbox/sd-checkbox.d.ts.map +1 -1
  6. package/dist/controls/checkbox/sd-checkbox.js +3 -3
  7. package/dist/controls/checkbox/sd-switch.js +2 -2
  8. package/dist/controls/collapse/sd-collapse-icon.d.ts +1 -1
  9. package/dist/controls/collapse/sd-collapse-icon.d.ts.map +1 -1
  10. package/dist/controls/collapse/sd-collapse-icon.js +3 -1
  11. package/dist/controls/collapse/sd-collapse.d.ts +1 -1
  12. package/dist/controls/collapse/sd-collapse.d.ts.map +1 -1
  13. package/dist/controls/collapse/sd-collapse.js +3 -1
  14. package/dist/controls/dropdown/sd-dropdown-popup.js +2 -2
  15. package/dist/controls/gap/sd-gap.js +2 -2
  16. package/dist/controls/input/sd-date-range-picker.js +2 -2
  17. package/dist/controls/input/sd-range.js +2 -2
  18. package/dist/controls/input/sd-textarea.d.ts.map +1 -1
  19. package/dist/controls/input/sd-textarea.js +3 -3
  20. package/dist/controls/input/sd-textfield.d.ts +2 -0
  21. package/dist/controls/input/sd-textfield.d.ts.map +1 -1
  22. package/dist/controls/input/sd-textfield.js +44 -16
  23. package/dist/controls/list/sd-list-item.js +2 -2
  24. package/dist/controls/select/sd-select-button.js +2 -2
  25. package/dist/controls/select/sd-select-item.d.ts.map +1 -1
  26. package/dist/controls/select/sd-select-item.js +3 -3
  27. package/dist/controls/select/sd-select.d.ts.map +1 -1
  28. package/dist/controls/select/sd-select.js +3 -3
  29. package/dist/core/busy/sd-busy-container.js +2 -2
  30. package/dist/core/directive-input-signals.d.ts +0 -9
  31. package/dist/core/directive-input-signals.d.ts.map +1 -1
  32. package/dist/core/modal/sd-modal.js +2 -2
  33. package/dist/core/provideSdAngular.d.ts.map +1 -1
  34. package/dist/core/provideSdAngular.js +12 -0
  35. package/dist/core/ripple/setupRipple.js +1 -1
  36. package/dist/core/toast/sd-toast-container.js +2 -2
  37. package/dist/core/toast/sd-toast.js +2 -2
  38. package/dist/data/crud/sd-base-container.js +4 -4
  39. package/dist/data/kanban/sd-kanban-board.js +2 -2
  40. package/dist/data/kanban/sd-kanban-lane.js +2 -2
  41. package/dist/data/kanban/sd-kanban.js +2 -2
  42. package/dist/data/sheet/sd-sheet.d.ts.map +1 -1
  43. package/dist/data/sheet/sd-sheet.js +3 -3
  44. package/dist/features/editor/sd-tiptap-editor.d.ts.map +1 -1
  45. package/dist/features/editor/sd-tiptap-editor.js +3 -3
  46. package/dist/features/theme/sd-theme-provider.d.ts +1 -0
  47. package/dist/features/theme/sd-theme-provider.d.ts.map +1 -1
  48. package/dist/features/theme/sd-theme-provider.js +5 -0
  49. package/dist/features/theme/sd-theme-selector.d.ts.map +1 -1
  50. package/dist/features/theme/sd-theme-selector.js +14 -2
  51. package/dist/features/visual/sd-calendar.js +2 -2
  52. package/dist/features/visual/sd-label.js +2 -2
  53. package/dist/features/visual/sd-note.js +2 -2
  54. package/dist/features/visual/sd-progress.js +2 -2
  55. package/dist/layout/sidebar/sd-sidebar-container.js +2 -2
  56. package/dist/layout/sidebar/sd-sidebar.js +2 -2
  57. package/dist/layout/topbar/sd-topbar.js +2 -2
  58. package/package.json +5 -5
  59. package/scss/commons/_colors.scss +326 -0
  60. package/scss/commons/_mixins.scss +129 -129
  61. package/scss/commons/_theme-variables.scss +8 -1
  62. package/scss/commons/_variables.scss +37 -33
  63. package/scss/controls/_card.scss +1 -1
  64. package/scss/styles.scss +3 -0
  65. package/scss/themes/_blueprint-surfaces.scss +81 -0
  66. package/scss/themes/_variables-blueprint.scss +95 -0
  67. package/scss/themes/_variables-dark.scss +9 -22
  68. package/src/controls/button/sd-button.ts +2 -2
  69. package/src/controls/checkbox/sd-checkbox.ts +13 -11
  70. package/src/controls/collapse/sd-collapse-icon.ts +3 -1
  71. package/src/controls/collapse/sd-collapse.ts +3 -1
  72. package/src/controls/dropdown/sd-dropdown-popup.ts +2 -2
  73. package/src/controls/input/sd-textarea.ts +5 -0
  74. package/src/controls/input/sd-textfield.ts +40 -4
  75. package/src/controls/list/sd-list-item.ts +5 -5
  76. package/src/controls/select/sd-select-button.ts +1 -1
  77. package/src/controls/select/sd-select-item.ts +4 -3
  78. package/src/controls/select/sd-select.ts +2 -1
  79. package/src/core/busy/sd-busy-container.ts +3 -3
  80. package/src/core/directive-input-signals.ts +0 -9
  81. package/src/core/provideSdAngular.ts +14 -0
  82. package/src/core/ripple/setupRipple.ts +1 -1
  83. package/src/data/crud/sd-base-container.ts +3 -3
  84. package/src/data/kanban/sd-kanban-lane.ts +1 -1
  85. package/src/data/kanban/sd-kanban.ts +1 -1
  86. package/src/data/sheet/sd-sheet.ts +4 -3
  87. package/src/features/editor/sd-tiptap-editor.ts +1 -0
  88. package/src/features/theme/sd-theme-provider.ts +7 -0
  89. package/src/features/theme/sd-theme-selector.ts +4 -0
  90. package/src/layout/sidebar/sd-sidebar-container.ts +3 -3
  91. package/src/layout/sidebar/sd-sidebar.ts +5 -5
  92. package/src/layout/topbar/sd-topbar.ts +1 -1
  93. package/styles.css +481 -103
@@ -1,11 +1,12 @@
1
1
  @use "sass:map";
2
2
  @use "sass:color";
3
+ @use "./colors";
3
4
 
4
- @function to-rgb($oklch-color) {
5
+ /*@function to-rgb($oklch-color) {
5
6
  @return color.to-space($oklch-color, rgb);
6
- }
7
+ }*/
7
8
 
8
- $colors: (
9
+ /*$colors: (
9
10
  red: to-rgb(oklch(0.704 0.191 22.216)),
10
11
  orange: to-rgb(oklch(0.75 0.183 55.934)),
11
12
  amber: to-rgb(oklch(0.828 0.189 84.429)),
@@ -28,21 +29,21 @@ $colors: (
28
29
  zinc: to-rgb(oklch(0.705 0.015 286.067)),
29
30
  neutral: to-rgb(oklch(0.708 0 0)),
30
31
  stone: to-rgb(oklch(0.709 0.01 56.259)),
31
- );
32
+ );*/
32
33
 
33
34
  // D6: lightest~darkest가 실제 밝기와 일치하도록 수정
34
35
  // lightest(+90%) > lighter(+75%) > light(+60%) > default > dark(-10%) > darker(-25%) > darkest(-40%)
35
- @function color-map($base, $offset: 0%) {
36
- @return (
37
- lightest: color.scale($base, $lightness: 90% + $offset),
38
- lighter: color.scale($base, $lightness: 75% + $offset),
39
- light: color.scale($base, $lightness: 60% + $offset),
40
- default: $base,
41
- dark: color.scale($base, $lightness: -10% + $offset),
42
- darker: color.scale($base, $lightness: -25% + $offset),
43
- darkest: color.scale($base, $lightness: -40% + $offset)
44
- );
45
- }
36
+ //@function color-map($base, $offset: 0%) {
37
+ // @return (
38
+ // lightest: color.scale($base, $lightness: 90% + $offset),
39
+ // lighter: color.scale($base, $lightness: 75% + $offset),
40
+ // light: color.scale($base, $lightness: 60% + $offset),
41
+ // default: $base,
42
+ // dark: color.scale($base, $lightness: -10% + $offset),
43
+ // darker: color.scale($base, $lightness: -25% + $offset),
44
+ // darkest: color.scale($base, $lightness: -40% + $offset)
45
+ // );
46
+ //}
46
47
 
47
48
  // Breakpoints for media queries (CSS custom properties cannot be used in media queries)
48
49
  $breakpoint-mobile: 520px;
@@ -52,14 +53,14 @@ $breakpoint-sm: 1280px;
52
53
 
53
54
  $vars: (
54
55
  theme: (
55
- "gray": color-map(map.get($colors, gray)),
56
- blue-gray: color-map(map.get($colors, slate)),
57
- primary: color-map(map.get($colors, blue)),
58
- secondary: color-map(map.get($colors, blue)),
59
- info: color-map(map.get($colors, cyan)),
60
- success: color-map(map.get($colors, lime)),
61
- warning: color-map(map.get($colors, orange)),
62
- danger: color-map(map.get($colors, red)),
56
+ "gray": colors.variants(colors.get(zinc, 400)),
57
+ blue-gray: colors.variants(colors.get(slate, 400)),
58
+ primary: colors.variants(colors.get(blue, 400)),
59
+ secondary: colors.variants(colors.get(blue, 400)),
60
+ info: colors.variants(colors.get(cyan, 400)),
61
+ success: colors.variants(colors.get(lime, 400)),
62
+ warning: colors.variants(colors.get(orange, 400)),
63
+ danger: colors.variants(colors.get(red, 400)),
63
64
  ),
64
65
  trans: (
65
66
  darkest: rgba(0, 0, 0, 0.5),
@@ -106,14 +107,14 @@ $vars: (
106
107
  0: 0,
107
108
  auto: "auto",
108
109
  ),
109
- border-color: color-map(map.get($colors, gray), 5%),
110
+ border-color: colors.variants(colors.get(zinc, 400)),
110
111
  border-radius: (
111
- xs: var(--gap-xs),
112
- sm: var(--gap-sm),
113
- default: var(--gap-default),
114
- lg: var(--gap-lg),
115
- xl: var(--gap-xl),
116
- xxl: var(--gap-xxl),
112
+ xs: var(--gap-xxs),
113
+ sm: var(--gap-xs),
114
+ default: var(--gap-sm),
115
+ lg: var(--gap-default),
116
+ xl: var(--gap-lg),
117
+ xxl: var(--gap-xl),
117
118
  ),
118
119
  z-index: (
119
120
  toast: 9999,
@@ -124,14 +125,17 @@ $vars: (
124
125
  ),
125
126
  line-height: 1.5em,
126
127
  line-height-strip-unit: 1.5,
127
- font-family: sans-serif,
128
- font-family-monospace: monospace,
129
- background-color: white,
128
+ font-family: "sans-serif",
129
+ font-family-field: "ui-sans-serif, system-ui, sans-serif",
130
+ font-family-monospace: "ui-monospace, monospace",
131
+ background-color: var(--theme-gray-lightest),
130
132
  background-rev-color: black,
131
133
  control-color: white,
132
134
  busy-overlay-bg: rgba(255, 255, 255, 0.6),
133
135
  animation-duration: 0.2s,
134
136
  elevation-size: 0.0833rem,
137
+ // elevation 그림자 blur 배수 (기본 1 = 현재 동작 유지). 테마에서 0으로 덮으면 하드 섀도.
138
+ elevation-blur-mult: 1,
135
139
  sidebar: (
136
140
  width: 14rem,
137
141
  ),
@@ -4,7 +4,7 @@
4
4
  display: block;
5
5
  background: var(--control-color);
6
6
  border-radius: var(--border-radius-default);
7
- transition: box-shadow 0.3s ease-in-out;
7
+ transition: box-shadow var(--animation-duration) ease-in-out;
8
8
  @include mixins.elevation(2);
9
9
  animation: sd-card var(--animation-duration) ease-out;
10
10
  opacity: 0;
package/scss/styles.scss CHANGED
@@ -1,6 +1,9 @@
1
1
  @use "commons/theme-variables";
2
2
  @use "commons/styles";
3
3
 
4
+ // 블루프린트 모눈 그리드 면 (언레이어드 — 파일 내 주석 참조)
5
+ @use "themes/blueprint-surfaces";
6
+
4
7
  @use "controls/flex";
5
8
  @use "controls/grid";
6
9
  @use "controls/card";
@@ -0,0 +1,81 @@
1
+ //
2
+ // 블루프린트 모눈 그리드 면 — body(앱 배경)와 chrome(사이드바·탑바)에만 적용.
3
+ // 콘텐츠(카드·시트·폼·드롭다운·모달) 내부는 무지(가독 우선) — 브랜드 패턴과 동일.
4
+ //
5
+ // ⚠ 언레이어드(@layer 밖)로 둔다. 면 배경은 컴포넌트 스타일(언레이어드)이
6
+ // `background: var(--theme-gray-lightest)` 같은 단축으로 background-image 를 none 으로
7
+ // 리셋하므로, 같은(언레이어드) 우선순위에서 더 높은 명시도의 자손 셀렉터로 background-image
8
+ // 만 다시 얹어야 그리드가 살아남는다. background-color 는 컴포넌트 단축이 그대로 유지한다.
9
+ //
10
+
11
+ // 모눈: 24px 헤어라인 + 120px 메이저
12
+ @mixin grid-image($strong, $weak) {
13
+ background-image:
14
+ linear-gradient(#{$strong} 1px, transparent 1px),
15
+ linear-gradient(90deg, #{$strong} 1px, transparent 1px),
16
+ linear-gradient(#{$weak} 1px, transparent 1px),
17
+ linear-gradient(90deg, #{$weak} 1px, transparent 1px);
18
+ background-size:
19
+ 120px 120px,
20
+ 120px 120px,
21
+ 24px 24px,
22
+ 24px 24px;
23
+ }
24
+
25
+ body.sd-theme-blueprint,
26
+ .sd-theme-blueprint sd-sheet > ._sheet-container {
27
+ @include grid-image(rgba(28, 62, 156, 0.055), rgba(28, 62, 156, 0.022));
28
+ }
29
+
30
+ .sd-theme-blueprint sd-sheet > ._sheet-container > table {
31
+ box-shadow: 1px 1px 0 rgba(28, 62, 156, 0.1);
32
+ }
33
+
34
+ .sd-theme-blueprint .card {
35
+ border: 1px solid var(--border-color-default);
36
+ box-shadow: 3px 3px 0 rgba(28, 62, 156, 0.1);
37
+
38
+ &:hover,
39
+ &:focus-within {
40
+ box-shadow: 5px 5px 0 rgba(28, 62, 156, 0.14);
41
+ }
42
+ }
43
+
44
+ .sd-theme-blueprint sd-permission-table table > * > tr > * {
45
+ border-bottom: 1px solid var(--border-color-lighter);
46
+ }
47
+
48
+ .sd-theme-blueprint sd-permission-table table > * > tr[data-sd-theme="first"] > *._before,
49
+ .sd-theme-blueprint sd-permission-table table > * > tr[data-sd-theme="first"] > *._title,
50
+ .sd-theme-blueprint sd-permission-table table > * > tr[data-sd-theme="first"] > *._after {
51
+ background: var(--trans-lighter);
52
+ border-top: 1px solid var(--border-color-default);
53
+ border-bottom: 1px solid var(--border-color-default);
54
+ color: var(--text-trans-default);
55
+ font-weight: 700;
56
+
57
+ > * {
58
+ color: var(--text-trans-default) !important;
59
+ }
60
+ }
61
+
62
+ // 하위 depth 틴트(info/warning/success lightest) 제거 → 무지, 행 헤어라인으로만 구분
63
+ .sd-theme-blueprint sd-permission-table table > * > tr[data-sd-theme="info"] > *._title,
64
+ .sd-theme-blueprint sd-permission-table table > * > tr[data-sd-theme="info"] > *._after,
65
+ .sd-theme-blueprint sd-permission-table table > * > tr[data-sd-theme="warning"] > *._title,
66
+ .sd-theme-blueprint sd-permission-table table > * > tr[data-sd-theme="warning"] > *._after,
67
+ .sd-theme-blueprint sd-permission-table table > * > tr[data-sd-theme="success"] > *._title,
68
+ .sd-theme-blueprint sd-permission-table table > * > tr[data-sd-theme="success"] > *._after {
69
+ background: transparent;
70
+ }
71
+
72
+ .sd-theme-blueprint {
73
+ sd-modal > ._dialog > ._header {
74
+ background: var(--theme-primary-default);
75
+ color: var(--text-trans-rev-default);
76
+ }
77
+
78
+ sd-crud-detail > sd-base-container > sd-busy-container > .bg-control > .main-align-end {
79
+ background: var(--theme-gray-lightest);
80
+ }
81
+ }
@@ -0,0 +1,95 @@
1
+ @use "sass:map";
2
+ @use "sass:color";
3
+ @use "../commons/colors";
4
+
5
+ $paper: (
6
+ theme: (
7
+ "gray": (
8
+ lightest: colors.get(stone, 50),
9
+ lighter: colors.get(stone, 100),
10
+ light: colors.get(stone, 300),
11
+ default: colors.get(stone, 500),
12
+ dark: colors.get(stone, 600),
13
+ darker: colors.get(stone, 700),
14
+ darkest: colors.get(stone, 800)
15
+ ),
16
+ blue-gray: (
17
+ lightest: colors.get(slate, 50),
18
+ lighter: colors.get(slate, 100),
19
+ light: colors.get(slate, 300),
20
+ default: colors.get(slate, 500),
21
+ dark: colors.get(slate, 600),
22
+ darker: colors.get(slate, 700),
23
+ darkest: colors.get(slate, 800)
24
+ ),
25
+ primary: (
26
+ lightest: colors.get(blue, 100),
27
+ lighter: colors.get(blue, 300),
28
+ light: colors.get(blue, 500),
29
+ default: colors.get(blue, 900),
30
+ dark: colors.get(blue, 950),
31
+ darker: colors.get(blue, 950),
32
+ darkest: colors.get(blue, 950)
33
+ ),
34
+ secondary: (
35
+ lightest: colors.get(blue, 50),
36
+ lighter: colors.get(blue, 100),
37
+ light: colors.get(blue, 300),
38
+ default: colors.get(blue, 500),
39
+ dark: colors.get(blue, 600),
40
+ darker: colors.get(blue, 700),
41
+ darkest: colors.get(blue, 800)
42
+ ),
43
+ info: (
44
+ lightest: colors.get(cyan, 50),
45
+ lighter: colors.get(cyan, 100),
46
+ light: colors.get(cyan, 300),
47
+ default: colors.get(cyan, 500),
48
+ dark: colors.get(cyan, 600),
49
+ darker: colors.get(cyan, 700),
50
+ darkest: colors.get(cyan, 800)
51
+ ),
52
+ success: (
53
+ lightest: colors.get(green, 50),
54
+ lighter: colors.get(green, 100),
55
+ light: colors.get(green, 300),
56
+ default: colors.get(green, 500),
57
+ dark: colors.get(green, 600),
58
+ darker: colors.get(green, 700),
59
+ darkest: colors.get(green, 800)
60
+ ),
61
+ warning: (
62
+ lightest: colors.get(orange, 50),
63
+ lighter: colors.get(orange, 100),
64
+ light: colors.get(orange, 200),
65
+ default: colors.get(orange, 400),
66
+ dark: colors.get(orange, 600),
67
+ darker: colors.get(orange, 700),
68
+ darkest: colors.get(orange, 800)
69
+ ),
70
+ danger: (
71
+ lightest: colors.get(red, 50),
72
+ lighter: colors.get(red, 100),
73
+ light: colors.get(red, 200),
74
+ default: colors.get(red, 400),
75
+ dark: colors.get(red, 600),
76
+ darker: colors.get(red, 700),
77
+ darkest: colors.get(red, 800)
78
+ )
79
+ ),
80
+ background-color: var(--theme-gray-lightest),
81
+ control-color: white,
82
+ border-radius: (
83
+ xs: 0,
84
+ sm: 0,
85
+ default: 0,
86
+ lg: 0,
87
+ xl: 0,
88
+ xxl: 0,
89
+ ),
90
+ elevation-blur-mult: 0,
91
+ sheet: (
92
+ bg: var(--theme-gray-lightest),
93
+ ),
94
+ border-color: colors.variants(colors.get(zinc, 500)),
95
+ );
@@ -1,30 +1,17 @@
1
1
  @use "sass:map";
2
2
  @use "sass:color";
3
-
4
- @use "../commons/variables";
5
-
6
- @function color-map($base) {
7
- @return (
8
- darkest: color.mix(white, $base, 80%),
9
- darker: color.mix(white, $base, 60%),
10
- dark: color.mix(white, $base, 40%),
11
- default: color.mix(black, $base, 20%),
12
- light: color.mix(black, $base, 55%),
13
- lighter: color.mix(black, $base, 70%),
14
- lightest: color.mix(black, $base, 80%)
15
- );
16
- }
3
+ @use "../commons/colors";
17
4
 
18
5
  $vars: (
19
6
  theme: (
20
- "gray": color-map(map.get(variables.$colors, gray)),
21
- blue-gray: color-map(map.get(variables.$colors, slate)),
22
- primary: color-map(map.get(variables.$colors, blue)),
23
- secondary: color-map(map.get(variables.$colors, blue)),
24
- info: color-map(map.get(variables.$colors, cyan)),
25
- success: color-map(map.get(variables.$colors, lime)),
26
- warning: color-map(map.get(variables.$colors, orange)),
27
- danger: color-map(map.get(variables.$colors, red)),
7
+ "gray": colors.variants-dark(colors.get(gray)),
8
+ blue-gray: colors.variants-dark(colors.get(slate)),
9
+ primary: colors.variants-dark(colors.get(blue)),
10
+ secondary: colors.variants-dark(colors.get(blue)),
11
+ info: colors.variants-dark(colors.get(cyan)),
12
+ success: colors.variants-dark(colors.get(lime)),
13
+ warning: colors.variants-dark(colors.get(orange)),
14
+ danger: colors.variants-dark(colors.get(red)),
28
15
  ),
29
16
  trans: (
30
17
  darkest: rgba(255, 255, 255, 0.5),
@@ -40,14 +40,14 @@ import { SdRipple } from "../../core/ripple/sd-ripple";
40
40
  width: 100%;
41
41
 
42
42
  background: var(--control-color);
43
- border-color: var(--border-color-light);
43
+ border-color: var(--theme-primary-default);
44
44
  border-radius: var(--border-radius-default);
45
45
 
46
46
  font-weight: bold;
47
47
  text-align: center;
48
48
  cursor: pointer;
49
49
 
50
- transition: 0.1s linear;
50
+ transition: var(--animation-duration) linear;
51
51
  transition-property: border, background;
52
52
 
53
53
  &:hover {
@@ -62,7 +62,7 @@ import { tablerCheck } from "@ng-icons/tabler-icons";
62
62
 
63
63
  width: calc(var(--font-size-default) + 2px);
64
64
  height: calc(var(--font-size-default) + 2px);
65
- border: 1px solid var(--trans-light);
65
+ border: 1px solid var(--border-color-light);
66
66
  background: var(--theme-secondary-lightest);
67
67
 
68
68
  > ._indicator {
@@ -114,14 +114,9 @@ import { tablerCheck } from "@ng-icons/tabler-icons";
114
114
  }
115
115
  }
116
116
 
117
- &:focus {
118
- > ._indicator_rect {
119
- border-color: var(--theme-#{$key}-default);
120
- }
121
- }
122
-
123
117
  &[data-sd-checked="true"] {
124
118
  > ._indicator_rect {
119
+ border-color: var(--theme-#{$key}-default);
125
120
  background: var(--theme-#{$key}-default);
126
121
 
127
122
  > ._indicator {
@@ -129,6 +124,12 @@ import { tablerCheck } from "@ng-icons/tabler-icons";
129
124
  }
130
125
  }
131
126
  }
127
+
128
+ &:focus {
129
+ > ._indicator_rect {
130
+ border-color: var(--theme-#{$key}-dark);
131
+ }
132
+ }
132
133
  }
133
134
  }
134
135
 
@@ -138,15 +139,16 @@ import { tablerCheck } from "@ng-icons/tabler-icons";
138
139
  border-color: var(--text-trans-lightest);
139
140
  }
140
141
 
141
- &:focus {
142
+ &[data-sd-checked="true"] {
142
143
  > ._indicator_rect {
143
- border-color: var(--text-trans-default);
144
+ border-color: var(--theme-primary-default);
145
+ background: var(--theme-primary-default);
144
146
  }
145
147
  }
146
148
 
147
- &[data-sd-checked="true"] {
149
+ &:focus {
148
150
  > ._indicator_rect {
149
- background: var(--theme-primary-default);
151
+ border-color: var(--theme-primary-dark);
150
152
  }
151
153
  }
152
154
  }
@@ -45,6 +45,8 @@ export class SdCollapseIcon {
45
45
  });
46
46
 
47
47
  transitionStyle = computed(() => {
48
- return this.open() ? "transform 0.1s ease-out" : "transform 0.1s ease-in";
48
+ return this.open()
49
+ ? "transform var(--animation-duration) ease-out"
50
+ : "transform var(--animation-duration) ease-in";
49
51
  });
50
52
  }
@@ -54,7 +54,9 @@ export class SdCollapse {
54
54
 
55
55
  contentTransition = computed(() => {
56
56
  if (!this._initialized()) return "";
57
- return this.open() ? "margin-top 0.1s ease-out" : "margin-top 0.1s ease-in";
57
+ return this.open()
58
+ ? "margin-top var(--animation-duration) ease-out"
59
+ : "margin-top var(--animation-duration) ease-in";
58
60
  });
59
61
 
60
62
  constructor() {
@@ -33,7 +33,7 @@ import { SdResizeDirective } from "../../core/events/sd-resize";
33
33
  z-index: var(--z-index-dropdown);
34
34
  opacity: 0;
35
35
  transform: translateY(-0.625rem);
36
- transition: 0.1s linear;
36
+ transition: var(--animation-duration) linear;
37
37
  transition-property: transform, opacity;
38
38
  pointer-events: none;
39
39
  background: var(--control-color);
@@ -70,7 +70,7 @@ import { SdResizeDirective } from "../../core/events/sd-resize";
70
70
  opacity: 1;
71
71
  pointer-events: auto;
72
72
  transform: none;
73
- animation: sd-dropdown-slide-up 0.2s ease-out;
73
+ animation: sd-dropdown-slide-up var(--animation-duration) ease-out;
74
74
  @include mixins.elevation(8);
75
75
  }
76
76
  }
@@ -56,6 +56,7 @@ import { setupInvalid } from "../../core/validation/setupInvalid";
56
56
  > textarea,
57
57
  > ._contents {
58
58
  @include mixins.form-control-base();
59
+ font-family: var(--font-family-field);
59
60
  resize: none;
60
61
 
61
62
  overflow: auto;
@@ -79,6 +80,10 @@ import { setupInvalid } from "../../core/validation/setupInvalid";
79
80
  }
80
81
  }
81
82
 
83
+ > ._contents > pre {
84
+ font-family: inherit;
85
+ }
86
+
82
87
  &:not([data-sd-inset="true"]):not([data-sd-disabled="true"]) > ._contents {
83
88
  height: 0;
84
89
  max-height: 0;
@@ -1,10 +1,16 @@
1
+ import { isPlatformBrowser } from "@angular/common";
1
2
  import {
2
3
  booleanAttribute,
3
4
  ChangeDetectionStrategy,
4
5
  Component,
5
6
  computed,
7
+ effect,
8
+ ElementRef,
9
+ inject,
6
10
  input,
7
11
  model,
12
+ PLATFORM_ID,
13
+ viewChild,
8
14
  ViewEncapsulation,
9
15
  } from "@angular/core";
10
16
  import { setupInvalid } from "../../core/validation/setupInvalid";
@@ -40,6 +46,7 @@ import {
40
46
  </div>
41
47
  @if (!readonly() && !disabled()) {
42
48
  <input
49
+ #inputEl
43
50
  [style]="inputStyle()"
44
51
  [class]="inputClass()"
45
52
  [attr.title]="title() ?? placeholder()"
@@ -48,11 +55,11 @@ import {
48
55
  [attr.max]="max()"
49
56
  [type]="controlType()"
50
57
  [attr.inputmode]="type() === 'number' ? 'numeric' : undefined"
51
- [value]="controlValue()"
52
58
  [attr.autocomplete]="autocomplete()"
53
59
  [attr.step]="controlStep()"
54
60
  (input)="onInput($event)"
55
61
  (paste)="onInputPaste($event)"
62
+ (blur)="onBlur($event)"
56
63
  />
57
64
  }
58
65
  `,
@@ -70,17 +77,18 @@ import {
70
77
  > input,
71
78
  > ._contents {
72
79
  @include mixins.form-control-base();
80
+ font-family: var(--font-family-field);
73
81
 
74
82
  overflow: auto;
75
83
  width: 100%;
76
84
 
77
- border: 1px solid var(--trans-lighter);
85
+ border: 1px solid var(--border-color-light);
78
86
  border-radius: var(--border-radius-default);
79
87
  background: var(--theme-secondary-lightest);
80
88
 
81
89
  &:focus {
82
90
  outline: none;
83
- border-color: var(--theme-secondary-default);
91
+ border-color: var(--theme-primary-default);
84
92
  }
85
93
 
86
94
  &[type="date"],
@@ -114,6 +122,10 @@ import {
114
122
  display: none;
115
123
  }
116
124
 
125
+ > ._contents > pre {
126
+ font-family: inherit;
127
+ }
128
+
117
129
  &[data-sd-type="number"] {
118
130
  > input,
119
131
  > ._contents {
@@ -253,7 +265,7 @@ import {
253
265
  &[data-sd-disabled="true"] {
254
266
  > ._contents {
255
267
  display: block;
256
- background: var(--theme-gray-lightest);
268
+ background: var(--trans-lightest);
257
269
  color: var(--text-trans-light);
258
270
  }
259
271
 
@@ -316,6 +328,8 @@ export class SdTextfield<K extends keyof SdTextfieldTypes> {
316
328
  "primary" | "secondary" | "info" | "success" | "warning" | "danger" | "gray" | "blue-gray"
317
329
  >();
318
330
 
331
+ private readonly _inputElRef = viewChild<ElementRef<HTMLInputElement>>("inputEl");
332
+
319
333
  private readonly _handler = computed(() => textfieldTypeHandlers[this.type()]);
320
334
 
321
335
  controlType = computed(() => this._handler().controlType);
@@ -340,6 +354,21 @@ export class SdTextfield<K extends keyof SdTextfieldTypes> {
340
354
  });
341
355
 
342
356
  constructor() {
357
+ if (isPlatformBrowser(inject(PLATFORM_ID))) {
358
+ effect(() => {
359
+ const controlValue = this.controlValue();
360
+ const inputEl = this._inputElRef()?.nativeElement;
361
+ if (inputEl == null) return;
362
+
363
+ // 편집(포커스) 중에는 DOM 을 되쓰면 사용자 입력(세그먼트·캐럿·IME 조합)이 깨지므로 생략
364
+ if (document.activeElement === inputEl) return;
365
+
366
+ if (inputEl.value !== controlValue) {
367
+ inputEl.value = controlValue;
368
+ }
369
+ });
370
+ }
371
+
343
372
  setupInvalid(() => {
344
373
  const value = this.value();
345
374
  const handlerErrors = this._handler().validate(value, {
@@ -379,6 +408,13 @@ export class SdTextfield<K extends keyof SdTextfieldTypes> {
379
408
  this.value.set(parsed as SdTextfieldTypes[K]);
380
409
  }
381
410
 
411
+ onBlur(event: FocusEvent): void {
412
+ // 편집 종료 시 모델 기준값으로 동기화 (number 콤마 포맷 반영, date 미완성 입력 정리)
413
+ // date 미완성 입력은 input.value 가 "" 라 비교 없이 무조건 되써야 남은 세그먼트가 정리됨
414
+ const inputEl = event.target as HTMLInputElement;
415
+ inputEl.value = this.controlValue();
416
+ }
417
+
382
418
  onInputPaste(event: ClipboardEvent): void {
383
419
  event.preventDefault();
384
420
  const text = event.clipboardData?.getData("text/plain").trim();
@@ -84,12 +84,12 @@ import { SdRipple } from "../../core/ripple/sd-ripple";
84
84
  &:focus-visible {
85
85
  outline: none;
86
86
  transition: background var(--animation-duration) ease-out;
87
- background: var(--trans-lighter);
87
+ background: var(--trans-light);
88
88
  }
89
89
  }
90
90
 
91
91
  &[data-sd-selected="true"] > ._content {
92
- background: var(--trans-lighter);
92
+ background: var(--trans-light);
93
93
  font-weight: bold;
94
94
  }
95
95
 
@@ -97,7 +97,7 @@ import { SdRipple } from "../../core/ripple/sd-ripple";
97
97
  color: var(--text-trans-default);
98
98
 
99
99
  &:hover {
100
- background: var(--trans-lighter);
100
+ background: var(--trans-light);
101
101
  }
102
102
  }
103
103
 
@@ -128,13 +128,13 @@ import { SdRipple } from "../../core/ripple/sd-ripple";
128
128
  &:not([data-sd-readonly="true"]) {
129
129
  > ._content:hover {
130
130
  transition: background var(--animation-duration) ease-out;
131
- background: var(--trans-lighter);
131
+ background: var(--trans-light);
132
132
  }
133
133
  }
134
134
 
135
135
  // 깊이별 들여쓰기: accordion 항목의 자식 리스트를 한 칸씩 누적 들여씀.
136
136
  // (flat 항목의 자식 리스트는 들여쓰지 않음)
137
- > sd-collapse > ._content > ._children > sd-list {
137
+ > sd-collapse > ._content > ._children > sd-list > sd-list-item > ._content {
138
138
  padding-left: 1.5em;
139
139
  }
140
140
  }
@@ -22,7 +22,7 @@ import { setupRipple } from "../../core/ripple/setupRipple";
22
22
  font-weight: bold;
23
23
  cursor: pointer;
24
24
  color: var(--theme-primary-default);
25
- transition: background 0.1s linear;
25
+ transition: background var(--animation-duration) linear;
26
26
 
27
27
  &:hover {
28
28
  color: var(--theme-primary-darker);