@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
|
@@ -3,142 +3,140 @@ 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
|
-
/*
|
|
102
|
-
.
|
|
100
|
+
/* 툴 영역 (clear, password toggle 등) */
|
|
101
|
+
.suffix-items {
|
|
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
|
+
.suffix-items 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
|
+
.suffix-items u-icon:hover {
|
|
115
114
|
color: var(--u-icon-color-hover);
|
|
116
115
|
}
|
|
117
|
-
.
|
|
116
|
+
.suffix-items 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;
|
|
@@ -1,36 +1,25 @@
|
|
|
1
1
|
import { PropertyValues } from 'lit';
|
|
2
2
|
import { BaseElement } from '../BaseElement.js';
|
|
3
|
-
/**
|
|
4
|
-
* Menu 컴포넌트는 일반적인 메뉴 컨테이너입니다.
|
|
5
|
-
* MenuItem 컴포넌트를 자식으로 포함하여 메뉴를 구성합니다.
|
|
6
|
-
*/
|
|
7
3
|
export declare class Menu extends BaseElement {
|
|
8
4
|
static styles: import('lit').CSSResultGroup[];
|
|
9
5
|
static dependencies: Record<string, typeof BaseElement>;
|
|
10
|
-
/** 슬롯에 할당된 메뉴 항목들을 가져옵니다. */
|
|
11
6
|
private items;
|
|
12
|
-
/** 메뉴가 열려있는지 여부입니다. */
|
|
13
7
|
open: boolean;
|
|
14
|
-
/** 메뉴 항목 중 하나만 선택할 수 있는지 여부입니다. */
|
|
15
8
|
selectable: boolean;
|
|
16
|
-
/** 현재 선택된 메뉴 항목의 값입니다. */
|
|
17
9
|
value: string;
|
|
18
10
|
connectedCallback(): void;
|
|
19
11
|
disconnectedCallback(): void;
|
|
20
12
|
protected updated(changedProperties: PropertyValues): void;
|
|
21
13
|
render(): import('lit-html').TemplateResult<1>;
|
|
22
|
-
/** 메뉴를 표시합니다. */
|
|
23
14
|
show: () => Promise<void>;
|
|
24
|
-
/** 메뉴를 숨깁니다. */
|
|
25
15
|
hide: () => Promise<void>;
|
|
26
|
-
/**
|
|
16
|
+
/** (추가) 첫 번째 활성 아이템 포커스 */
|
|
17
|
+
focusFirstItem: () => Promise<void>;
|
|
27
18
|
private updateOpenState;
|
|
28
|
-
/** 선택 상태를 업데이트합니다. */
|
|
29
19
|
private updateSelection;
|
|
30
|
-
/** 슬롯 변경 이벤트를 처리합니다. */
|
|
31
20
|
private handleSlotChange;
|
|
32
|
-
/** 메뉴 항목 선택 이벤트를 처리합니다. */
|
|
33
21
|
private handleSelect;
|
|
34
|
-
/**
|
|
22
|
+
/** 같은 레벨 다른 submenu 닫기 */
|
|
23
|
+
private handleSubmenuOpen;
|
|
35
24
|
private handleKeydown;
|
|
36
25
|
}
|
|
@@ -19,27 +19,23 @@ class Menu extends BaseElement {
|
|
|
19
19
|
this.open = false;
|
|
20
20
|
this.selectable = false;
|
|
21
21
|
this.value = "";
|
|
22
|
-
/** 메뉴를 표시합니다. */
|
|
23
22
|
this.show = async () => {
|
|
24
23
|
await this.updateComplete;
|
|
25
|
-
requestAnimationFrame(() =>
|
|
26
|
-
this.open = true;
|
|
27
|
-
});
|
|
24
|
+
requestAnimationFrame(() => this.open = true);
|
|
28
25
|
};
|
|
29
|
-
/** 메뉴를 숨깁니다. */
|
|
30
26
|
this.hide = async () => {
|
|
31
27
|
await this.updateComplete;
|
|
32
|
-
requestAnimationFrame(() =>
|
|
33
|
-
|
|
34
|
-
|
|
28
|
+
requestAnimationFrame(() => this.open = false);
|
|
29
|
+
};
|
|
30
|
+
/** (추가) 첫 번째 활성 아이템 포커스 */
|
|
31
|
+
this.focusFirstItem = async () => {
|
|
32
|
+
await this.updateComplete;
|
|
33
|
+
const enabled = (this.items || []).filter((i) => !i.disabled);
|
|
34
|
+
if (enabled.length) enabled[0].focus();
|
|
35
35
|
};
|
|
36
|
-
/** 슬롯 변경 이벤트를 처리합니다. */
|
|
37
36
|
this.handleSlotChange = () => {
|
|
38
|
-
if (this.selectable && this.value)
|
|
39
|
-
this.updateSelection();
|
|
40
|
-
}
|
|
37
|
+
if (this.selectable && this.value) this.updateSelection();
|
|
41
38
|
};
|
|
42
|
-
/** 메뉴 항목 선택 이벤트를 처리합니다. */
|
|
43
39
|
this.handleSelect = (e) => {
|
|
44
40
|
const event = e;
|
|
45
41
|
const menuItem = e.target;
|
|
@@ -48,9 +44,16 @@ class Menu extends BaseElement {
|
|
|
48
44
|
this.updateSelection();
|
|
49
45
|
}
|
|
50
46
|
};
|
|
51
|
-
/**
|
|
52
|
-
this.
|
|
53
|
-
const
|
|
47
|
+
/** 같은 레벨 다른 submenu 닫기 */
|
|
48
|
+
this.handleSubmenuOpen = (e) => {
|
|
49
|
+
const openedItem = e.detail?.item;
|
|
50
|
+
if (!openedItem) return;
|
|
51
|
+
(this.items || []).forEach((item) => {
|
|
52
|
+
if (item !== openedItem) item.closeSubmenu?.();
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
this.handleKeydown = async (e) => {
|
|
56
|
+
const items = (this.items || []).filter((item) => !item.disabled);
|
|
54
57
|
if (items.length === 0) return;
|
|
55
58
|
const currentIndex = items.findIndex((item) => item === e.target);
|
|
56
59
|
let nextIndex = currentIndex;
|
|
@@ -76,14 +79,29 @@ class Menu extends BaseElement {
|
|
|
76
79
|
case "Enter":
|
|
77
80
|
case " ":
|
|
78
81
|
e.preventDefault();
|
|
79
|
-
if (currentIndex >= 0)
|
|
80
|
-
|
|
82
|
+
if (currentIndex >= 0) items[currentIndex].click();
|
|
83
|
+
break;
|
|
84
|
+
case "ArrowLeft": {
|
|
85
|
+
const parentItem = this.parentElement;
|
|
86
|
+
if (parentItem?.tagName?.toLowerCase() === "u-menu-item") {
|
|
87
|
+
e.preventDefault();
|
|
88
|
+
parentItem.closeSubmenu?.();
|
|
89
|
+
parentItem.focus?.();
|
|
81
90
|
}
|
|
82
91
|
break;
|
|
83
|
-
|
|
92
|
+
}
|
|
93
|
+
case "Escape": {
|
|
84
94
|
e.preventDefault();
|
|
85
|
-
this.
|
|
95
|
+
const parentItem = this.parentElement;
|
|
96
|
+
if (parentItem?.tagName?.toLowerCase() === "u-menu-item") {
|
|
97
|
+
parentItem.closeSubmenu?.();
|
|
98
|
+
parentItem.focus?.();
|
|
99
|
+
} else {
|
|
100
|
+
this.emit("u-request-close");
|
|
101
|
+
await this.hide();
|
|
102
|
+
}
|
|
86
103
|
break;
|
|
104
|
+
}
|
|
87
105
|
}
|
|
88
106
|
};
|
|
89
107
|
}
|
|
@@ -100,10 +118,12 @@ class Menu extends BaseElement {
|
|
|
100
118
|
this.setAttribute("role", "menu");
|
|
101
119
|
this.addEventListener("u-select", this.handleSelect);
|
|
102
120
|
this.addEventListener("keydown", this.handleKeydown);
|
|
121
|
+
this.addEventListener("u-submenu-open", this.handleSubmenuOpen);
|
|
103
122
|
}
|
|
104
123
|
disconnectedCallback() {
|
|
105
124
|
this.removeEventListener("u-select", this.handleSelect);
|
|
106
125
|
this.removeEventListener("keydown", this.handleKeydown);
|
|
126
|
+
this.removeEventListener("u-submenu-open", this.handleSubmenuOpen);
|
|
107
127
|
super.disconnectedCallback();
|
|
108
128
|
}
|
|
109
129
|
updated(changedProperties) {
|
|
@@ -122,17 +142,12 @@ class Menu extends BaseElement {
|
|
|
122
142
|
</div>
|
|
123
143
|
`;
|
|
124
144
|
}
|
|
125
|
-
/** open 상태가 변경될 때 호출됩니다. */
|
|
126
145
|
updateOpenState(open) {
|
|
127
|
-
if (open)
|
|
128
|
-
|
|
129
|
-
} else {
|
|
130
|
-
this.emit("u-hide");
|
|
131
|
-
}
|
|
146
|
+
if (open) this.emit("u-show");
|
|
147
|
+
else this.emit("u-hide");
|
|
132
148
|
}
|
|
133
|
-
/** 선택 상태를 업데이트합니다. */
|
|
134
149
|
updateSelection() {
|
|
135
|
-
this.items.forEach((item) => {
|
|
150
|
+
(this.items || []).forEach((item) => {
|
|
136
151
|
item.selected = item.value === this.value;
|
|
137
152
|
});
|
|
138
153
|
}
|
|
@@ -2,31 +2,19 @@ import { css } from 'lit';
|
|
|
2
2
|
|
|
3
3
|
const styles = css`
|
|
4
4
|
:host {
|
|
5
|
-
display:
|
|
6
|
-
width: max-content;
|
|
5
|
+
display: none;
|
|
7
6
|
min-width: 180px;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
transition: opacity 0.2s ease, transform 0.2s ease;
|
|
13
|
-
pointer-events: none;
|
|
7
|
+
padding: 6px;
|
|
8
|
+
border-radius: 8px;
|
|
9
|
+
background: var(--u-menu-bg, #fff);
|
|
10
|
+
box-shadow: 0 10px 24px rgba(0,0,0,0.18);
|
|
14
11
|
}
|
|
15
12
|
:host([open]) {
|
|
16
|
-
|
|
17
|
-
transform: scale(1);
|
|
18
|
-
pointer-events: auto;
|
|
13
|
+
display: block;
|
|
19
14
|
}
|
|
20
15
|
|
|
21
16
|
.container {
|
|
22
|
-
display:
|
|
23
|
-
flex-direction: column;
|
|
24
|
-
gap: 2px;
|
|
25
|
-
padding: 4px;
|
|
26
|
-
border: 1px solid var(--u-border-color, #ddd);
|
|
27
|
-
border-radius: 8px;
|
|
28
|
-
background-color: var(--u-bg-color, #fff);
|
|
29
|
-
overflow: auto;
|
|
17
|
+
display: block;
|
|
30
18
|
}
|
|
31
19
|
`;
|
|
32
20
|
|
|
@@ -1,27 +1,36 @@
|
|
|
1
1
|
import { PropertyValues } from 'lit';
|
|
2
2
|
import { BaseElement } from '../BaseElement.js';
|
|
3
|
-
/**
|
|
4
|
-
* MenuItem 컴포넌트는 메뉴의 개별 항목을 나타냅니다.
|
|
5
|
-
* u-menu 및 u-context-menu와 함께 사용됩니다.
|
|
6
|
-
*/
|
|
7
3
|
export declare class MenuItem extends BaseElement {
|
|
8
4
|
static styles: import('lit').CSSResultGroup[];
|
|
9
5
|
static dependencies: Record<string, typeof BaseElement>;
|
|
10
|
-
/** 메뉴 항목이 비활성화 상태인지 여부입니다. */
|
|
11
6
|
disabled: boolean;
|
|
12
|
-
/** 메뉴 항목이 선택된 상태인지 여부입니다. */
|
|
13
7
|
selected: boolean;
|
|
14
|
-
/** 체크 가능한 경우, 체크 상태인지 여부입니다. */
|
|
15
8
|
checked: boolean;
|
|
16
|
-
/** 메뉴 항목에 체크 표시를 할 수 있는지 여부입니다. */
|
|
17
9
|
checkable: boolean;
|
|
18
|
-
/** 메뉴 항목의 값입니다. */
|
|
19
10
|
value: string;
|
|
11
|
+
private submenuOpen;
|
|
12
|
+
private containerEl;
|
|
13
|
+
private submenuList;
|
|
14
|
+
private submenuCleanup;
|
|
15
|
+
private closeTimer;
|
|
16
|
+
private get submenu();
|
|
20
17
|
connectedCallback(): void;
|
|
21
|
-
|
|
18
|
+
disconnectedCallback(): void;
|
|
19
|
+
protected updated(changed: PropertyValues): void;
|
|
20
|
+
private updateRole;
|
|
22
21
|
render(): import('lit-html').TemplateResult<1>;
|
|
23
|
-
/** 메뉴 항목의 앞부분을 렌더링합니다. */
|
|
24
22
|
private renderPrefixItem;
|
|
25
|
-
/**
|
|
23
|
+
/** 외부에서 호출 가능하게(부모 menu가 형제 submenu 닫을 때 사용) */
|
|
24
|
+
closeSubmenu: () => Promise<void>;
|
|
25
|
+
private openSubmenu;
|
|
26
|
+
private onSubmenuSelect;
|
|
27
|
+
private scheduleCloseSubmenu;
|
|
28
|
+
private stopSubmenuAutoUpdate;
|
|
29
|
+
private positionSubmenu;
|
|
30
|
+
private onPointerEnter;
|
|
31
|
+
private onPointerLeave;
|
|
32
|
+
private onFocusIn;
|
|
33
|
+
private onFocusOut;
|
|
34
|
+
private handleKeydown;
|
|
26
35
|
private handleClick;
|
|
27
36
|
}
|