@iyulab/components 0.1.4 → 0.1.6
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/CHANGELOG.md +18 -18
- package/LICENSE +20 -20
- package/README.md +33 -33
- package/dist/assets/icons/arrow-clockwise.svg.js +1 -1
- package/dist/assets/icons/arrow-down.svg.js +1 -1
- package/dist/assets/icons/arrow-up.svg.js +1 -1
- package/dist/assets/icons/ban.svg.js +1 -1
- package/dist/assets/icons/bell-fill.svg.js +1 -1
- package/dist/assets/icons/check-circle-fill.svg.js +1 -1
- package/dist/assets/icons/check-lg.svg.js +1 -1
- package/dist/assets/icons/chevron-down.svg.js +1 -1
- package/dist/assets/icons/chevron-left.svg.js +1 -1
- package/dist/assets/icons/chevron-right.svg.js +1 -1
- package/dist/assets/icons/chevron-up.svg.js +1 -1
- package/dist/assets/icons/copy.svg.js +1 -1
- package/dist/assets/icons/dash-lg.svg.js +1 -1
- package/dist/assets/icons/exclamation-circle-fill.svg.js +1 -1
- package/dist/assets/icons/exclamation-triangle-fill.svg.js +1 -1
- package/dist/assets/icons/eye-slash.svg.js +1 -1
- package/dist/assets/icons/eye.svg.js +1 -1
- package/dist/assets/icons/info-circle-fill.svg.js +1 -1
- package/dist/assets/icons/layout-sidebar.svg.js +1 -1
- package/dist/assets/icons/lightbulb-fill.svg.js +1 -1
- package/dist/assets/icons/lightbulb-off.svg.js +1 -1
- package/dist/assets/icons/lightbulb.svg.js +1 -1
- package/dist/assets/icons/mic-fill.svg.js +1 -1
- package/dist/assets/icons/mic-mute-fill.svg.js +1 -1
- package/dist/assets/icons/paperclip.svg.js +1 -1
- package/dist/assets/icons/pencil-square.svg.js +1 -1
- package/dist/assets/icons/plus-lg.svg.js +1 -1
- package/dist/assets/icons/search.svg.js +1 -1
- package/dist/assets/icons/speedometer.svg.js +1 -1
- package/dist/assets/icons/x-lg.svg.js +1 -1
- package/dist/assets/styles/dark.css +129 -125
- package/dist/assets/styles/dark.css.js +1 -1
- package/dist/assets/styles/light.css +129 -126
- package/dist/assets/styles/light.css.js +1 -1
- package/dist/components/BaseElement.styles.js +2 -2
- package/dist/components/FloatingElement.d.ts +84 -0
- package/dist/components/FloatingElement.js +166 -0
- package/dist/components/FloatingElement.styles.js +26 -0
- 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/ContextMenu.d.ts +20 -39
- package/dist/components/context-menu/ContextMenu.js +92 -137
- package/dist/components/context-menu/ContextMenu.styles.js +3 -28
- package/dist/components/context-menu/index.d.ts +1 -1
- 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/Dialog.d.ts +14 -7
- package/dist/components/dialog/Dialog.js +88 -27
- package/dist/components/dialog/Dialog.styles.js +60 -11
- package/dist/components/dialog/index.js +5 -0
- package/dist/components/divider/Divider.d.ts +10 -10
- package/dist/components/divider/Divider.js +32 -32
- package/dist/components/divider/Divider.styles.js +10 -10
- package/dist/components/divider/index.js +5 -0
- package/dist/components/dropdown-menu/DropdownMenu.d.ts +27 -0
- package/dist/components/dropdown-menu/DropdownMenu.js +135 -0
- package/dist/components/dropdown-menu/DropdownMenu.styles.d.ts +1 -0
- package/dist/components/dropdown-menu/DropdownMenu.styles.js +15 -0
- package/dist/components/dropdown-menu/index.d.ts +7 -0
- package/dist/components/dropdown-menu/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 +15 -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 +3 -1
- package/dist/components/input/Input.d.ts +14 -13
- package/dist/components/input/Input.js +57 -56
- package/dist/components/input/Input.styles.js +54 -56
- package/dist/components/input/index.js +5 -0
- package/dist/components/menu/Menu.d.ts +4 -15
- package/dist/components/menu/Menu.js +43 -28
- package/dist/components/menu/Menu.styles.js +7 -19
- package/dist/components/menu/index.js +5 -0
- package/dist/components/menu-item/MenuItem.d.ts +21 -12
- package/dist/components/menu-item/MenuItem.js +184 -15
- package/dist/components/menu-item/MenuItem.styles.js +6 -0
- package/dist/components/menu-item/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 +11 -3
- package/dist/components/split-panel/SplitPanel.js +44 -27
- package/dist/components/split-panel/SplitPanel.styles.js +1 -16
- package/dist/components/split-panel/index.js +5 -0
- package/dist/components/tooltip/Tooltip.d.ts +9 -29
- package/dist/components/tooltip/Tooltip.js +27 -149
- package/dist/components/tooltip/Tooltip.styles.js +9 -23
- 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 +28 -5
- package/dist/integrations/react/UDropdownMenu.d.ts +8 -0
- package/dist/integrations/react/UDropdownMenu.js +10 -0
- package/dist/integrations/react/index.d.ts +1 -1
- package/dist/integrations/react/index.js +1 -1
- package/dist/internals/index.d.ts +0 -1
- package/dist/internals/node-helpers.d.ts +6 -1
- package/dist/internals/node-helpers.js +5 -6
- 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 +59 -58
- package/dist/components/panel/Panel.d.ts +0 -9
- package/dist/components/panel/Panel.js +0 -17
- 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
- /package/dist/components/{panel/Panel.styles.d.ts → FloatingElement.styles.d.ts} +0 -0
|
@@ -51,7 +51,9 @@ class Form extends BaseElement {
|
|
|
51
51
|
<slot></slot>
|
|
52
52
|
`;
|
|
53
53
|
}
|
|
54
|
-
/**
|
|
54
|
+
/**
|
|
55
|
+
* 폼 내의 모든 입력 요소를 검증합니다.
|
|
56
|
+
*/
|
|
55
57
|
validate() {
|
|
56
58
|
const slot = this.shadowRoot?.querySelector("slot");
|
|
57
59
|
const inputEls = slot?.assignedElements({ flatten: true }).filter((el) => el instanceof Input) || [];
|
|
@@ -6,24 +6,18 @@ export declare class Icon extends BaseElement {
|
|
|
6
6
|
static styles: import('lit').CSSResultGroup[];
|
|
7
7
|
static dependencies: Record<string, typeof BaseElement>;
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* -
|
|
12
|
-
*
|
|
9
|
+
* 사용할 아이콘 라이브러리를 지정합니다.
|
|
10
|
+
*
|
|
11
|
+
* - 기본 내장: "internal" | "default"
|
|
12
|
+
* - 사용자 확장 라이브러리: icons.register()로 등록한 라이브러리 이름
|
|
13
|
+
* @default "default"
|
|
13
14
|
*/
|
|
14
|
-
|
|
15
|
+
library: "internal" | "default" | (string & {});
|
|
15
16
|
/**
|
|
16
17
|
* 사용할 아이콘의 이름을 지정합니다.
|
|
17
|
-
* @description 외부에서 불러오는 SVG 아이콘인 경우, 이름은 파일명(확장자 제외)이어야 합니다.
|
|
18
18
|
*/
|
|
19
19
|
name?: string;
|
|
20
20
|
render(): import('lit-html/directive.js').DirectiveResult<typeof import('lit-html/directives/until.js').UntilDirective>;
|
|
21
|
-
/**
|
|
22
|
-
* 아이콘의 HTML 콘텐츠를 가져옵니다.
|
|
23
|
-
* 외부 아이콘 경로를 사용하거나, 내부 레지스트리에서 아이콘을 찾습니다.
|
|
24
|
-
* @param name 아이콘 이름
|
|
25
|
-
*/
|
|
26
|
-
private load;
|
|
27
21
|
/**
|
|
28
22
|
* SVG 콘텐츠가 유효한 HTML인지 검사합니다.
|
|
29
23
|
*/
|
|
@@ -3,7 +3,7 @@ import { property } from 'lit/decorators.js';
|
|
|
3
3
|
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
|
4
4
|
import { until } from 'lit/directives/until.js';
|
|
5
5
|
import { BaseElement } from '../BaseElement.js';
|
|
6
|
-
import {
|
|
6
|
+
import { icons } from '../../utilities/icons.js';
|
|
7
7
|
import { styles } from './Icon.styles.js';
|
|
8
8
|
|
|
9
9
|
var __defProp = Object.defineProperty;
|
|
@@ -18,7 +18,7 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
18
18
|
class Icon extends BaseElement {
|
|
19
19
|
constructor() {
|
|
20
20
|
super(...arguments);
|
|
21
|
-
this.
|
|
21
|
+
this.library = "default";
|
|
22
22
|
}
|
|
23
23
|
static {
|
|
24
24
|
this.styles = [super.styles, styles];
|
|
@@ -28,44 +28,29 @@ class Icon extends BaseElement {
|
|
|
28
28
|
}
|
|
29
29
|
render() {
|
|
30
30
|
if (!this.name) return nothing;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return unsafeHTML(html);
|
|
31
|
+
console.log(this.library, this.name, "icon render");
|
|
32
|
+
return until(icons.resolve(this.library, this.name).then((html) => {
|
|
33
|
+
return this.validate(html) ? unsafeHTML(html) : nothing;
|
|
34
34
|
}), nothing);
|
|
35
35
|
}
|
|
36
|
-
/**
|
|
37
|
-
* 아이콘의 HTML 콘텐츠를 가져옵니다.
|
|
38
|
-
* 외부 아이콘 경로를 사용하거나, 내부 레지스트리에서 아이콘을 찾습니다.
|
|
39
|
-
* @param name 아이콘 이름
|
|
40
|
-
*/
|
|
41
|
-
async load(name) {
|
|
42
|
-
if (this.remote) {
|
|
43
|
-
const baseUrl = getBaseUrl();
|
|
44
|
-
const remoteUrl = baseUrl.endsWith("/") ? `${baseUrl}${name}.svg` : `${baseUrl}/${name}.svg`;
|
|
45
|
-
try {
|
|
46
|
-
const response = await fetch(remoteUrl);
|
|
47
|
-
if (!response.ok) return void 0;
|
|
48
|
-
return (await response.text())?.trim();
|
|
49
|
-
} catch (error) {
|
|
50
|
-
console.error(error);
|
|
51
|
-
return void 0;
|
|
52
|
-
}
|
|
53
|
-
} else {
|
|
54
|
-
return iconBundle.get(name)?.trim();
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
36
|
/**
|
|
58
37
|
* SVG 콘텐츠가 유효한 HTML인지 검사합니다.
|
|
59
38
|
*/
|
|
60
39
|
validate(html) {
|
|
61
40
|
if (!html) return false;
|
|
62
|
-
|
|
63
|
-
|
|
41
|
+
const trimmed = html.trim();
|
|
42
|
+
try {
|
|
43
|
+
const doc = new DOMParser().parseFromString(trimmed, "image/svg+xml");
|
|
44
|
+
if (doc.querySelector("parsererror")) return false;
|
|
45
|
+
return doc.documentElement?.tagName.toLowerCase() === "svg";
|
|
46
|
+
} catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
64
49
|
}
|
|
65
50
|
}
|
|
66
51
|
__decorateClass([
|
|
67
|
-
property({ type:
|
|
68
|
-
], Icon.prototype, "
|
|
52
|
+
property({ type: String, attribute: "lib" })
|
|
53
|
+
], Icon.prototype, "library");
|
|
69
54
|
__decorateClass([
|
|
70
55
|
property({ type: String })
|
|
71
56
|
], Icon.prototype, "name");
|
|
@@ -5,14 +5,14 @@ import { BaseElement } from '../BaseElement.js';
|
|
|
5
5
|
export declare class IconButton extends BaseElement {
|
|
6
6
|
static styles: import('lit').CSSResultGroup[];
|
|
7
7
|
static dependencies: Record<string, typeof BaseElement>;
|
|
8
|
-
/** 경계선이 없는
|
|
8
|
+
/** 경계선이 없는 스타일을 적용합니다. */
|
|
9
9
|
borderless: boolean;
|
|
10
10
|
/** 버튼이 비활성화 상태인지 여부를 설정합니다. 비활성화된 버튼은 클릭할 수 없습니다. */
|
|
11
11
|
disabled: boolean;
|
|
12
12
|
/** 버튼이 로딩 상태인지 여부를 설정합니다. 로딩 중에는 버튼이 비활성화되고 스피너가 표시됩니다. */
|
|
13
13
|
loading: boolean;
|
|
14
|
-
/**
|
|
15
|
-
|
|
14
|
+
/** 아이콘 라이브러리를 지정합니다. */
|
|
15
|
+
library: "internal" | "default" | (string & {});
|
|
16
16
|
/** 아이콘의 이름을 지정합니다. */
|
|
17
17
|
name?: string;
|
|
18
18
|
render(): import('lit-html').TemplateResult<1>;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { html } from 'lit';
|
|
2
2
|
import { property } from 'lit/decorators.js';
|
|
3
|
-
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
4
3
|
import { BaseElement } from '../BaseElement.js';
|
|
5
4
|
import { Spinner } from '../spinner/Spinner.js';
|
|
6
5
|
import { Icon } from '../icon/Icon.js';
|
|
@@ -21,7 +20,7 @@ class IconButton extends BaseElement {
|
|
|
21
20
|
this.borderless = false;
|
|
22
21
|
this.disabled = false;
|
|
23
22
|
this.loading = false;
|
|
24
|
-
this.
|
|
23
|
+
this.library = "default";
|
|
25
24
|
}
|
|
26
25
|
static {
|
|
27
26
|
this.styles = [super.styles, styles];
|
|
@@ -34,8 +33,9 @@ class IconButton extends BaseElement {
|
|
|
34
33
|
}
|
|
35
34
|
render() {
|
|
36
35
|
return html`
|
|
37
|
-
<button part="base"
|
|
38
|
-
|
|
36
|
+
<button part="base"
|
|
37
|
+
?disabled=${this.disabled || this.loading}>
|
|
38
|
+
${this.loading ? html`<u-spinner></u-spinner>` : html`<u-icon .library=${this.library} .name=${this.name}></u-icon>`}
|
|
39
39
|
</button>
|
|
40
40
|
`;
|
|
41
41
|
}
|
|
@@ -50,8 +50,8 @@ __decorateClass([
|
|
|
50
50
|
property({ type: Boolean, reflect: true })
|
|
51
51
|
], IconButton.prototype, "loading");
|
|
52
52
|
__decorateClass([
|
|
53
|
-
property({ type:
|
|
54
|
-
], IconButton.prototype, "
|
|
53
|
+
property({ type: String, attribute: "lib" })
|
|
54
|
+
], IconButton.prototype, "library");
|
|
55
55
|
__decorateClass([
|
|
56
56
|
property({ type: String })
|
|
57
57
|
], IconButton.prototype, "name");
|
|
@@ -6,63 +6,48 @@ const styles = css`
|
|
|
6
6
|
display: inline-flex;
|
|
7
7
|
|
|
8
8
|
font-size: 16px;
|
|
9
|
-
color: var(--u-icon-color);
|
|
10
9
|
padding: 0.5em;
|
|
11
|
-
|
|
10
|
+
color: var(--u-icon-color);
|
|
12
11
|
border: 1px solid var(--u-border-color);
|
|
13
12
|
border-radius: 6px;
|
|
13
|
+
background-color: var(--u-bg-color);
|
|
14
14
|
|
|
15
15
|
transition: all 0.2s ease;
|
|
16
16
|
user-select: none;
|
|
17
17
|
cursor: pointer;
|
|
18
18
|
}
|
|
19
|
-
:host([borderless]) {
|
|
20
|
-
border: none;
|
|
21
|
-
background-color: transparent;
|
|
22
|
-
}
|
|
23
|
-
:host([borderless]:hover) {
|
|
24
|
-
border: none;
|
|
25
|
-
background-color: transparent;
|
|
26
|
-
}
|
|
27
|
-
:host([borderless]:active) {
|
|
28
|
-
border: none;
|
|
29
|
-
background-color: transparent;
|
|
30
|
-
}
|
|
31
|
-
:host([loading]),
|
|
32
|
-
:host([disabled]) {
|
|
33
|
-
pointer-events: none;
|
|
34
|
-
}
|
|
35
|
-
:host([disabled]) {
|
|
36
|
-
opacity: 0.6;
|
|
37
|
-
color: var(--u-icon-color-disabled);
|
|
38
|
-
}
|
|
39
19
|
:host(:hover) {
|
|
40
20
|
color: var(--u-icon-color-hover);
|
|
41
21
|
background-color: var(--u-bg-color-hover);
|
|
42
|
-
border-color: var(--u-border-color-strong);
|
|
43
22
|
}
|
|
44
23
|
:host(:active) {
|
|
45
24
|
color: var(--u-icon-color-active);
|
|
46
25
|
background-color: var(--u-bg-color-active);
|
|
47
26
|
transform: translateY(1px);
|
|
48
27
|
}
|
|
28
|
+
:host([borderless]) {
|
|
29
|
+
border: none;
|
|
30
|
+
background-color: transparent;
|
|
31
|
+
}
|
|
32
|
+
:host([loading]),
|
|
33
|
+
:host([disabled]) {
|
|
34
|
+
color: var(--u-icon-color-disabled);
|
|
35
|
+
pointer-events: none;
|
|
36
|
+
}
|
|
49
37
|
|
|
50
38
|
button {
|
|
51
39
|
all: unset;
|
|
52
40
|
display: inline-flex;
|
|
53
|
-
align-items: center;
|
|
54
|
-
justify-content: center;
|
|
55
41
|
}
|
|
56
42
|
button:focus-visible {
|
|
57
43
|
outline: 2px solid var(--u-blue-500, #3b82f6);
|
|
58
44
|
outline-offset: 2px;
|
|
59
|
-
border-radius: inherit;
|
|
60
45
|
}
|
|
61
46
|
|
|
62
|
-
u-
|
|
63
|
-
u-
|
|
64
|
-
font-size: inherit;
|
|
47
|
+
u-spinner,
|
|
48
|
+
u-icon {
|
|
65
49
|
color: inherit;
|
|
50
|
+
font-size: inherit;
|
|
66
51
|
}
|
|
67
52
|
`;
|
|
68
53
|
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
export * from './alert';
|
|
2
2
|
export * from './button';
|
|
3
3
|
export * from './context-menu';
|
|
4
|
+
export * from './copy-button';
|
|
4
5
|
export * from './dialog';
|
|
5
6
|
export * from './divider';
|
|
7
|
+
export * from './dropdown-menu';
|
|
6
8
|
export * from './form';
|
|
7
9
|
export * from './icon';
|
|
8
10
|
export * from './icon-button';
|
|
9
11
|
export * from './input';
|
|
10
12
|
export * from './menu';
|
|
11
|
-
export * from './
|
|
13
|
+
export * from './menu-item';
|
|
12
14
|
export * from './progress-bar';
|
|
13
15
|
export * from './progress-ring';
|
|
14
16
|
export * from './spinner';
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { PropertyValues } from 'lit';
|
|
2
2
|
import { BaseElement } from '../BaseElement.js';
|
|
3
|
+
/** 지원하는 input 타입 */
|
|
4
|
+
type InputType = ('text' | 'password' | 'email' | 'tel' | 'url' | 'search' | 'number' | 'date' | 'time' | 'datetime-local' | 'month' | 'week');
|
|
3
5
|
/**
|
|
4
6
|
* Input 컴포넌트는 사용자 입력을 받는 텍스트 입력 필드입니다.
|
|
5
7
|
* prefix, suffix 슬롯과 라벨, 도움말, 유효성 검사 등의 기능을 제공합니다.
|
|
@@ -7,23 +9,23 @@ import { BaseElement } from '../BaseElement.js';
|
|
|
7
9
|
export declare class Input extends BaseElement {
|
|
8
10
|
static styles: import('lit').CSSResultGroup[];
|
|
9
11
|
static dependencies: Record<string, typeof BaseElement>;
|
|
10
|
-
|
|
11
|
-
/** password type인 경우 비밀번호 표시/숨김 상태 */
|
|
12
|
-
showPassword: boolean;
|
|
12
|
+
inputEl: HTMLInputElement;
|
|
13
13
|
/** 유효성 검사 실패 여부 */
|
|
14
14
|
isInvalid: boolean;
|
|
15
15
|
/** 현재 표시할 유효성 검사 메시지 */
|
|
16
16
|
currentValidationMessage: string;
|
|
17
|
+
/** password type인 경우 비밀번호 표시/숨김 상태 */
|
|
18
|
+
showPassword: boolean;
|
|
17
19
|
/** input 요소의 type 속성 */
|
|
18
|
-
type:
|
|
20
|
+
type: InputType;
|
|
19
21
|
/** 필수 입력 여부 */
|
|
20
22
|
required: boolean;
|
|
23
|
+
/** 읽기 전용 여부 */
|
|
24
|
+
readonly: boolean;
|
|
21
25
|
/** 비활성화 여부 */
|
|
22
26
|
disabled: boolean;
|
|
23
27
|
/** 클리어 버튼 표시 여부 */
|
|
24
28
|
clearable: boolean;
|
|
25
|
-
/** 읽기 전용 여부 */
|
|
26
|
-
readonly: boolean;
|
|
27
29
|
/** input 요소의 name 속성 */
|
|
28
30
|
name?: string;
|
|
29
31
|
/** 라벨 텍스트 */
|
|
@@ -50,8 +52,6 @@ export declare class Input extends BaseElement {
|
|
|
50
52
|
validationMessage?: string;
|
|
51
53
|
protected updated(changedProperties: PropertyValues): void;
|
|
52
54
|
render(): import('lit-html').TemplateResult<1>;
|
|
53
|
-
/** 라벨 영역을 렌더링합니다. */
|
|
54
|
-
private renderHeader;
|
|
55
55
|
/** 유효성 검사를 수행합니다. */
|
|
56
56
|
validate(): boolean;
|
|
57
57
|
/** 입력값을 초기화합니다. */
|
|
@@ -63,11 +63,12 @@ export declare class Input extends BaseElement {
|
|
|
63
63
|
/** input 이벤트 핸들러 */
|
|
64
64
|
private handleInput;
|
|
65
65
|
/** change 이벤트 핸들러 */
|
|
66
|
-
private
|
|
66
|
+
private handleInputChange;
|
|
67
67
|
/** blur 이벤트 핸들러 */
|
|
68
|
-
private
|
|
69
|
-
/** 클리어 버튼 클릭 핸들러 */
|
|
70
|
-
private handleClear;
|
|
68
|
+
private handleInputBlur;
|
|
71
69
|
/** 비밀번호 표시/숨김 토글 핸들러 */
|
|
72
|
-
private
|
|
70
|
+
private handlePasswordTogglerClick;
|
|
71
|
+
/** 클리어 버튼 클릭 핸들러 */
|
|
72
|
+
private handleClearBtnClick;
|
|
73
73
|
}
|
|
74
|
+
export {};
|
|
@@ -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
|
-
<div class="
|
|
112
|
-
<u-icon
|
|
126
|
+
<div class="suffix-items">
|
|
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");
|