@simplysm/angular 14.2.1 → 14.2.3
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/controls/button/sd-anchor.d.ts +1 -1
- package/dist/controls/button/sd-anchor.d.ts.map +1 -1
- package/dist/controls/button/sd-anchor.js +2 -2
- package/dist/controls/button/sd-button.d.ts +1 -1
- package/dist/controls/button/sd-button.d.ts.map +1 -1
- package/dist/controls/button/sd-button.js +2 -2
- package/dist/controls/checkbox/sd-checkbox.d.ts +1 -1
- package/dist/controls/checkbox/sd-checkbox.d.ts.map +1 -1
- package/dist/controls/checkbox/sd-checkbox.js +2 -2
- package/dist/controls/checkbox/sd-switch.d.ts +1 -1
- package/dist/controls/checkbox/sd-switch.d.ts.map +1 -1
- package/dist/controls/checkbox/sd-switch.js +2 -2
- package/dist/controls/dropdown/sd-dropdown.d.ts +3 -0
- package/dist/controls/dropdown/sd-dropdown.d.ts.map +1 -1
- package/dist/controls/dropdown/sd-dropdown.js +29 -9
- package/dist/controls/input/sd-textarea.d.ts +1 -1
- package/dist/controls/input/sd-textarea.d.ts.map +1 -1
- package/dist/controls/input/sd-textarea.js +2 -2
- package/dist/controls/input/sd-textfield-type-handlers.js +1 -1
- package/dist/controls/input/sd-textfield.d.ts +1 -1
- package/dist/controls/input/sd-textfield.d.ts.map +1 -1
- package/dist/controls/input/sd-textfield.js +9 -10
- package/dist/controls/list/sd-list.d.ts.map +1 -1
- package/dist/controls/list/sd-list.js +4 -6
- package/dist/controls/select/sd-select-button.d.ts.map +1 -1
- package/dist/controls/select/sd-select-button.js +3 -5
- package/dist/controls/select/sd-select.js +2 -2
- package/dist/core/error-handler/sd-global-error-handler.plugin.js +1 -1
- package/dist/core/modal/sd-modal.provider.js +1 -1
- package/dist/core/provideSdAngular.d.ts.map +1 -1
- package/dist/core/provideSdAngular.js +1 -13
- package/dist/core/setupBgTheme.d.ts +1 -1
- package/dist/core/setupBgTheme.d.ts.map +1 -1
- package/dist/core/toast/sd-toast.js +2 -2
- package/dist/core/toast/sd-toast.provider.d.ts +1 -1
- package/dist/core/toast/sd-toast.provider.d.ts.map +1 -1
- package/dist/core/toast/sd-toast.provider.js +1 -1
- package/dist/data/crud/sd-base-container.d.ts +1 -1
- package/dist/data/crud/sd-base-container.d.ts.map +1 -1
- package/dist/data/crud/sd-base-container.js +2 -2
- package/dist/data/crud/sd-crud-detail.d.ts +1 -1
- package/dist/data/crud/sd-crud-detail.d.ts.map +1 -1
- package/dist/data/crud/sd-crud-list.d.ts +3 -3
- package/dist/data/crud/sd-crud-list.d.ts.map +1 -1
- package/dist/data/shared-data/sd-shared-data-select.d.ts +2 -2
- package/dist/data/shared-data/sd-shared-data-select.d.ts.map +1 -1
- package/dist/data/sheet/injectSheetDomAccessor.d.ts +1 -0
- package/dist/data/sheet/injectSheetDomAccessor.d.ts.map +1 -1
- package/dist/data/sheet/injectSheetDomAccessor.js +7 -0
- package/dist/data/sheet/injectSheetDragSelection.d.ts +18 -0
- package/dist/data/sheet/injectSheetDragSelection.d.ts.map +1 -0
- package/dist/data/sheet/injectSheetDragSelection.js +193 -0
- package/dist/data/sheet/sd-sheet.d.ts +3 -0
- package/dist/data/sheet/sd-sheet.d.ts.map +1 -1
- package/dist/data/sheet/sd-sheet.js +17 -6
- package/dist/data/state-preset/sd-state-preset.d.ts +2 -2
- package/dist/data/state-preset/sd-state-preset.d.ts.map +1 -1
- package/dist/features/editor/sd-tiptap-editor.js +2 -2
- package/dist/features/theme/sd-theme-provider.d.ts +0 -2
- package/dist/features/theme/sd-theme-provider.d.ts.map +1 -1
- package/dist/features/theme/sd-theme-provider.js +0 -5
- package/dist/features/theme/sd-theme-selector.d.ts +1 -1
- package/dist/features/theme/sd-theme-selector.d.ts.map +1 -1
- package/dist/features/theme/sd-theme-selector.js +5 -22
- package/dist/features/visual/sd-label.d.ts +1 -1
- package/dist/features/visual/sd-label.d.ts.map +1 -1
- package/dist/features/visual/sd-label.js +2 -2
- package/dist/features/visual/sd-note.d.ts +1 -1
- package/dist/features/visual/sd-note.d.ts.map +1 -1
- package/dist/features/visual/sd-note.js +2 -2
- package/dist/features/visual/sd-progress.d.ts +1 -1
- package/dist/features/visual/sd-progress.d.ts.map +1 -1
- package/dist/features/visual/sd-progress.js +2 -2
- package/dist/layout/sidebar/sd-sidebar.d.ts.map +1 -1
- package/dist/layout/sidebar/sd-sidebar.js +3 -5
- package/dist/layout/topbar/sd-topbar.d.ts.map +1 -1
- package/dist/layout/topbar/sd-topbar.js +3 -3
- package/package.json +26 -26
- package/scss/commons/_mixins.scss +1 -1
- package/scss/commons/_theme-variables.scss +0 -8
- package/scss/commons/_variables.scss +114 -121
- package/scss/themes/_variables-blueprint.scss +65 -63
- package/scss/themes/_variables-ide-dark.scss +166 -144
- package/src/controls/button/sd-anchor.ts +3 -3
- package/src/controls/button/sd-button.ts +1 -3
- package/src/controls/checkbox/sd-checkbox.ts +2 -10
- package/src/controls/checkbox/sd-switch.ts +2 -4
- package/src/controls/dropdown/sd-dropdown.ts +33 -9
- package/src/controls/input/sd-textarea.ts +2 -4
- package/src/controls/input/sd-textfield-type-handlers.ts +1 -1
- package/src/controls/input/sd-textfield.ts +9 -12
- package/src/controls/list/sd-list.ts +3 -5
- package/src/controls/select/sd-select-button.ts +2 -4
- package/src/controls/select/sd-select.ts +1 -1
- package/src/core/error-handler/sd-global-error-handler.plugin.ts +1 -1
- package/src/core/modal/sd-modal.provider.ts +1 -1
- package/src/core/provideSdAngular.ts +1 -15
- package/src/core/setupBgTheme.ts +1 -2
- package/src/core/toast/sd-toast.provider.ts +5 -3
- package/src/data/crud/sd-base-container.ts +1 -1
- package/src/data/sheet/injectSheetDomAccessor.ts +7 -0
- package/src/data/sheet/injectSheetDragSelection.ts +226 -0
- package/src/data/sheet/sd-sheet.ts +16 -3
- package/src/features/editor/sd-tiptap-editor.ts +1 -1
- package/src/features/theme/sd-theme-provider.ts +0 -9
- package/src/features/theme/sd-theme-selector.ts +1 -10
- package/src/features/visual/sd-label.ts +1 -3
- package/src/features/visual/sd-note.ts +1 -3
- package/src/features/visual/sd-progress.ts +2 -2
- package/src/layout/sidebar/sd-sidebar.ts +2 -3
- package/src/layout/topbar/sd-topbar.ts +1 -0
- package/styles.css +278 -567
- package/scss/commons/_colors.scss +0 -301
- package/scss/commons/_density.scss +0 -23
- package/scss/sd-tokens.md +0 -132
|
@@ -1,204 +1,207 @@
|
|
|
1
|
-
// IDE 다크 테마 — VSCode "Dark 2026" 을 --sd-* 역할 토큰 값
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// 치수(gap
|
|
1
|
+
// IDE 다크 테마 — VSCode "Dark 2026"(v1.113 기본, 2026-dark.json)을 --sd-* 역할 토큰 값 맵으로 구성.
|
|
2
|
+
// 색 원천: 리터럴 rgb(팔레트 배타 폐기 — 테마 값 자립). Dark 2026 은 near-black 3단 surface +
|
|
3
|
+
// solid 텍스트/보더 + 상태만 흰알파(하이브리드) + 죽인 teal 액센트가 핵심 의도.
|
|
4
|
+
// surface 3단: content #121314(editor) < canvas #191A1B(chrome/input) < elevated/overlay #202122(widget/menu).
|
|
5
|
+
// 치수(gap, radius, sheet pv/ph, topbar), 폰트(Sarasa Fixed K), 그림자(off)는 IDE 컨셉 — 색 외 항목 불변.
|
|
6
6
|
$dark: (
|
|
7
7
|
bg: (
|
|
8
|
-
// 계층: canvas
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
// 계층: content #121314(메인/에디터 — 제일 어두움) < canvas #191A1B(배경, 사이드바, 토프바) < elevated/overlay #202122(카드, 팝업)
|
|
9
|
+
// editor.background #121314 = 메인 콘텐츠(content) / sideBar.background #191A1B = 배경(canvas)
|
|
10
|
+
canvas: rgb(25, 26, 27),
|
|
11
|
+
// 콘텐츠 면 = editor.background #121314 (메인/에디터/시트셀/리스트 — 제일 어두움)
|
|
12
|
+
content: rgb(18, 19, 20),
|
|
13
|
+
elevated: rgb(32, 33, 34),
|
|
14
|
+
overlay: rgb(32, 33, 34),
|
|
15
|
+
sheet: rgb(18, 19, 20),
|
|
14
16
|
inverse: white,
|
|
15
|
-
// 필드 배경 — input.background
|
|
16
|
-
field:
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
// 필드 배경 — input.background #191A1B
|
|
18
|
+
field: rgb(25, 26, 27),
|
|
19
|
+
// 트랙 — inactive-selection #2C2D2E 근사
|
|
20
|
+
track: rgb(44, 45, 46),
|
|
21
|
+
// 노브 — 강조텍스트 #ededed 와 통일한 밝은 손잡이(트랙, success-solid 위 대비)
|
|
22
|
+
knob: rgb(237, 237, 237),
|
|
23
|
+
// 체크박스 박스 면 = checkbox.background #242526 (별도 면 — canvas 보다 밝음)
|
|
24
|
+
checkbox: rgb(36, 37, 38),
|
|
25
|
+
// 시맨틱 solid = 뮤트 중암 채움, hover 는 더 밝게(다크 hover 밝힘 — button #297AA0→#2B7DA3)
|
|
19
26
|
"gray": (
|
|
20
|
-
solid:
|
|
21
|
-
solid-hover:
|
|
22
|
-
subtle:
|
|
23
|
-
subtle-hover:
|
|
27
|
+
solid: rgb(135, 136, 137),
|
|
28
|
+
solid-hover: rgb(160, 161, 162),
|
|
29
|
+
subtle: rgb(32, 33, 34),
|
|
30
|
+
subtle-hover: rgb(42, 43, 44),
|
|
24
31
|
),
|
|
25
32
|
blue-gray: (
|
|
26
|
-
solid:
|
|
27
|
-
solid-hover:
|
|
28
|
-
subtle:
|
|
29
|
-
subtle-hover:
|
|
33
|
+
solid: rgb(100, 116, 139),
|
|
34
|
+
solid-hover: rgb(120, 136, 159),
|
|
35
|
+
subtle: rgb(28, 34, 44),
|
|
36
|
+
subtle-hover: rgb(38, 46, 58),
|
|
30
37
|
),
|
|
38
|
+
// 액센트 = 죽인 teal(button.background #297AA0 / hover #2B7DA3)
|
|
31
39
|
primary: (
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
secondary: (
|
|
38
|
-
solid: var(--sd-color-sky-600),
|
|
39
|
-
solid-hover: var(--sd-color-sky-500),
|
|
40
|
-
subtle: var(--sd-color-zinc-900),
|
|
41
|
-
subtle-hover: var(--sd-color-sky-900),
|
|
42
|
-
),
|
|
40
|
+
solid: rgb(41, 122, 160),
|
|
41
|
+
solid-hover: rgb(43, 125, 163),
|
|
42
|
+
subtle: rgb(20, 50, 63),
|
|
43
|
+
subtle-hover: rgb(26, 63, 78),
|
|
44
|
+
),
|
|
43
45
|
info: (
|
|
44
|
-
solid:
|
|
45
|
-
solid-hover:
|
|
46
|
-
subtle:
|
|
47
|
-
subtle-hover:
|
|
46
|
+
solid: rgb(57, 148, 188),
|
|
47
|
+
solid-hover: rgb(66, 158, 200),
|
|
48
|
+
subtle: rgb(16, 45, 60),
|
|
49
|
+
subtle-hover: rgb(22, 58, 76),
|
|
48
50
|
),
|
|
51
|
+
// success solid = 뮤트 다크그린(파생), tx 는 charts.green #86CF86
|
|
49
52
|
success: (
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
solid: rgb(56, 125, 86),
|
|
54
|
+
solid-hover: rgb(64, 140, 97),
|
|
55
|
+
subtle: rgb(16, 45, 30),
|
|
56
|
+
subtle-hover: rgb(22, 58, 40),
|
|
57
|
+
),
|
|
58
|
+
// warning = inputValidation.warningBorder #B89500
|
|
55
59
|
warning: (
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
//
|
|
60
|
+
solid: rgb(184, 149, 0),
|
|
61
|
+
solid-hover: rgb(200, 163, 10),
|
|
62
|
+
subtle: rgb(48, 40, 4),
|
|
63
|
+
subtle-hover: rgb(60, 50, 6),
|
|
64
|
+
),
|
|
65
|
+
// danger solid = inputValidation.errorBorder #BE1100, tx 는 errorForeground #f48771
|
|
62
66
|
danger: (
|
|
63
|
-
solid:
|
|
64
|
-
solid-hover:
|
|
65
|
-
subtle:
|
|
66
|
-
subtle-hover:
|
|
67
|
+
solid: rgb(190, 17, 0),
|
|
68
|
+
solid-hover: rgb(215, 25, 5),
|
|
69
|
+
subtle: rgb(58, 14, 8),
|
|
70
|
+
subtle-hover: rgb(74, 18, 10),
|
|
67
71
|
),
|
|
68
|
-
//
|
|
72
|
+
// 상태 오버레이 = 흰알파(list.hover #FFFFFF14 / active, focus #FFFFFF22)
|
|
69
73
|
state: (
|
|
70
|
-
hover: rgba(255, 255, 255, 0.
|
|
71
|
-
active: rgba(255, 255, 255, 0.
|
|
72
|
-
selected: rgba(255, 255, 255, 0.
|
|
74
|
+
hover: rgba(255, 255, 255, 0.08),
|
|
75
|
+
active: rgba(255, 255, 255, 0.13),
|
|
76
|
+
selected: rgba(255, 255, 255, 0.13),
|
|
77
|
+
// 포커스 없는 선택행 solid (list.inactiveSelection #2C2D2E)
|
|
78
|
+
selected-inactive: rgb(44, 45, 46),
|
|
73
79
|
),
|
|
74
|
-
|
|
80
|
+
// 드롭 자리, 텍스트 선택 (list.dropBackground #3994BC1A / editor.selection #276782dd)
|
|
81
|
+
drop-target: rgba(57, 148, 188, 0.1),
|
|
82
|
+
selection: rgba(39, 103, 130, 0.87),
|
|
83
|
+
// 비활성 = 가라앉음(canvas 보다 어둡게)
|
|
84
|
+
disabled: rgb(22, 23, 24),
|
|
75
85
|
busy-overlay: rgba(0, 0, 0, 0.6),
|
|
76
|
-
|
|
86
|
+
// 진행/로딩 중립 (progressBar.background #878889)
|
|
87
|
+
busy-indicator: rgb(135, 136, 137)
|
|
77
88
|
),
|
|
78
|
-
//
|
|
89
|
+
// 텍스트 = solid 그레이(foreground #bfbfbf, description #8c8c8c, disabled #555, activeSelection #ededed)
|
|
79
90
|
tx: (
|
|
80
|
-
strong:
|
|
81
|
-
default:
|
|
82
|
-
muted:
|
|
83
|
-
faint:
|
|
91
|
+
strong: rgb(237, 237, 237),
|
|
92
|
+
default: rgb(191, 191, 191),
|
|
93
|
+
muted: rgb(140, 140, 140),
|
|
94
|
+
faint: rgb(85, 85, 85),
|
|
84
95
|
on-inverse: white,
|
|
85
96
|
on-inverse-muted: rgba(255, 255, 255, 0.75),
|
|
86
97
|
on-inverse-disabled: rgba(255, 255, 255, 0.55),
|
|
87
|
-
disabled:
|
|
88
|
-
//
|
|
89
|
-
"gray":
|
|
90
|
-
gray-hover:
|
|
91
|
-
gray-subtle:
|
|
92
|
-
blue-gray:
|
|
93
|
-
blue-gray-hover:
|
|
94
|
-
blue-gray-subtle:
|
|
95
|
-
primary:
|
|
96
|
-
primary-hover:
|
|
97
|
-
primary-subtle:
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
danger: var(--sd-color-red-400),
|
|
111
|
-
danger-hover: var(--sd-color-red-500),
|
|
112
|
-
danger-subtle: var(--sd-color-red-300),
|
|
98
|
+
disabled: rgb(85, 85, 85),
|
|
99
|
+
// 시맨틱 텍스트 = VSCode 라이트 foreground(link #48A0C7, charts.* 등)
|
|
100
|
+
"gray": rgb(140, 140, 140),
|
|
101
|
+
gray-hover: rgb(191, 191, 191),
|
|
102
|
+
gray-subtle: rgb(191, 191, 191),
|
|
103
|
+
blue-gray: rgb(148, 163, 184),
|
|
104
|
+
blue-gray-hover: rgb(170, 183, 200),
|
|
105
|
+
blue-gray-subtle: rgb(170, 183, 200),
|
|
106
|
+
primary: rgb(72, 160, 199),
|
|
107
|
+
primary-hover: rgb(83, 165, 202),
|
|
108
|
+
primary-subtle: rgb(130, 197, 224),
|
|
109
|
+
info: rgb(87, 163, 248),
|
|
110
|
+
info-hover: rgb(120, 185, 250),
|
|
111
|
+
info-subtle: rgb(130, 190, 250),
|
|
112
|
+
success: rgb(134, 207, 134),
|
|
113
|
+
success-hover: rgb(160, 220, 160),
|
|
114
|
+
success-subtle: rgb(150, 215, 150),
|
|
115
|
+
warning: rgb(224, 185, 127),
|
|
116
|
+
warning-hover: rgb(232, 200, 150),
|
|
117
|
+
warning-subtle: rgb(232, 205, 160),
|
|
118
|
+
danger: rgb(244, 135, 113),
|
|
119
|
+
danger-hover: rgb(248, 160, 140),
|
|
120
|
+
danger-subtle: rgb(248, 170, 152),
|
|
113
121
|
),
|
|
114
|
-
//
|
|
122
|
+
// 보더 = solid 그레이(widget.border #2A2B2C, input.border #333536, checkbox #707070)
|
|
115
123
|
bd: (
|
|
116
|
-
hairline:
|
|
117
|
-
soft:
|
|
118
|
-
default:
|
|
119
|
-
strong:
|
|
120
|
-
emphasis:
|
|
121
|
-
field:
|
|
122
|
-
disabled:
|
|
124
|
+
hairline: rgb(36, 37, 38),
|
|
125
|
+
soft: rgb(42, 43, 44),
|
|
126
|
+
default: rgb(42, 43, 44),
|
|
127
|
+
strong: rgb(51, 53, 54),
|
|
128
|
+
emphasis: rgb(112, 112, 112),
|
|
129
|
+
field: rgb(51, 53, 54),
|
|
130
|
+
disabled: rgb(42, 43, 44),
|
|
123
131
|
"gray": (
|
|
124
|
-
solid:
|
|
125
|
-
solid-hover:
|
|
126
|
-
subtle:
|
|
132
|
+
solid: rgb(135, 136, 137),
|
|
133
|
+
solid-hover: rgb(160, 161, 162),
|
|
134
|
+
subtle: rgb(51, 53, 54),
|
|
127
135
|
),
|
|
128
136
|
blue-gray: (
|
|
129
|
-
solid:
|
|
130
|
-
solid-hover:
|
|
131
|
-
subtle:
|
|
137
|
+
solid: rgb(100, 116, 139),
|
|
138
|
+
solid-hover: rgb(120, 136, 159),
|
|
139
|
+
subtle: rgb(51, 53, 54),
|
|
132
140
|
),
|
|
133
141
|
primary: (
|
|
134
|
-
solid:
|
|
135
|
-
solid-hover:
|
|
136
|
-
subtle:
|
|
137
|
-
),
|
|
138
|
-
secondary: (
|
|
139
|
-
solid: var(--sd-color-sky-600),
|
|
140
|
-
solid-hover: var(--sd-color-sky-500),
|
|
141
|
-
subtle: var(--sd-color-sky-500),
|
|
142
|
+
solid: rgb(41, 122, 160),
|
|
143
|
+
solid-hover: rgb(43, 125, 163),
|
|
144
|
+
subtle: rgb(38, 90, 110),
|
|
142
145
|
),
|
|
143
146
|
info: (
|
|
144
|
-
solid:
|
|
145
|
-
solid-hover:
|
|
146
|
-
subtle:
|
|
147
|
+
solid: rgb(57, 148, 188),
|
|
148
|
+
solid-hover: rgb(66, 158, 200),
|
|
149
|
+
subtle: rgb(30, 74, 96),
|
|
147
150
|
),
|
|
148
151
|
success: (
|
|
149
|
-
solid:
|
|
150
|
-
solid-hover:
|
|
151
|
-
subtle:
|
|
152
|
+
solid: rgb(56, 125, 86),
|
|
153
|
+
solid-hover: rgb(64, 140, 97),
|
|
154
|
+
subtle: rgb(34, 72, 52),
|
|
152
155
|
),
|
|
153
156
|
warning: (
|
|
154
|
-
solid:
|
|
155
|
-
solid-hover:
|
|
156
|
-
subtle:
|
|
157
|
+
solid: rgb(184, 149, 0),
|
|
158
|
+
solid-hover: rgb(200, 163, 10),
|
|
159
|
+
subtle: rgb(90, 74, 10),
|
|
157
160
|
),
|
|
158
161
|
danger: (
|
|
159
|
-
solid:
|
|
160
|
-
solid-hover:
|
|
161
|
-
subtle:
|
|
162
|
+
solid: rgb(190, 17, 0),
|
|
163
|
+
solid-hover: rgb(215, 25, 5),
|
|
164
|
+
subtle: rgb(96, 30, 20),
|
|
162
165
|
),
|
|
163
166
|
),
|
|
167
|
+
// focusBorder #3994BCB3 (70% 알파 teal)
|
|
164
168
|
focus-ring: (
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
//
|
|
169
|
+
color: rgba(57, 148, 188, 0.7),
|
|
170
|
+
),
|
|
171
|
+
// scrollbarSlider #A8A9AA85/90
|
|
168
172
|
scrollbar: (
|
|
169
|
-
thumb: rgba(
|
|
170
|
-
thumb-hover: rgba(
|
|
173
|
+
thumb: rgba(168, 169, 170, 0.52),
|
|
174
|
+
thumb-hover: rgba(168, 169, 170, 0.565),
|
|
171
175
|
track: rgba(255, 255, 255, 0.03),
|
|
172
176
|
),
|
|
173
|
-
// 그림자 전면 제거 —
|
|
177
|
+
// 그림자 전면 제거 — dark JSON 은 widget.shadow 부재, 계층을 휘도 3단으로 표현
|
|
174
178
|
shadow: (
|
|
175
179
|
size: 0,
|
|
176
180
|
blur-mult: 0,
|
|
177
181
|
),
|
|
178
|
-
//
|
|
179
|
-
// (tab.activeBorderTop #3994BC 근사 = sky-500)
|
|
182
|
+
// 카드 경계 = solid widget.border #2A2B2C. focus 는 전체 outline(focus-ring)으로 — 상단 액센트 라인 제거
|
|
180
183
|
card: (
|
|
181
|
-
bd:
|
|
182
|
-
bd-active:
|
|
184
|
+
bd: rgb(42, 43, 44),
|
|
185
|
+
bd-active: transparent,
|
|
183
186
|
shadow: none,
|
|
184
187
|
shadow-hover: none,
|
|
185
188
|
),
|
|
186
|
-
// 오버레이
|
|
189
|
+
// 오버레이 경계 — editorWidget/menu 배경(#202122) + widget.border #2A2B2C solid
|
|
187
190
|
modal: (
|
|
188
|
-
bd:
|
|
189
|
-
header-bg:
|
|
190
|
-
header-tx:
|
|
191
|
-
header-tx-muted:
|
|
191
|
+
bd: rgb(42, 43, 44),
|
|
192
|
+
header-bg: rgb(32, 33, 34),
|
|
193
|
+
header-tx: rgb(191, 191, 191),
|
|
194
|
+
header-tx-muted: rgb(140, 140, 140),
|
|
192
195
|
),
|
|
193
196
|
dropdown: (
|
|
194
|
-
bd:
|
|
197
|
+
bd: rgb(42, 43, 44),
|
|
195
198
|
),
|
|
196
|
-
// 권한표 그룹 행 —
|
|
199
|
+
// 권한표 그룹 행 — 원색 solid 를 무채 어두운 행으로
|
|
197
200
|
permission-group: (
|
|
198
|
-
bg:
|
|
201
|
+
bg: rgb(32, 33, 34),
|
|
199
202
|
tx: rgba(255, 255, 255, 0.75),
|
|
200
203
|
),
|
|
201
|
-
// VSCode 수준 소형 라운드 —
|
|
204
|
+
// VSCode 수준 소형 라운드 — 버튼, 인풋 2px, 위젯, 메뉴 4px 급(12px 기준)
|
|
202
205
|
radius: (
|
|
203
206
|
xs: 0.0833rem,
|
|
204
207
|
sm: 0.0833rem,
|
|
@@ -207,7 +210,26 @@ $dark: (
|
|
|
207
210
|
xl: 0.3333rem,
|
|
208
211
|
xxl: 0.5rem,
|
|
209
212
|
),
|
|
210
|
-
//
|
|
213
|
+
// 치수 — 오밀조밀(구 밀도 compact 이관). 라이트, 블루프린트는 기본 치수 유지.
|
|
214
|
+
gap: (
|
|
215
|
+
xxs: 0.0833rem,
|
|
216
|
+
xs: 0.0833rem,
|
|
217
|
+
sm: 0.1667rem,
|
|
218
|
+
default: 0.3333rem,
|
|
219
|
+
lg: 0.4167rem,
|
|
220
|
+
xl: 0.6667rem,
|
|
221
|
+
xxl: 1rem,
|
|
222
|
+
),
|
|
223
|
+
// line-height: 1.5em,
|
|
224
|
+
// line-height-strip-unit: 1.5,
|
|
225
|
+
sheet: (
|
|
226
|
+
pv: 0.0833rem,
|
|
227
|
+
ph: 0.1667rem,
|
|
228
|
+
),
|
|
229
|
+
topbar: (
|
|
230
|
+
height: 2rem,
|
|
231
|
+
),
|
|
232
|
+
// 폰트는 이 테마 컨셉이라 여기서만 Sarasa Fixed K 로 덮는다(라이트, 블루프린트 불변)
|
|
211
233
|
font-family: '"Sarasa Fixed K", ui-monospace, monospace',
|
|
212
234
|
font-family-field: '"Sarasa Fixed K", ui-monospace, monospace',
|
|
213
235
|
font-family-monospace: '"Sarasa Fixed K", ui-monospace, monospace',
|
|
@@ -60,7 +60,7 @@ import {
|
|
|
60
60
|
})
|
|
61
61
|
export class SdAnchor {
|
|
62
62
|
disabled = input(false, { transform: booleanAttribute });
|
|
63
|
-
theme = input<
|
|
64
|
-
"primary"
|
|
65
|
-
|
|
63
|
+
theme = input<"primary" | "info" | "success" | "warning" | "danger" | "gray" | "blue-gray">(
|
|
64
|
+
"primary",
|
|
65
|
+
);
|
|
66
66
|
}
|
|
@@ -37,7 +37,7 @@ import { SdRipple } from "../../core/ripple/sd-ripple";
|
|
|
37
37
|
padding: var(--sd-gap-sm) var(--sd-gap-lg);
|
|
38
38
|
width: 100%;
|
|
39
39
|
|
|
40
|
-
background-color: var(--sd-bg-
|
|
40
|
+
background-color: var(--sd-bg-content);
|
|
41
41
|
border-color: var(--sd-bd-primary-solid);
|
|
42
42
|
border-radius: var(--sd-radius-default);
|
|
43
43
|
|
|
@@ -184,7 +184,6 @@ export class SdButton {
|
|
|
184
184
|
type = input<"button" | "submit">("button");
|
|
185
185
|
theme = input<
|
|
186
186
|
| "primary"
|
|
187
|
-
| "secondary"
|
|
188
187
|
| "info"
|
|
189
188
|
| "success"
|
|
190
189
|
| "warning"
|
|
@@ -193,7 +192,6 @@ export class SdButton {
|
|
|
193
192
|
| "blue-gray"
|
|
194
193
|
| "link"
|
|
195
194
|
| "link-primary"
|
|
196
|
-
| "link-secondary"
|
|
197
195
|
| "link-info"
|
|
198
196
|
| "link-success"
|
|
199
197
|
| "link-warning"
|
|
@@ -135,7 +135,7 @@ import { tablerCheck } from "@ng-icons/tabler-icons";
|
|
|
135
135
|
|
|
136
136
|
&[data-sd-theme="white"] {
|
|
137
137
|
> ._indicator_rect {
|
|
138
|
-
background-color: var(--sd-bg-
|
|
138
|
+
background-color: var(--sd-bg-checkbox);
|
|
139
139
|
border-color: var(--sd-bd-field);
|
|
140
140
|
}
|
|
141
141
|
|
|
@@ -279,15 +279,7 @@ export class SdCheckbox {
|
|
|
279
279
|
inline = input(false, { transform: booleanAttribute });
|
|
280
280
|
inset = input(false, { transform: booleanAttribute });
|
|
281
281
|
theme = input<
|
|
282
|
-
| "
|
|
283
|
-
| "secondary"
|
|
284
|
-
| "info"
|
|
285
|
-
| "success"
|
|
286
|
-
| "warning"
|
|
287
|
-
| "danger"
|
|
288
|
-
| "gray"
|
|
289
|
-
| "blue-gray"
|
|
290
|
-
| "white"
|
|
282
|
+
"primary" | "info" | "success" | "warning" | "danger" | "gray" | "blue-gray" | "white"
|
|
291
283
|
>();
|
|
292
284
|
|
|
293
285
|
contentStyle = input<string>();
|
|
@@ -56,7 +56,7 @@ import { setupModelHook } from "../../core/setupModelHook";
|
|
|
56
56
|
height: calc(var(--sd-line-height) - var(--sd-gap-xs));
|
|
57
57
|
border-radius: 100%;
|
|
58
58
|
|
|
59
|
-
background-color: var(--sd-bg-
|
|
59
|
+
background-color: var(--sd-bg-knob);
|
|
60
60
|
|
|
61
61
|
transition: transform var(--sd-animation-duration);
|
|
62
62
|
}
|
|
@@ -123,9 +123,7 @@ export class SdSwitch {
|
|
|
123
123
|
inset = input(false, { transform: booleanAttribute });
|
|
124
124
|
|
|
125
125
|
size = input<"sm" | "lg">();
|
|
126
|
-
theme = input<
|
|
127
|
-
"primary" | "secondary" | "info" | "success" | "warning" | "danger" | "gray" | "blue-gray"
|
|
128
|
-
>();
|
|
126
|
+
theme = input<"primary" | "info" | "success" | "warning" | "danger" | "gray" | "blue-gray">();
|
|
129
127
|
|
|
130
128
|
constructor() {
|
|
131
129
|
setupModelHook(this.value, this.canChangeFn);
|
|
@@ -42,7 +42,8 @@ export class SdDropdown {
|
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
private _popupEl?: HTMLElement;
|
|
45
|
-
|
|
45
|
+
/** `<svg>` 등 비-HTML 요소도 hover 대상이 되므로 `Element` 로 받는다. */
|
|
46
|
+
private _mouseoverEl?: Element;
|
|
46
47
|
private _backdropEl?: HTMLElement;
|
|
47
48
|
private readonly _isMobile;
|
|
48
49
|
private readonly _mql: MediaQueryList;
|
|
@@ -88,7 +89,8 @@ export class SdDropdown {
|
|
|
88
89
|
this._onDocumentScrollCapture(event);
|
|
89
90
|
};
|
|
90
91
|
const onMouseover = (event: Event) => {
|
|
91
|
-
|
|
92
|
+
const target = (event as MouseEvent).target;
|
|
93
|
+
this._mouseoverEl = target instanceof Element ? target : undefined;
|
|
92
94
|
};
|
|
93
95
|
const onBlur = (event: Event) => {
|
|
94
96
|
this._onDocumentBlurCapture(event as FocusEvent);
|
|
@@ -245,18 +247,27 @@ export class SdDropdown {
|
|
|
245
247
|
}
|
|
246
248
|
}
|
|
247
249
|
|
|
250
|
+
// 팝업 내부 요소가 disabled 로 전환되며 포커스를 잃은 경우.
|
|
251
|
+
// 브라우저가 렌더 도중 동기 blur 를 발사하는 경로이며, 사용자가 팝업을 벗어난 것이 아니다.
|
|
252
|
+
// 여기서 팝업을 닫으면 렌더 중 signal 쓰기가 되어 NG0600 이 발생한다.
|
|
253
|
+
const blurredEl = event.target;
|
|
254
|
+
if (
|
|
255
|
+
relatedTarget == null &&
|
|
256
|
+
blurredEl instanceof HTMLElement &&
|
|
257
|
+
(contentEl.contains(blurredEl) === true || popupEl.contains(blurredEl) === true) &&
|
|
258
|
+
blurredEl.matches(":disabled")
|
|
259
|
+
) {
|
|
260
|
+
this._restoreFocus();
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
248
264
|
const mouseoverEl = this._mouseoverEl;
|
|
249
265
|
if (
|
|
250
266
|
relatedTarget == null &&
|
|
251
|
-
mouseoverEl instanceof
|
|
267
|
+
mouseoverEl instanceof Element &&
|
|
252
268
|
(contentEl.contains(mouseoverEl) === true || popupEl.contains(mouseoverEl) === true)
|
|
253
269
|
) {
|
|
254
|
-
|
|
255
|
-
if (tabbable != null) {
|
|
256
|
-
tabbable.focus();
|
|
257
|
-
} else {
|
|
258
|
-
contentEl.focus();
|
|
259
|
-
}
|
|
270
|
+
this._restoreFocus();
|
|
260
271
|
return;
|
|
261
272
|
}
|
|
262
273
|
|
|
@@ -265,6 +276,19 @@ export class SdDropdown {
|
|
|
265
276
|
}
|
|
266
277
|
}
|
|
267
278
|
|
|
279
|
+
/** 팝업이 열린 상태를 유지해야 할 때 포커스를 팝업 안으로 되돌린다. */
|
|
280
|
+
private _restoreFocus(): void {
|
|
281
|
+
const popupEl = this._popupEl;
|
|
282
|
+
if (popupEl == null) return;
|
|
283
|
+
|
|
284
|
+
const tabbable = popupEl.findFirstTabbableChild();
|
|
285
|
+
if (tabbable != null) {
|
|
286
|
+
tabbable.focus();
|
|
287
|
+
} else {
|
|
288
|
+
this._elRef.nativeElement.focus();
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
268
292
|
private _removePopup(): void {
|
|
269
293
|
if (this._backdropEl != null) {
|
|
270
294
|
this._backdropEl.remove();
|
|
@@ -160,7 +160,7 @@ import { setupInvalid } from "../../core/validation/setupInvalid";
|
|
|
160
160
|
// inset(시트 셀 등)의 disabled 는 일반 콘텐츠처럼 표시(현행 유지)
|
|
161
161
|
&[data-sd-inset="true"] {
|
|
162
162
|
> ._contents {
|
|
163
|
-
background-color: var(--sd-bg-
|
|
163
|
+
background-color: var(--sd-bg-content);
|
|
164
164
|
color: var(--sd-tx-default);
|
|
165
165
|
}
|
|
166
166
|
}
|
|
@@ -190,9 +190,7 @@ export class SdTextarea {
|
|
|
190
190
|
inset = input(false, { transform: booleanAttribute });
|
|
191
191
|
size = input<"sm" | "lg">();
|
|
192
192
|
validatorFn = input<(value: string | undefined) => string | undefined>();
|
|
193
|
-
theme = input<
|
|
194
|
-
"primary" | "secondary" | "info" | "success" | "warning" | "danger" | "gray" | "blue-gray"
|
|
195
|
-
>();
|
|
193
|
+
theme = input<"primary" | "info" | "success" | "warning" | "danger" | "gray" | "blue-gray">();
|
|
196
194
|
inputStyle = input<string>();
|
|
197
195
|
inputClass = input<string>();
|
|
198
196
|
|
|
@@ -160,7 +160,7 @@ function createNumberHandler(): TextfieldTypeHandler {
|
|
|
160
160
|
},
|
|
161
161
|
isIncomplete(raw) {
|
|
162
162
|
const inputValue = raw.replace(/[^0-9-.]/g, "");
|
|
163
|
-
//
|
|
163
|
+
// 부호, 소수점 형식은 갖췄으나 아직 완성되지 않은 진행 상태 ("-", "12.", ".", "-.")
|
|
164
164
|
// Number("12.")===12 이므로 endsWith(".") 를 별도 판정 (parse 의 실패 조건과 정합)
|
|
165
165
|
return (
|
|
166
166
|
/^-?\d*\.?\d*$/.test(inputValue)
|
|
@@ -273,7 +273,7 @@ import { textfieldTypeHandlers, type SdTextfieldTypes } from "./sd-textfield-typ
|
|
|
273
273
|
// inset(시트 셀 등)의 disabled 는 일반 콘텐츠처럼 표시(현행 유지)
|
|
274
274
|
&[data-sd-inset="true"] {
|
|
275
275
|
> ._contents {
|
|
276
|
-
background-color: var(--sd-bg-
|
|
276
|
+
background-color: var(--sd-bg-content);
|
|
277
277
|
color: var(--sd-tx-default);
|
|
278
278
|
}
|
|
279
279
|
}
|
|
@@ -326,13 +326,11 @@ export class SdTextfield<K extends keyof SdTextfieldTypes> {
|
|
|
326
326
|
inline = input(false, { transform: booleanAttribute });
|
|
327
327
|
inset = input(false, { transform: booleanAttribute });
|
|
328
328
|
size = input<"sm" | "lg">();
|
|
329
|
-
theme = input<
|
|
330
|
-
"primary" | "secondary" | "info" | "success" | "warning" | "danger" | "gray" | "blue-gray"
|
|
331
|
-
>();
|
|
329
|
+
theme = input<"primary" | "info" | "success" | "warning" | "danger" | "gray" | "blue-gray">();
|
|
332
330
|
|
|
333
331
|
private readonly _inputElRef = viewChild<ElementRef<HTMLInputElement>>("inputEl");
|
|
334
332
|
|
|
335
|
-
// 실제 input 의 브라우저 native 제약 위반(이메일
|
|
333
|
+
// 실제 input 의 브라우저 native 제약 위반(이메일 형식, 날짜 미완성 등) 메시지. onInput/onBlur 에서 갱신.
|
|
336
334
|
private readonly _nativeInvalidMessage = signal("");
|
|
337
335
|
|
|
338
336
|
// IME 조합(한글 등) 중 여부. 조합 중에는 미완성 자모가 model 로 흐르지 않도록 갱신을 보류.
|
|
@@ -375,11 +373,11 @@ export class SdTextfield<K extends keyof SdTextfieldTypes> {
|
|
|
375
373
|
if (this._composing) return;
|
|
376
374
|
|
|
377
375
|
// 편집(포커스) 중이라도 변경 origin 을 구분한다.
|
|
378
|
-
// 사용자 입력이 만든 DOM(정규화
|
|
379
|
-
// 모델만 외부에서 바뀐 경우(프로그래밍적
|
|
376
|
+
// 사용자 입력이 만든 DOM(정규화 차이, 진행 중 입력 포함)은 보호하고,
|
|
377
|
+
// 모델만 외부에서 바뀐 경우(프로그래밍적 리셋, prefill, 표시옵션 변경)는 되써서 반영한다.
|
|
380
378
|
if (document.activeElement === inputEl) {
|
|
381
379
|
const domParsed = this._handler().parse(inputEl.value, { format: this.format() });
|
|
382
|
-
// DOM raw 가 현재 모델의 유효한 표현이면(사용자 입력 유래) 되쓰지 않아
|
|
380
|
+
// DOM raw 가 현재 모델의 유효한 표현이면(사용자 입력 유래) 되쓰지 않아 캐럿, IME 보호
|
|
383
381
|
const domReflectsModel =
|
|
384
382
|
domParsed != null &&
|
|
385
383
|
this._handler().toControlValue(domParsed, {
|
|
@@ -399,9 +397,8 @@ export class SdTextfield<K extends keyof SdTextfieldTypes> {
|
|
|
399
397
|
}
|
|
400
398
|
|
|
401
399
|
setupInvalid(() => {
|
|
402
|
-
//
|
|
403
|
-
|
|
404
|
-
|
|
400
|
+
// 검증은 편집 가능 여부와 무관하다. disabled, readonly 여도 값이 제약을 어기면 invalid 다.
|
|
401
|
+
// 값이 무의미한 맥락이면 소비자가 제약(required 등)을 함께 내려야 한다.
|
|
405
402
|
const value = this.value();
|
|
406
403
|
const handlerErrors = this._handler().validate(value, {
|
|
407
404
|
required: this.required(),
|
|
@@ -422,7 +419,7 @@ export class SdTextfield<K extends keyof SdTextfieldTypes> {
|
|
|
422
419
|
}
|
|
423
420
|
}
|
|
424
421
|
|
|
425
|
-
// 브라우저 native 제약 위반(이메일
|
|
422
|
+
// 브라우저 native 제약 위반(이메일 형식, 날짜 미완성 등)을 우리 검증(빨간점)에 합류
|
|
426
423
|
const nativeMessage = this._nativeInvalidMessage();
|
|
427
424
|
if (nativeMessage !== "") {
|
|
428
425
|
errorMessages.push(nativeMessage);
|