@iyulab/components 0.1.4 → 0.1.5
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/assets/styles/dark.css +40 -36
- package/dist/assets/styles/dark.css.js +1 -1
- package/dist/assets/styles/light.css +41 -38
- package/dist/assets/styles/light.css.js +1 -1
- package/dist/components/BaseElement.styles.js +2 -2
- package/dist/components/alert/Alert.d.ts +8 -4
- package/dist/components/alert/Alert.js +24 -15
- package/dist/components/alert/Alert.styles.js +32 -39
- package/dist/components/alert/index.js +5 -0
- package/dist/components/button/Button.js +4 -2
- package/dist/components/button/Button.styles.js +13 -20
- package/dist/components/button/index.js +5 -0
- package/dist/components/context-menu/index.js +5 -0
- package/dist/components/copy-button/CopyButton.d.ts +7 -3
- package/dist/components/copy-button/CopyButton.js +69 -0
- package/dist/components/copy-button/CopyButton.styles.js +17 -0
- package/dist/components/copy-button/index.js +5 -0
- package/dist/components/dialog/index.js +5 -0
- package/dist/components/divider/Divider.d.ts +5 -5
- package/dist/components/divider/Divider.js +15 -15
- package/dist/components/divider/Divider.styles.js +7 -5
- package/dist/components/divider/index.js +5 -0
- package/dist/components/form/Form.d.ts +3 -1
- package/dist/components/form/Form.js +3 -1
- package/dist/components/form/Form.styles.js +1 -0
- package/dist/components/form/index.js +5 -0
- package/dist/components/icon/Icon.d.ts +6 -12
- package/dist/components/icon/Icon.js +14 -30
- package/dist/components/icon/Icon.styles.js +1 -1
- package/dist/components/icon/index.js +5 -0
- package/dist/components/icon-button/IconButton.d.ts +3 -3
- package/dist/components/icon-button/IconButton.js +6 -6
- package/dist/components/icon-button/IconButton.styles.js +14 -29
- package/dist/components/icon-button/index.js +5 -0
- package/dist/components/index.d.ts +1 -1
- package/dist/components/input/Input.d.ts +14 -13
- package/dist/components/input/Input.js +56 -55
- package/dist/components/input/Input.styles.js +52 -54
- package/dist/components/input/index.js +5 -0
- package/dist/components/menu/index.js +5 -0
- package/dist/components/progress-bar/ProgressBar.d.ts +1 -1
- package/dist/components/progress-bar/ProgressBar.js +2 -2
- package/dist/components/progress-bar/ProgressBar.styles.js +10 -10
- package/dist/components/progress-bar/index.js +5 -0
- package/dist/components/progress-ring/ProgressRing.d.ts +2 -2
- package/dist/components/progress-ring/ProgressRing.js +7 -6
- package/dist/components/progress-ring/ProgressRing.styles.js +8 -9
- package/dist/components/progress-ring/index.js +5 -0
- package/dist/components/spinner/Spinner.styles.js +5 -3
- package/dist/components/spinner/index.js +5 -0
- package/dist/components/split-panel/SplitPanel.d.ts +1 -1
- package/dist/components/split-panel/SplitPanel.js +5 -7
- package/dist/components/split-panel/index.js +5 -0
- package/dist/components/tooltip/Tooltip.styles.js +1 -1
- package/dist/components/tooltip/index.js +5 -0
- package/dist/components/tree/index.js +5 -0
- package/dist/components/tree-item/index.js +5 -0
- package/dist/index.js +24 -5
- package/dist/integrations/react/index.d.ts +0 -1
- package/dist/integrations/react/index.js +0 -1
- package/dist/internals/index.d.ts +0 -1
- package/dist/utilities/decorators.js +2 -0
- package/dist/utilities/icons.d.ts +46 -0
- package/dist/utilities/icons.js +114 -0
- package/dist/utilities/index.d.ts +1 -0
- package/dist/utilities/notifier.d.ts +17 -7
- package/dist/utilities/notifier.js +51 -41
- package/dist/utilities/theme.d.ts +15 -20
- package/dist/utilities/theme.js +24 -20
- package/package.json +7 -6
- package/dist/components/panel/Panel.d.ts +0 -9
- package/dist/components/panel/Panel.js +0 -17
- package/dist/components/panel/Panel.styles.d.ts +0 -1
- package/dist/components/panel/Panel.styles.js +0 -12
- package/dist/components/panel/index.d.ts +0 -7
- package/dist/integrations/react/UPanel.d.ts +0 -8
- package/dist/integrations/react/UPanel.js +0 -10
- package/dist/internals/icon-helpers.d.ts +0 -32
- package/dist/internals/icon-helpers.js +0 -48
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { nothing, html } from 'lit';
|
|
2
2
|
import { query, state, property } from 'lit/decorators.js';
|
|
3
3
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
4
4
|
import { live } from 'lit/directives/live.js';
|
|
@@ -19,14 +19,14 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
19
19
|
class Input extends BaseElement {
|
|
20
20
|
constructor() {
|
|
21
21
|
super(...arguments);
|
|
22
|
-
this.showPassword = false;
|
|
23
22
|
this.isInvalid = false;
|
|
24
23
|
this.currentValidationMessage = "";
|
|
24
|
+
this.showPassword = false;
|
|
25
25
|
this.type = "text";
|
|
26
26
|
this.required = false;
|
|
27
|
+
this.readonly = false;
|
|
27
28
|
this.disabled = false;
|
|
28
29
|
this.clearable = false;
|
|
29
|
-
this.readonly = false;
|
|
30
30
|
this.spellcheck = false;
|
|
31
31
|
this.value = "";
|
|
32
32
|
/** input 이벤트 핸들러 */
|
|
@@ -40,26 +40,28 @@ class Input extends BaseElement {
|
|
|
40
40
|
this.emit("u-input", { value: this.value });
|
|
41
41
|
};
|
|
42
42
|
/** change 이벤트 핸들러 */
|
|
43
|
-
this.
|
|
43
|
+
this.handleInputChange = (e) => {
|
|
44
44
|
const input = e.target;
|
|
45
45
|
this.value = input.value;
|
|
46
46
|
this.emit("u-change", { value: this.value });
|
|
47
47
|
};
|
|
48
48
|
/** blur 이벤트 핸들러 */
|
|
49
|
-
this.
|
|
49
|
+
this.handleInputBlur = () => {
|
|
50
50
|
this.validate();
|
|
51
51
|
};
|
|
52
|
-
/** 클리어 버튼 클릭 핸들러 */
|
|
53
|
-
this.handleClear = (e) => {
|
|
54
|
-
e.stopPropagation();
|
|
55
|
-
this.clear();
|
|
56
|
-
};
|
|
57
52
|
/** 비밀번호 표시/숨김 토글 핸들러 */
|
|
58
|
-
this.
|
|
53
|
+
this.handlePasswordTogglerClick = (e) => {
|
|
54
|
+
e.preventDefault();
|
|
59
55
|
e.stopPropagation();
|
|
60
56
|
this.showPassword = !this.showPassword;
|
|
61
57
|
this.focus();
|
|
62
58
|
};
|
|
59
|
+
/** 클리어 버튼 클릭 핸들러 */
|
|
60
|
+
this.handleClearBtnClick = (e) => {
|
|
61
|
+
e.preventDefault();
|
|
62
|
+
e.stopPropagation();
|
|
63
|
+
this.clear();
|
|
64
|
+
};
|
|
63
65
|
}
|
|
64
66
|
static {
|
|
65
67
|
this.styles = [super.styles, styles];
|
|
@@ -72,21 +74,34 @@ class Input extends BaseElement {
|
|
|
72
74
|
}
|
|
73
75
|
updated(changedProperties) {
|
|
74
76
|
super.updated(changedProperties);
|
|
75
|
-
if (changedProperties.has("value") && this.
|
|
76
|
-
if (this.
|
|
77
|
-
this.
|
|
77
|
+
if (changedProperties.has("value") && this.inputEl) {
|
|
78
|
+
if (this.inputEl.value !== this.value) {
|
|
79
|
+
this.inputEl.value = this.value;
|
|
78
80
|
}
|
|
79
81
|
}
|
|
80
82
|
}
|
|
81
83
|
render() {
|
|
82
84
|
return html`
|
|
83
|
-
|
|
85
|
+
<div class="header" ?hidden=${!this.label}>
|
|
86
|
+
${this.required ? html`<span class="required-mark">*</span>` : nothing}
|
|
87
|
+
|
|
88
|
+
<label class="label" @click=${this.focus}>
|
|
89
|
+
${this.label}
|
|
90
|
+
</label>
|
|
91
|
+
|
|
92
|
+
${this.labelhelp ? html`
|
|
93
|
+
<u-icon class="help-icon" lib="internal" name="info-circle-fill"></u-icon>
|
|
94
|
+
<u-tooltip class="help-tooltip" trigger-selectors=".help-icon" placement="right-end">
|
|
95
|
+
${this.labelhelp}
|
|
96
|
+
</u-tooltip>` : nothing}
|
|
97
|
+
</div>
|
|
84
98
|
|
|
85
99
|
<div class="container"
|
|
86
100
|
?invalid=${this.isInvalid}
|
|
87
101
|
?disabled=${this.disabled}
|
|
88
102
|
?readonly=${this.readonly}>
|
|
89
|
-
|
|
103
|
+
|
|
104
|
+
<slot name="prefix"></slot>
|
|
90
105
|
|
|
91
106
|
<input part="input"
|
|
92
107
|
type=${this.type === "password" && this.showPassword ? "text" : this.type}
|
|
@@ -94,33 +109,37 @@ class Input extends BaseElement {
|
|
|
94
109
|
?required=${this.required}
|
|
95
110
|
?disabled=${this.disabled}
|
|
96
111
|
?readonly=${this.readonly}
|
|
97
|
-
placeholder=${ifDefined(this.placeholder)}
|
|
98
112
|
minlength=${ifDefined(this.minlength)}
|
|
99
113
|
maxlength=${ifDefined(this.maxlength)}
|
|
100
114
|
spellcheck=${this.spellcheck}
|
|
101
115
|
autocomplete=${ifDefined(this.autocomplete)}
|
|
116
|
+
placeholder=${ifDefined(this.placeholder)}
|
|
102
117
|
pattern=${ifDefined(this.pattern)}
|
|
103
118
|
.value=${live(this.value)}
|
|
104
119
|
@input=${this.handleInput}
|
|
105
|
-
@change=${this.
|
|
106
|
-
@blur=${this.
|
|
120
|
+
@change=${this.handleInputChange}
|
|
121
|
+
@blur=${this.handleInputBlur}
|
|
107
122
|
/>
|
|
108
123
|
|
|
109
|
-
<slot name="suffix"
|
|
124
|
+
<slot name="suffix"></slot>
|
|
110
125
|
|
|
111
126
|
<div class="tools">
|
|
112
|
-
<u-icon
|
|
127
|
+
<u-icon
|
|
128
|
+
lib="internal"
|
|
129
|
+
name=${this.showPassword ? "eye-slash" : "eye"}
|
|
113
130
|
?hidden=${this.type !== "password" || this.disabled || this.readonly}
|
|
114
|
-
@click=${this.
|
|
131
|
+
@click=${this.handlePasswordTogglerClick}
|
|
115
132
|
></u-icon>
|
|
116
|
-
<u-icon
|
|
133
|
+
<u-icon
|
|
134
|
+
lib="internal"
|
|
135
|
+
name="x-lg"
|
|
117
136
|
?hidden=${!this.clearable || !this.value || this.disabled || this.readonly}
|
|
118
|
-
@click=${this.
|
|
137
|
+
@click=${this.handleClearBtnClick}
|
|
119
138
|
></u-icon>
|
|
120
139
|
</div>
|
|
121
140
|
</div>
|
|
122
141
|
|
|
123
|
-
<div class="validation-
|
|
142
|
+
<div class="validation-message" ?hidden=${!this.currentValidationMessage}>
|
|
124
143
|
${this.currentValidationMessage}
|
|
125
144
|
</div>
|
|
126
145
|
|
|
@@ -129,30 +148,13 @@ class Input extends BaseElement {
|
|
|
129
148
|
</div>
|
|
130
149
|
`;
|
|
131
150
|
}
|
|
132
|
-
/** 라벨 영역을 렌더링합니다. */
|
|
133
|
-
renderHeader() {
|
|
134
|
-
if (!this.label) return nothing;
|
|
135
|
-
return html`
|
|
136
|
-
<div class="header">
|
|
137
|
-
<label class="label" @click=${this.focus}>
|
|
138
|
-
${this.label}
|
|
139
|
-
${this.required ? html`<span class="required-mark">*</span>` : ""}
|
|
140
|
-
</label>
|
|
141
|
-
|
|
142
|
-
${this.labelhelp ? html`
|
|
143
|
-
<u-icon class="help-icon" name="info-circle-fill"></u-icon>
|
|
144
|
-
<u-tooltip trigger-selectors=".help-icon" placement="right-end">${this.labelhelp}</u-tooltip>
|
|
145
|
-
` : nothing}
|
|
146
|
-
</div>
|
|
147
|
-
`;
|
|
148
|
-
}
|
|
149
151
|
/** 유효성 검사를 수행합니다. */
|
|
150
152
|
validate() {
|
|
151
|
-
if (!this.
|
|
152
|
-
const isValid = this.
|
|
153
|
+
if (!this.inputEl) return true;
|
|
154
|
+
const isValid = this.inputEl.checkValidity();
|
|
153
155
|
this.isInvalid = !isValid;
|
|
154
156
|
if (!isValid) {
|
|
155
|
-
this.currentValidationMessage = this.validationMessage || this.
|
|
157
|
+
this.currentValidationMessage = this.validationMessage || this.inputEl.validationMessage;
|
|
156
158
|
} else {
|
|
157
159
|
this.currentValidationMessage = "";
|
|
158
160
|
}
|
|
@@ -164,29 +166,28 @@ class Input extends BaseElement {
|
|
|
164
166
|
this.isInvalid = false;
|
|
165
167
|
this.currentValidationMessage = "";
|
|
166
168
|
this.focus();
|
|
167
|
-
this.emit("u-clear");
|
|
168
169
|
}
|
|
169
170
|
/** 입력 필드에 포커스를 설정합니다. */
|
|
170
171
|
focus() {
|
|
171
|
-
this.
|
|
172
|
+
this.inputEl?.focus();
|
|
172
173
|
}
|
|
173
174
|
/** 입력 필드의 포커스를 해제합니다. */
|
|
174
175
|
blur() {
|
|
175
|
-
this.
|
|
176
|
+
this.inputEl?.blur();
|
|
176
177
|
}
|
|
177
178
|
}
|
|
178
179
|
__decorateClass([
|
|
179
180
|
query("input")
|
|
180
|
-
], Input.prototype, "
|
|
181
|
-
__decorateClass([
|
|
182
|
-
state()
|
|
183
|
-
], Input.prototype, "showPassword");
|
|
181
|
+
], Input.prototype, "inputEl");
|
|
184
182
|
__decorateClass([
|
|
185
183
|
state()
|
|
186
184
|
], Input.prototype, "isInvalid");
|
|
187
185
|
__decorateClass([
|
|
188
186
|
state()
|
|
189
187
|
], Input.prototype, "currentValidationMessage");
|
|
188
|
+
__decorateClass([
|
|
189
|
+
state()
|
|
190
|
+
], Input.prototype, "showPassword");
|
|
190
191
|
__decorateClass([
|
|
191
192
|
property({ type: String, reflect: true })
|
|
192
193
|
], Input.prototype, "type");
|
|
@@ -195,13 +196,13 @@ __decorateClass([
|
|
|
195
196
|
], Input.prototype, "required");
|
|
196
197
|
__decorateClass([
|
|
197
198
|
property({ type: Boolean, reflect: true })
|
|
198
|
-
], Input.prototype, "
|
|
199
|
+
], Input.prototype, "readonly");
|
|
199
200
|
__decorateClass([
|
|
200
201
|
property({ type: Boolean, reflect: true })
|
|
201
|
-
], Input.prototype, "
|
|
202
|
+
], Input.prototype, "disabled");
|
|
202
203
|
__decorateClass([
|
|
203
204
|
property({ type: Boolean, reflect: true })
|
|
204
|
-
], Input.prototype, "
|
|
205
|
+
], Input.prototype, "clearable");
|
|
205
206
|
__decorateClass([
|
|
206
207
|
property({ type: String })
|
|
207
208
|
], Input.prototype, "name");
|
|
@@ -3,99 +3,98 @@ import { css } from 'lit';
|
|
|
3
3
|
const styles = css`
|
|
4
4
|
:host {
|
|
5
5
|
display: inline-block;
|
|
6
|
+
color: var(--u-txt-color);
|
|
6
7
|
font-size: inherit;
|
|
8
|
+
font-family: var(--u-font-base);
|
|
7
9
|
}
|
|
8
10
|
:host([disabled]) {
|
|
9
|
-
opacity: 0.
|
|
11
|
+
opacity: 0.6;
|
|
12
|
+
cursor: not-allowed;
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
/* 헤더 영역 */
|
|
13
16
|
.header {
|
|
14
17
|
display: flex;
|
|
18
|
+
flex-direction: row;
|
|
15
19
|
align-items: center;
|
|
16
|
-
gap: 0.375em;
|
|
17
20
|
margin-bottom: 0.5em;
|
|
21
|
+
user-select: none;
|
|
18
22
|
}
|
|
19
23
|
.header .label {
|
|
20
24
|
font-size: 0.8em;
|
|
21
25
|
font-weight: 500;
|
|
22
|
-
line-height: 1;
|
|
23
|
-
color: var(--u-text-color);
|
|
24
|
-
user-select: none;
|
|
26
|
+
line-height: 1.2;
|
|
25
27
|
cursor: pointer;
|
|
26
28
|
}
|
|
27
29
|
.header .required-mark {
|
|
28
30
|
color: var(--u-red-600);
|
|
29
|
-
margin-
|
|
31
|
+
margin-right: 0.25em;
|
|
30
32
|
}
|
|
31
33
|
.header .help-icon {
|
|
32
34
|
font-size: 0.8em;
|
|
35
|
+
margin-left: 0.5em;
|
|
33
36
|
cursor: help;
|
|
34
37
|
}
|
|
38
|
+
.header .help-tooltip {
|
|
39
|
+
font-size: 0.6em;
|
|
40
|
+
}
|
|
35
41
|
|
|
36
42
|
/* 입력 래퍼 */
|
|
37
43
|
.container {
|
|
38
44
|
display: flex;
|
|
45
|
+
flex-direction: row;
|
|
39
46
|
align-items: center;
|
|
40
|
-
|
|
41
|
-
padding: 0.5em 0.75em;
|
|
42
|
-
background-color: var(--u-bg-color);
|
|
47
|
+
padding: 0.3em 0.6em;
|
|
43
48
|
border: 1px solid var(--u-input-border-color);
|
|
44
|
-
border-radius: 0.
|
|
49
|
+
border-radius: 0.25em;
|
|
50
|
+
background-color: var(--u-input-bg-color);
|
|
45
51
|
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
|
46
52
|
}
|
|
47
|
-
.container[
|
|
48
|
-
border-color: var(--u-red-600);
|
|
49
|
-
}
|
|
50
|
-
.container[invalid]:focus-within {
|
|
51
|
-
box-shadow: 0 0 0 0.125em rgba(244, 67, 54, 0.1);
|
|
52
|
-
}
|
|
53
|
+
.container[readonly],
|
|
53
54
|
.container[disabled] {
|
|
54
|
-
background-color: var(--u-bg-color-disabled);
|
|
55
55
|
border-color: var(--u-border-color-weak);
|
|
56
|
-
|
|
56
|
+
background-color: var(--u-bg-color-disabled);
|
|
57
57
|
}
|
|
58
|
-
.container[readonly] {
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
.container:hover:not([readonly]):not([disabled]) {
|
|
59
|
+
box-shadow:
|
|
60
|
+
0 0 0 1px var(--u-input-border-color-hover),
|
|
61
|
+
0 0 0 3px rgba(59, 130, 246, 0.12);
|
|
61
62
|
}
|
|
62
|
-
.container:
|
|
63
|
-
|
|
63
|
+
.container:focus-within:not([readonly]):not([disabled]) {
|
|
64
|
+
box-shadow:
|
|
65
|
+
0 0 0 1px var(--u-input-border-color-focus),
|
|
66
|
+
0 0 0 3px rgba(59, 130, 246, 0.22);
|
|
64
67
|
}
|
|
65
|
-
.container:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
.container[invalid]:not([readonly]):not([disabled]) {
|
|
69
|
+
box-shadow:
|
|
70
|
+
0 0 0 1px var(--u-input-border-color-invalid),
|
|
71
|
+
0 0 0 3px rgba(220, 38, 38, 0.12);
|
|
69
72
|
}
|
|
70
73
|
|
|
71
74
|
/* 입력 필드 */
|
|
72
75
|
input {
|
|
73
|
-
flex: 1;
|
|
76
|
+
flex: 1 1 auto;
|
|
74
77
|
min-width: 0;
|
|
75
|
-
|
|
76
|
-
background: transparent;
|
|
77
|
-
outline: none;
|
|
78
|
-
font-family: inherit;
|
|
78
|
+
all: unset;
|
|
79
79
|
font-size: 1em;
|
|
80
80
|
line-height: 1.5;
|
|
81
|
-
color: var(--u-text-color);
|
|
82
|
-
padding: 0;
|
|
83
81
|
}
|
|
84
82
|
input::placeholder {
|
|
85
|
-
color: var(--u-
|
|
83
|
+
color: var(--u-txt-color-weak);
|
|
86
84
|
}
|
|
87
85
|
input:disabled {
|
|
88
86
|
cursor: not-allowed;
|
|
89
|
-
color: var(--u-text-color-disabled);
|
|
90
87
|
}
|
|
91
88
|
input:read-only {
|
|
92
89
|
cursor: default;
|
|
93
90
|
}
|
|
94
91
|
|
|
95
|
-
/*
|
|
96
|
-
::slotted([slot="prefix"])
|
|
92
|
+
/* 슬롯에 내용이 있을 때 gap 적용 */
|
|
93
|
+
::slotted([slot="prefix"]) {
|
|
94
|
+
margin-right: 0.5em;
|
|
95
|
+
}
|
|
97
96
|
::slotted([slot="suffix"]) {
|
|
98
|
-
|
|
97
|
+
margin-left: 0.5em;
|
|
99
98
|
}
|
|
100
99
|
|
|
101
100
|
/* Tools 영역 (clear, password toggle 등) */
|
|
@@ -103,42 +102,41 @@ const styles = css`
|
|
|
103
102
|
display: flex;
|
|
104
103
|
flex-direction: row;
|
|
105
104
|
align-items: center;
|
|
106
|
-
gap: 0.375em;
|
|
107
105
|
}
|
|
108
|
-
.
|
|
109
|
-
font-size: 1.125em;
|
|
106
|
+
.tools u-icon {
|
|
110
107
|
color: var(--u-icon-color);
|
|
108
|
+
font-size: 1em;
|
|
109
|
+
margin-left: 0.5em;
|
|
111
110
|
transition: color 0.2s ease;
|
|
112
111
|
cursor: pointer;
|
|
113
112
|
}
|
|
114
|
-
.
|
|
113
|
+
.tools u-icon:hover {
|
|
115
114
|
color: var(--u-icon-color-hover);
|
|
116
115
|
}
|
|
117
|
-
.
|
|
116
|
+
.tools u-icon:active {
|
|
118
117
|
color: var(--u-icon-color-active);
|
|
119
118
|
}
|
|
120
119
|
|
|
121
120
|
/* 유효성 검사 에러 메시지 */
|
|
122
|
-
.validation-
|
|
123
|
-
margin-top: 0.
|
|
124
|
-
font-size: 0.8125em;
|
|
121
|
+
.validation-message {
|
|
122
|
+
margin-top: 0.5em;
|
|
125
123
|
color: var(--u-red-600);
|
|
126
|
-
|
|
124
|
+
font-size: 0.75em;
|
|
125
|
+
line-height: 1.2;
|
|
127
126
|
}
|
|
128
127
|
|
|
129
128
|
/* 설명 텍스트 */
|
|
130
129
|
.description {
|
|
131
|
-
margin-top: 0.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
line-height: 1.
|
|
130
|
+
margin-top: 0.5em;
|
|
131
|
+
color: var(--u-txt-color-weak);
|
|
132
|
+
font-size: 0.75em;
|
|
133
|
+
line-height: 1.2;
|
|
135
134
|
}
|
|
136
135
|
|
|
137
|
-
/*
|
|
136
|
+
/* input 기본 제공 스타일 초기화 */
|
|
138
137
|
input[type="number"] {
|
|
139
138
|
-moz-appearance: textfield;
|
|
140
139
|
}
|
|
141
|
-
/* Number input 스피너 제거 옵션 (선택적) */
|
|
142
140
|
input[type="number"]::-webkit-inner-spin-button,
|
|
143
141
|
input[type="number"]::-webkit-outer-spin-button {
|
|
144
142
|
-webkit-appearance: none;
|
|
@@ -34,7 +34,7 @@ class ProgressBar extends BaseElement {
|
|
|
34
34
|
this.progressState = this.indeterminate ? "indeterminate" : "turned-on";
|
|
35
35
|
}
|
|
36
36
|
if (changedProperties.has("minValue") || changedProperties.has("maxValue") || changedProperties.has("value")) {
|
|
37
|
-
this.
|
|
37
|
+
this.updateProgressState();
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
render() {
|
|
@@ -48,7 +48,7 @@ class ProgressBar extends BaseElement {
|
|
|
48
48
|
`;
|
|
49
49
|
}
|
|
50
50
|
/** 내부 진행 상태 업데이트 */
|
|
51
|
-
async
|
|
51
|
+
async updateProgressState() {
|
|
52
52
|
await this.updateComplete;
|
|
53
53
|
if (this.indeterminate) return;
|
|
54
54
|
const range = this.maxValue - this.minValue;
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import { css } from 'lit';
|
|
2
2
|
|
|
3
3
|
const styles = css`
|
|
4
|
+
:host {
|
|
5
|
+
--progress-value: 0;
|
|
6
|
+
}
|
|
7
|
+
|
|
4
8
|
:host {
|
|
5
9
|
position: relative;
|
|
6
10
|
display: block;
|
|
7
11
|
width: 100%;
|
|
8
|
-
height:
|
|
12
|
+
height: 1em;
|
|
9
13
|
border-radius: 9999px;
|
|
10
14
|
background-color: var(--u-neutral-200);
|
|
11
15
|
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
12
16
|
overflow: hidden;
|
|
13
|
-
|
|
14
|
-
--progress-value: 0;
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
.indicator {
|
|
18
20
|
position: absolute;
|
|
19
21
|
inset: 0 0 0 0;
|
|
20
22
|
display: block;
|
|
21
|
-
width: 100%;
|
|
22
|
-
height: 100%;
|
|
23
23
|
border-radius: inherit;
|
|
24
24
|
background-color: var(--u-blue-600);
|
|
25
25
|
transform-origin: left center;
|
|
@@ -47,14 +47,14 @@ const styles = css`
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
.content {
|
|
50
|
-
position:
|
|
51
|
-
z-index:
|
|
50
|
+
position: absolute;
|
|
51
|
+
z-index: 100;
|
|
52
52
|
display: flex;
|
|
53
|
+
inset: 0 0 0 0;
|
|
53
54
|
align-items: center;
|
|
54
55
|
justify-content: center;
|
|
55
|
-
font-size:
|
|
56
|
-
line-height:
|
|
57
|
-
color: var(--u-neutral-800);
|
|
56
|
+
font-size: 0.5em;
|
|
57
|
+
line-height: 1em;
|
|
58
58
|
white-space: nowrap;
|
|
59
59
|
user-select: none;
|
|
60
60
|
pointer-events: none;
|
|
@@ -9,8 +9,8 @@ export type ProgressRingVariant = 'smooth' | 'blocks' | 'ticks';
|
|
|
9
9
|
export declare class ProgressRing extends BaseElement {
|
|
10
10
|
static styles: import('lit').CSSResultGroup[];
|
|
11
11
|
static dependencies: Record<string, typeof BaseElement>;
|
|
12
|
-
progress: number;
|
|
13
12
|
dasharray: string;
|
|
13
|
+
progress: number;
|
|
14
14
|
/** 진행 표시기의 스타일 변형을 설정합니다. */
|
|
15
15
|
variant: ProgressRingVariant;
|
|
16
16
|
/** 진행 표시기의 최소값을 설정합니다. */
|
|
@@ -24,7 +24,7 @@ export declare class ProgressRing extends BaseElement {
|
|
|
24
24
|
/**
|
|
25
25
|
* 진행 상태를 0과 1 사이의 값으로 반환합니다.
|
|
26
26
|
*/
|
|
27
|
-
private
|
|
27
|
+
private updateProgressState;
|
|
28
28
|
/**
|
|
29
29
|
* variant에 따라 dasharray 값을 반환합니다.
|
|
30
30
|
* [dash-length] [gap-length] or [dash-length] 형식
|
|
@@ -16,8 +16,8 @@ const PATH_LENGTH = 100;
|
|
|
16
16
|
class ProgressRing extends BaseElement {
|
|
17
17
|
constructor() {
|
|
18
18
|
super(...arguments);
|
|
19
|
-
this.progress = 0;
|
|
20
19
|
this.dasharray = PATH_LENGTH.toString();
|
|
20
|
+
this.progress = 0;
|
|
21
21
|
this.variant = "smooth";
|
|
22
22
|
this.minValue = 0;
|
|
23
23
|
this.maxValue = 100;
|
|
@@ -35,7 +35,7 @@ class ProgressRing extends BaseElement {
|
|
|
35
35
|
this.updateDashArray();
|
|
36
36
|
}
|
|
37
37
|
if (changedProperties.has("minValue") || changedProperties.has("maxValue") || changedProperties.has("value")) {
|
|
38
|
-
this.
|
|
38
|
+
this.updateProgressState();
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
render() {
|
|
@@ -48,6 +48,7 @@ class ProgressRing extends BaseElement {
|
|
|
48
48
|
stroke="white"
|
|
49
49
|
stroke-dasharray="${PATH_LENGTH}"
|
|
50
50
|
stroke-dashoffset="${PATH_LENGTH * (1 - this.progress)}"
|
|
51
|
+
stroke-linecap=${this.variant === "smooth" ? "round" : "butt"}
|
|
51
52
|
></circle>
|
|
52
53
|
</mask>
|
|
53
54
|
</defs>
|
|
@@ -65,14 +66,14 @@ class ProgressRing extends BaseElement {
|
|
|
65
66
|
></circle>
|
|
66
67
|
</svg>
|
|
67
68
|
<div class="label" part="label">
|
|
68
|
-
${Math.round(this.progress * 100)}%
|
|
69
|
+
${Math.round(this.progress * 100)} %
|
|
69
70
|
</div>
|
|
70
71
|
`;
|
|
71
72
|
}
|
|
72
73
|
/**
|
|
73
74
|
* 진행 상태를 0과 1 사이의 값으로 반환합니다.
|
|
74
75
|
*/
|
|
75
|
-
|
|
76
|
+
updateProgressState() {
|
|
76
77
|
const range = this.maxValue - this.minValue;
|
|
77
78
|
const clampedValue = Math.max(this.minValue, Math.min(this.maxValue, this.value));
|
|
78
79
|
this.progress = range === 0 ? 0 : (clampedValue - this.minValue) / range;
|
|
@@ -93,10 +94,10 @@ class ProgressRing extends BaseElement {
|
|
|
93
94
|
}
|
|
94
95
|
__decorateClass([
|
|
95
96
|
state()
|
|
96
|
-
], ProgressRing.prototype, "
|
|
97
|
+
], ProgressRing.prototype, "dasharray");
|
|
97
98
|
__decorateClass([
|
|
98
99
|
state()
|
|
99
|
-
], ProgressRing.prototype, "
|
|
100
|
+
], ProgressRing.prototype, "progress");
|
|
100
101
|
__decorateClass([
|
|
101
102
|
property({ type: String, reflect: true })
|
|
102
103
|
], ProgressRing.prototype, "variant");
|
|
@@ -2,20 +2,19 @@ import { css } from 'lit';
|
|
|
2
2
|
|
|
3
3
|
const styles = css`
|
|
4
4
|
:host {
|
|
5
|
-
position: relative;
|
|
6
|
-
display: inline-flex;
|
|
7
|
-
font-size: inherit;
|
|
8
|
-
|
|
9
5
|
--track-width: 0.25em;
|
|
10
6
|
--track-color: var(--u-neutral-200, #e5e7eb);
|
|
11
7
|
--indicator-color: var(--u-blue-600, #3b82f6);
|
|
12
8
|
}
|
|
13
|
-
|
|
14
|
-
:host
|
|
15
|
-
|
|
9
|
+
|
|
10
|
+
:host {
|
|
11
|
+
position: relative;
|
|
12
|
+
display: inline-flex;
|
|
13
|
+
font-size: inherit;
|
|
16
14
|
}
|
|
17
15
|
|
|
18
16
|
.progress-ring {
|
|
17
|
+
position: relative;
|
|
19
18
|
width: 6em;
|
|
20
19
|
height: 6em;
|
|
21
20
|
transform: rotate(-90deg); /* 0%가 위에서 시작하도록 회전 */
|
|
@@ -39,12 +38,12 @@ const styles = css`
|
|
|
39
38
|
/* 라벨 중앙 숫자 */
|
|
40
39
|
.label {
|
|
41
40
|
position: absolute;
|
|
42
|
-
inset: 0;
|
|
41
|
+
inset: 0 0 0 0;
|
|
43
42
|
display: flex;
|
|
44
43
|
align-items: center;
|
|
45
44
|
justify-content: center;
|
|
46
45
|
font-weight: 600;
|
|
47
|
-
font-size:
|
|
46
|
+
font-size: 1em;
|
|
48
47
|
color: var(--indicator-color);
|
|
49
48
|
pointer-events: none;
|
|
50
49
|
}
|
|
@@ -2,14 +2,16 @@ import { css } from 'lit';
|
|
|
2
2
|
|
|
3
3
|
const styles = css`
|
|
4
4
|
:host {
|
|
5
|
-
display: inline-flex;
|
|
6
|
-
font-size: inherit;
|
|
7
|
-
|
|
8
5
|
--track-width: 0.125em;
|
|
9
6
|
--track-color: var(--u-neutral-200, #e5e7eb);
|
|
10
7
|
--indicator-color: var(--u-neutral-800, #1f2937);
|
|
11
8
|
}
|
|
12
9
|
|
|
10
|
+
:host {
|
|
11
|
+
display: inline-flex;
|
|
12
|
+
font-size: inherit;
|
|
13
|
+
}
|
|
14
|
+
|
|
13
15
|
.spinner {
|
|
14
16
|
flex: 1 1 auto;
|
|
15
17
|
width: 1em;
|