@iyulab/components 0.1.10 → 0.2.0
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 +52 -0
- package/dist/assets/icons/arrow-repeat.svg.js +3 -0
- package/dist/assets/icons/box-arrow-up-right.svg.js +3 -0
- package/dist/assets/icons/file-earmark.svg.js +3 -0
- package/dist/assets/icons/flag.svg.js +3 -0
- package/dist/assets/icons/globe.svg.js +3 -0
- package/dist/assets/icons/hand-thumbs-down-fill.svg.js +3 -0
- package/dist/assets/icons/hand-thumbs-down.svg.js +3 -0
- package/dist/assets/icons/hand-thumbs-up-fill.svg.js +3 -0
- package/dist/assets/icons/hand-thumbs-up.svg.js +3 -0
- package/dist/assets/icons/share.svg.js +3 -0
- package/dist/assets/icons/stop-circle.svg.js +3 -0
- package/dist/assets/icons/tools.svg.js +3 -0
- package/dist/components/FloatingElement.d.ts +13 -5
- package/dist/components/FloatingElement.js +32 -15
- package/dist/components/FloatingElement.styles.js +0 -4
- package/dist/components/button/UButton.component.d.ts +7 -0
- package/dist/components/button/UButton.component.js +20 -1
- package/dist/components/button/UButton.styles.js +51 -8
- package/dist/components/dialog/UDialog.component.d.ts +2 -0
- package/dist/components/dialog/UDialog.component.js +14 -9
- package/dist/components/divider/UDivider.component.d.ts +3 -18
- package/dist/components/divider/UDivider.component.js +3 -62
- package/dist/components/divider/UDivider.styles.js +11 -43
- package/dist/components/drawer/UDrawer.component.d.ts +2 -0
- package/dist/components/drawer/UDrawer.component.js +14 -9
- package/dist/components/form/UForm.component.js +3 -3
- package/dist/components/icon/UIcon.component.d.ts +4 -1
- package/dist/components/icon/UIcon.component.js +2 -2
- package/dist/components/menu/UMenu.component.d.ts +4 -7
- package/dist/components/menu/UMenu.component.js +94 -83
- package/dist/components/menu/UMenu.styles.js +1 -1
- package/dist/components/menu-item/UMenuItem.component.d.ts +10 -4
- package/dist/components/menu-item/UMenuItem.component.js +37 -26
- package/dist/components/menu-item/UMenuItem.styles.js +4 -4
- package/dist/components/split-panel/USplitPanel.component.d.ts +22 -8
- package/dist/components/split-panel/USplitPanel.component.js +121 -75
- package/dist/components/split-panel/USplitPanel.styles.js +30 -0
- package/dist/components/tag/UTag.component.d.ts +23 -0
- package/dist/components/tag/UTag.component.js +72 -0
- package/dist/components/tag/UTag.d.ts +8 -0
- package/dist/components/tag/UTag.js +5 -0
- package/dist/components/tag/UTag.styles.js +83 -0
- package/dist/components/tooltip/UTooltip.component.d.ts +8 -0
- package/dist/components/tooltip/UTooltip.component.js +59 -17
- package/dist/components/tooltip/UTooltip.styles.js +15 -0
- package/dist/components/tree-item/UTreeItem.component.d.ts +16 -8
- package/dist/components/tree-item/UTreeItem.component.js +69 -31
- package/dist/components/tree-item/UTreeItem.styles.js +8 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +5 -4
- package/dist/react-components/UTag.d.ts +8 -0
- package/dist/react-components/UTag.js +10 -0
- package/dist/react-components/index.d.ts +1 -1
- package/dist/react-components/index.js +1 -1
- package/dist/utilities/{icons.d.ts → IconRegistry.d.ts} +20 -26
- package/dist/utilities/{icons.js → IconRegistry.js} +29 -20
- package/dist/utilities/{notifier.d.ts → Notifier.d.ts} +8 -13
- package/dist/utilities/{notifier.js → Notifier.js} +8 -10
- package/dist/utilities/{theme.d.ts → Theme.d.ts} +14 -20
- package/dist/utilities/{theme.js → Theme.js} +39 -35
- package/dist/{internals/attribute-converters.d.ts → utilities/converters.d.ts} +1 -1
- package/dist/{internals/attribute-converters.js → utilities/converters.js} +2 -2
- package/dist/{internals/node-helpers.js → utilities/elements.js} +6 -5
- package/package.json +7 -7
- package/dist/assets/icons/arrow-clockwise.svg.js +0 -3
- package/dist/assets/icons/speedometer.svg.js +0 -3
- package/dist/components/icon-button/UIconButton.component.d.ts +0 -20
- package/dist/components/icon-button/UIconButton.component.js +0 -59
- package/dist/components/icon-button/UIconButton.d.ts +0 -7
- package/dist/components/icon-button/UIconButton.js +0 -5
- package/dist/components/icon-button/UIconButton.styles.js +0 -54
- package/dist/internals/react-wrapper.d.ts +0 -21
- package/dist/react-components/UIconButton.d.ts +0 -8
- package/dist/react-components/UIconButton.js +0 -10
- /package/dist/components/{icon-button/UIconButton.styles.d.ts → tag/UTag.styles.d.ts} +0 -0
- /package/dist/{internals/node-helpers.d.ts → utilities/elements.d.ts} +0 -0
|
@@ -2,53 +2,21 @@ import { css } from 'lit';
|
|
|
2
2
|
|
|
3
3
|
const styles = css`
|
|
4
4
|
:host {
|
|
5
|
-
--divider-size:
|
|
6
|
-
--
|
|
7
|
-
--
|
|
5
|
+
--divider-size: 1px;
|
|
6
|
+
--divider-color: var(--u-neutral-200, #e5e7eb);
|
|
7
|
+
--divider-spacing: 8px;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
:host {
|
|
11
|
-
position: relative;
|
|
12
|
-
background-color: var(--u-neutral-200, #e5e7eb);
|
|
13
|
-
}
|
|
14
|
-
:host([orientation="horizontal"]) {
|
|
15
|
-
width: var(--divider-size, 2px);
|
|
16
|
-
min-height: 0px;
|
|
17
|
-
}
|
|
18
|
-
:host([orientation="vertical"]) {
|
|
19
|
-
min-width: 0px;
|
|
20
|
-
height: var(--divider-size, 2px);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.handler {
|
|
24
|
-
position: absolute;
|
|
25
|
-
z-index: 100;
|
|
26
11
|
display: block;
|
|
27
|
-
background-color: var(--
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
transform: translateX(-50%);
|
|
36
|
-
width: var(--handler-size, 4px);
|
|
37
|
-
height: 100%;
|
|
38
|
-
cursor: col-resize;
|
|
39
|
-
}
|
|
40
|
-
.handler[orientation="vertical"] {
|
|
41
|
-
left: 0;
|
|
42
|
-
right: 0;
|
|
43
|
-
top: 50%;
|
|
44
|
-
transform: translateY(-50%);
|
|
45
|
-
width: 100%;
|
|
46
|
-
height: var(--handler-size, 4px);
|
|
47
|
-
cursor: row-resize;
|
|
48
|
-
}
|
|
49
|
-
.handler[moving],
|
|
50
|
-
.handler:hover {
|
|
51
|
-
opacity: 1;
|
|
12
|
+
background-color: var(--divider-color);
|
|
13
|
+
height: var(--divider-size);
|
|
14
|
+
margin: var(--divider-spacing) 0;
|
|
15
|
+
}
|
|
16
|
+
:host([vertical]) {
|
|
17
|
+
width: var(--divider-size);
|
|
18
|
+
height: auto;
|
|
19
|
+
margin: 0 var(--divider-spacing);
|
|
52
20
|
}
|
|
53
21
|
`;
|
|
54
22
|
|
|
@@ -10,6 +10,8 @@ export declare class UDrawer extends ModalElement {
|
|
|
10
10
|
static dependencies: Record<string, typeof BaseElement>;
|
|
11
11
|
/** 드로어가 나타나는 위치 */
|
|
12
12
|
placement: DrawerPlacement;
|
|
13
|
+
/** 헤드리스 모드 여부 */
|
|
14
|
+
headless: boolean;
|
|
13
15
|
/** 타이틀 텍스트 */
|
|
14
16
|
heading: string;
|
|
15
17
|
render(): import('lit-html').TemplateResult<1>;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { html } from 'lit';
|
|
2
2
|
import { property } from 'lit/decorators.js';
|
|
3
3
|
import { ModalElement } from '../ModalElement.js';
|
|
4
|
-
import {
|
|
4
|
+
import { UIcon } from '../icon/UIcon.component.js';
|
|
5
|
+
import { UButton } from '../button/UButton.component.js';
|
|
5
6
|
import { styles } from './UDrawer.styles.js';
|
|
6
7
|
|
|
7
8
|
var __defProp = Object.defineProperty;
|
|
@@ -17,6 +18,7 @@ class UDrawer extends ModalElement {
|
|
|
17
18
|
constructor() {
|
|
18
19
|
super(...arguments);
|
|
19
20
|
this.placement = "left";
|
|
21
|
+
this.headless = false;
|
|
20
22
|
this.heading = "";
|
|
21
23
|
}
|
|
22
24
|
static {
|
|
@@ -24,22 +26,22 @@ class UDrawer extends ModalElement {
|
|
|
24
26
|
}
|
|
25
27
|
static {
|
|
26
28
|
this.dependencies = {
|
|
27
|
-
"u-icon
|
|
29
|
+
"u-icon": UIcon,
|
|
30
|
+
"u-button": UButton
|
|
28
31
|
};
|
|
29
32
|
}
|
|
30
33
|
render() {
|
|
31
34
|
return html`
|
|
32
35
|
<div class="drawer" part="base" ?open=${this.open} placement=${this.placement}>
|
|
33
|
-
<div class="header" part="header" ?hidden=${
|
|
36
|
+
<div class="header" part="header" ?hidden=${this.headless}>
|
|
34
37
|
<span class="title" part="title">
|
|
35
38
|
${this.heading}
|
|
36
39
|
</span>
|
|
37
|
-
<u-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
name="x-lg"
|
|
41
|
-
|
|
42
|
-
></u-icon-button>
|
|
40
|
+
<u-button class="close-btn" part="close-btn"
|
|
41
|
+
variant="link"
|
|
42
|
+
@click=${() => this.hide()}>
|
|
43
|
+
<u-icon lib="internal" name="x-lg"></u-icon>
|
|
44
|
+
</u-button>
|
|
43
45
|
</div>
|
|
44
46
|
|
|
45
47
|
<div class="content" part="content" scrollable>
|
|
@@ -52,6 +54,9 @@ class UDrawer extends ModalElement {
|
|
|
52
54
|
__decorateClass([
|
|
53
55
|
property({ type: String, reflect: true })
|
|
54
56
|
], UDrawer.prototype, "placement");
|
|
57
|
+
__decorateClass([
|
|
58
|
+
property({ type: Boolean, reflect: true })
|
|
59
|
+
], UDrawer.prototype, "headless");
|
|
55
60
|
__decorateClass([
|
|
56
61
|
property({ type: String })
|
|
57
62
|
], UDrawer.prototype, "heading");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { html } from 'lit';
|
|
2
2
|
import { property } from 'lit/decorators.js';
|
|
3
|
-
import {
|
|
3
|
+
import { arrayAttrConverter } from '../../utilities/converters.js';
|
|
4
4
|
import { BaseElement } from '../BaseElement.js';
|
|
5
5
|
import { UInput } from '../input/UInput.component.js';
|
|
6
6
|
import { styles } from './UForm.styles.js';
|
|
@@ -64,10 +64,10 @@ class UForm extends BaseElement {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
__decorateClass([
|
|
67
|
-
property({ type: Array, converter:
|
|
67
|
+
property({ type: Array, converter: arrayAttrConverter((v) => v) })
|
|
68
68
|
], UForm.prototype, "includes");
|
|
69
69
|
__decorateClass([
|
|
70
|
-
property({ type: Array, converter:
|
|
70
|
+
property({ type: Array, converter: arrayAttrConverter((v) => v) })
|
|
71
71
|
], UForm.prototype, "excludes");
|
|
72
72
|
__decorateClass([
|
|
73
73
|
property({ type: Object, attribute: false })
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { nothing } from 'lit';
|
|
1
2
|
import { BaseElement } from '../BaseElement.js';
|
|
2
3
|
export type IconLibrary = "internal" | "default" | (string & {});
|
|
3
4
|
/**
|
|
@@ -18,7 +19,9 @@ export declare class UIcon extends BaseElement {
|
|
|
18
19
|
* 사용할 아이콘의 이름을 지정합니다.
|
|
19
20
|
*/
|
|
20
21
|
name?: string;
|
|
21
|
-
render(): import('lit-html/directive.js').DirectiveResult<
|
|
22
|
+
render(): import('lit-html/directive.js').DirectiveResult<{
|
|
23
|
+
new (_partInfo: import('lit-html/directive.js').PartInfo): import('lit-html/directives/until.js').UntilDirective<typeof nothing | Promise<import('lit-html/directive.js').DirectiveResult<typeof import('lit-html/directives/unsafe-html.js').UnsafeHTMLDirective>>>;
|
|
24
|
+
}>;
|
|
22
25
|
/**
|
|
23
26
|
* SVG 콘텐츠가 유효한 HTML인지 검사합니다.
|
|
24
27
|
*/
|
|
@@ -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 { IconRegistry } from '../../utilities/IconRegistry.js';
|
|
7
7
|
import { styles } from './UIcon.styles.js';
|
|
8
8
|
|
|
9
9
|
var __defProp = Object.defineProperty;
|
|
@@ -28,7 +28,7 @@ class UIcon extends BaseElement {
|
|
|
28
28
|
}
|
|
29
29
|
render() {
|
|
30
30
|
if (!this.lib || !this.name) return nothing;
|
|
31
|
-
return until(
|
|
31
|
+
return until(IconRegistry.resolve(this.lib, this.name).then((html) => {
|
|
32
32
|
return this.validate(html) ? unsafeHTML(html) : nothing;
|
|
33
33
|
}), nothing);
|
|
34
34
|
}
|
|
@@ -17,7 +17,6 @@ export declare class UMenu extends FloatingElement {
|
|
|
17
17
|
* - default: 일반 메뉴 (수동 제어)
|
|
18
18
|
* - dropdown: 드롭다운 메뉴 (앵커 클릭 시 토글)
|
|
19
19
|
* - contextmenu: 컨텍스트 메뉴 (앵커 우클릭 시 표시)
|
|
20
|
-
* - submenu: 서브메뉴 (앵커 호버/포커스 시 표시)
|
|
21
20
|
*/
|
|
22
21
|
type: MenuType;
|
|
23
22
|
/**
|
|
@@ -57,14 +56,12 @@ export declare class UMenu extends FloatingElement {
|
|
|
57
56
|
private handleWindowFocusOut;
|
|
58
57
|
private handleWindowKeydown;
|
|
59
58
|
private handleWindowPointerDown;
|
|
60
|
-
private handleAnchorPointerEnter;
|
|
61
|
-
private handleAnchorPointerLeave;
|
|
62
|
-
private handleAnchorFocusIn;
|
|
63
|
-
private handleAnchorFocusOut;
|
|
64
59
|
private handleAnchorPointerDown;
|
|
65
60
|
private handleAnchorKeydown;
|
|
66
61
|
private handleAnchorContextMenu;
|
|
67
|
-
|
|
68
|
-
private
|
|
62
|
+
private handleSubmenuAnchorPointerEnter;
|
|
63
|
+
private handleSubmenuAnchorPointerLeave;
|
|
64
|
+
private handleSubmenuAnchorFocusIn;
|
|
65
|
+
private handleSubmenuAnchorFocusOut;
|
|
69
66
|
}
|
|
70
67
|
export {};
|
|
@@ -24,7 +24,7 @@ class UMenu extends FloatingElement {
|
|
|
24
24
|
*/
|
|
25
25
|
this.focusAt = async (index = 0) => {
|
|
26
26
|
await this.updateComplete;
|
|
27
|
-
const items = this.
|
|
27
|
+
const items = this.getItems("enabled");
|
|
28
28
|
const length = items.length;
|
|
29
29
|
if (length === 0) return;
|
|
30
30
|
index = index < 0 ? Math.max(0, length + index) : Math.min(index, length - 1);
|
|
@@ -34,8 +34,10 @@ class UMenu extends FloatingElement {
|
|
|
34
34
|
};
|
|
35
35
|
//#region 기본 이벤트 핸들러
|
|
36
36
|
this.handleClick = async (e) => {
|
|
37
|
-
const item =
|
|
38
|
-
if (!item
|
|
37
|
+
const item = e.target;
|
|
38
|
+
if (!(item instanceof UMenuItem)) return;
|
|
39
|
+
if (item.disabled) return;
|
|
40
|
+
if (item.submenu) return;
|
|
39
41
|
const items = this.getItems("enabled");
|
|
40
42
|
if (!items.includes(item)) return;
|
|
41
43
|
const value = item.value || "";
|
|
@@ -56,8 +58,9 @@ class UMenu extends FloatingElement {
|
|
|
56
58
|
this.emit("u-select", { value });
|
|
57
59
|
};
|
|
58
60
|
this.handleKeydown = async (e) => {
|
|
59
|
-
const item =
|
|
60
|
-
if (!item) return;
|
|
61
|
+
const item = e.target;
|
|
62
|
+
if (!(item instanceof UMenuItem)) return;
|
|
63
|
+
if (item.disabled) return;
|
|
61
64
|
const items = this.getItems("enabled");
|
|
62
65
|
if (!items.includes(item)) return;
|
|
63
66
|
const currentIndex = items.findIndex((i) => i === item);
|
|
@@ -87,18 +90,21 @@ class UMenu extends FloatingElement {
|
|
|
87
90
|
await this.focusAt(nextIndex);
|
|
88
91
|
break;
|
|
89
92
|
case "ArrowLeft":
|
|
90
|
-
e.preventDefault();
|
|
91
|
-
e.stopPropagation();
|
|
92
93
|
if (this.type === "submenu") {
|
|
93
|
-
|
|
94
|
+
e.preventDefault();
|
|
95
|
+
e.stopPropagation();
|
|
96
|
+
await this.hide();
|
|
97
|
+
if (this.target instanceof HTMLElement) {
|
|
98
|
+
this.target.focus();
|
|
99
|
+
}
|
|
94
100
|
}
|
|
95
101
|
break;
|
|
96
102
|
case "ArrowRight":
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
await
|
|
103
|
+
if (item.submenu) {
|
|
104
|
+
e.preventDefault();
|
|
105
|
+
e.stopPropagation();
|
|
106
|
+
await item.submenu.show(item);
|
|
107
|
+
await item.submenu.focusAt(0);
|
|
102
108
|
}
|
|
103
109
|
break;
|
|
104
110
|
}
|
|
@@ -121,51 +127,31 @@ class UMenu extends FloatingElement {
|
|
|
121
127
|
}
|
|
122
128
|
await this.hide();
|
|
123
129
|
} else if (this.type === "dropdown") {
|
|
124
|
-
const
|
|
125
|
-
if (!
|
|
130
|
+
const currentTarget = this.target;
|
|
131
|
+
if (!currentTarget || !(currentTarget instanceof HTMLElement)) return;
|
|
126
132
|
const targets = e.composedPath().filter((v) => v instanceof HTMLElement);
|
|
127
133
|
for (const target of targets) {
|
|
128
|
-
if (this.contains(target) ||
|
|
134
|
+
if (this.contains(target) || currentTarget.contains(target)) return;
|
|
129
135
|
}
|
|
130
136
|
await this.hide();
|
|
131
137
|
}
|
|
132
138
|
};
|
|
133
139
|
//#endregion
|
|
134
|
-
//#region 'submenu' 이벤트 핸들러
|
|
135
|
-
this.handleAnchorPointerEnter = (e) => {
|
|
136
|
-
const item = this.getEnabledItemFrom(e);
|
|
137
|
-
if (!item) return;
|
|
138
|
-
this.show();
|
|
139
|
-
};
|
|
140
|
-
this.handleAnchorPointerLeave = async (e) => {
|
|
141
|
-
const item = this.getEnabledItemFrom(e);
|
|
142
|
-
if (!item) return;
|
|
143
|
-
this.hide();
|
|
144
|
-
};
|
|
145
|
-
this.handleAnchorFocusIn = (e) => {
|
|
146
|
-
const item = this.getEnabledItemFrom(e);
|
|
147
|
-
if (!item) return;
|
|
148
|
-
this.show();
|
|
149
|
-
};
|
|
150
|
-
this.handleAnchorFocusOut = async (e) => {
|
|
151
|
-
const item = this.getEnabledItemFrom(e);
|
|
152
|
-
if (!item) return;
|
|
153
|
-
this.hide();
|
|
154
|
-
};
|
|
155
|
-
//#endregion
|
|
156
140
|
//#region 'dropdown' 이벤트 핸들러
|
|
157
141
|
this.handleAnchorPointerDown = async (e) => {
|
|
158
142
|
if (e.button !== 0) return;
|
|
159
|
-
|
|
143
|
+
const target = e.currentTarget;
|
|
144
|
+
if (this.visible && this.target === target)
|
|
160
145
|
await this.hide();
|
|
161
146
|
else
|
|
162
|
-
await this.show();
|
|
147
|
+
await this.show(target);
|
|
163
148
|
};
|
|
164
149
|
this.handleAnchorKeydown = async (e) => {
|
|
165
150
|
if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") {
|
|
166
151
|
e.preventDefault();
|
|
152
|
+
const target = e.currentTarget;
|
|
167
153
|
if (this.visible) return;
|
|
168
|
-
await this.show();
|
|
154
|
+
await this.show(target);
|
|
169
155
|
}
|
|
170
156
|
};
|
|
171
157
|
//#endregion
|
|
@@ -187,14 +173,40 @@ class UMenu extends FloatingElement {
|
|
|
187
173
|
};
|
|
188
174
|
await this.show(virtual, false);
|
|
189
175
|
};
|
|
176
|
+
//#endregion
|
|
177
|
+
//#region 'submenu' 이벤트 핸들러
|
|
178
|
+
this.handleSubmenuAnchorPointerEnter = (e) => {
|
|
179
|
+
const target = e.currentTarget;
|
|
180
|
+
if (target?.disabled) return;
|
|
181
|
+
this.show(target);
|
|
182
|
+
};
|
|
183
|
+
this.handleSubmenuAnchorPointerLeave = (e) => {
|
|
184
|
+
const related = e.relatedTarget;
|
|
185
|
+
if (related) {
|
|
186
|
+
const target = this.target;
|
|
187
|
+
if (target?.contains(related) || this.contains(related)) return;
|
|
188
|
+
}
|
|
189
|
+
this.hide();
|
|
190
|
+
};
|
|
191
|
+
this.handleSubmenuAnchorFocusIn = (e) => {
|
|
192
|
+
const target = e.currentTarget;
|
|
193
|
+
if (target?.disabled) return;
|
|
194
|
+
this.show(target);
|
|
195
|
+
};
|
|
196
|
+
this.handleSubmenuAnchorFocusOut = (e) => {
|
|
197
|
+
const related = e.relatedTarget;
|
|
198
|
+
if (related) {
|
|
199
|
+
const target = this.target;
|
|
200
|
+
if (target?.contains(related) || this.contains(related)) return;
|
|
201
|
+
}
|
|
202
|
+
this.hide();
|
|
203
|
+
};
|
|
190
204
|
}
|
|
191
205
|
static {
|
|
192
206
|
this.styles = [super.styles, styles];
|
|
193
207
|
}
|
|
194
208
|
static {
|
|
195
|
-
this.dependencies = {
|
|
196
|
-
"u-menu-item": UMenuItem
|
|
197
|
-
};
|
|
209
|
+
this.dependencies = {};
|
|
198
210
|
}
|
|
199
211
|
connectedCallback() {
|
|
200
212
|
super.connectedCallback();
|
|
@@ -208,13 +220,13 @@ class UMenu extends FloatingElement {
|
|
|
208
220
|
}
|
|
209
221
|
willUpdate(changedProperties) {
|
|
210
222
|
super.willUpdate(changedProperties);
|
|
211
|
-
if (changedProperties.has("
|
|
223
|
+
if (changedProperties.has("anchors") || changedProperties.has("type")) {
|
|
212
224
|
const oldType = changedProperties.get("type") || "default";
|
|
213
225
|
const newType = this.type || "default";
|
|
214
|
-
const
|
|
215
|
-
const
|
|
216
|
-
if (
|
|
217
|
-
if (
|
|
226
|
+
const oldAnchors = changedProperties.get("anchors");
|
|
227
|
+
const newAnchors = this.anchors;
|
|
228
|
+
if (oldAnchors) this.unbind(oldType, oldAnchors);
|
|
229
|
+
if (newAnchors) this.bind(newType, newAnchors);
|
|
218
230
|
}
|
|
219
231
|
if (changedProperties.has("mode")) {
|
|
220
232
|
this.clearAll();
|
|
@@ -228,13 +240,12 @@ class UMenu extends FloatingElement {
|
|
|
228
240
|
* 재귀적으로 서브메뉴의 아이템들도 해제됩니다.
|
|
229
241
|
*/
|
|
230
242
|
clearAll() {
|
|
231
|
-
const items = this.
|
|
243
|
+
const items = this.getItems("all");
|
|
232
244
|
for (const item of items) {
|
|
233
245
|
item.selected = false;
|
|
234
246
|
item.checked = false;
|
|
235
|
-
if (item.
|
|
236
|
-
|
|
237
|
-
submenu?.clearAll();
|
|
247
|
+
if (item.submenu) {
|
|
248
|
+
item.submenu.clearAll();
|
|
238
249
|
}
|
|
239
250
|
}
|
|
240
251
|
}
|
|
@@ -245,7 +256,7 @@ class UMenu extends FloatingElement {
|
|
|
245
256
|
* @return 조건에 맞는 아이템들의 배열입니다
|
|
246
257
|
*/
|
|
247
258
|
getItems(filter = "all") {
|
|
248
|
-
const items = this.items || [];
|
|
259
|
+
const items = this.items?.filter((item) => item instanceof UMenuItem) || [];
|
|
249
260
|
switch (filter) {
|
|
250
261
|
case "all":
|
|
251
262
|
return items;
|
|
@@ -266,24 +277,29 @@ class UMenu extends FloatingElement {
|
|
|
266
277
|
}
|
|
267
278
|
}
|
|
268
279
|
/** 앵커에 이벤트 바인딩 */
|
|
269
|
-
bind(type,
|
|
270
|
-
if (type === "
|
|
271
|
-
this.visible = false;
|
|
272
|
-
this.placement ||= "right-start";
|
|
273
|
-
this.offset = -8;
|
|
274
|
-
target.addEventListener("pointerenter", this.handleAnchorPointerEnter);
|
|
275
|
-
target.addEventListener("pointerleave", this.handleAnchorPointerLeave);
|
|
276
|
-
target.addEventListener("focusin", this.handleAnchorFocusIn);
|
|
277
|
-
target.addEventListener("focusout", this.handleAnchorFocusOut);
|
|
278
|
-
} else if (type === "dropdown") {
|
|
280
|
+
bind(type, anchors) {
|
|
281
|
+
if (type === "dropdown") {
|
|
279
282
|
this.visible = false;
|
|
280
283
|
this.placement ||= "bottom-start";
|
|
281
|
-
|
|
282
|
-
|
|
284
|
+
for (const anchor of anchors) {
|
|
285
|
+
anchor.addEventListener("pointerdown", this.handleAnchorPointerDown);
|
|
286
|
+
anchor.addEventListener("keydown", this.handleAnchorKeydown);
|
|
287
|
+
}
|
|
283
288
|
} else if (type === "contextmenu") {
|
|
284
289
|
this.visible = false;
|
|
285
290
|
this.placement ||= "bottom-start";
|
|
286
|
-
|
|
291
|
+
for (const anchor of anchors) {
|
|
292
|
+
anchor.addEventListener("contextmenu", this.handleAnchorContextMenu);
|
|
293
|
+
}
|
|
294
|
+
} else if (type === "submenu") {
|
|
295
|
+
this.visible = false;
|
|
296
|
+
this.placement ||= "right-start";
|
|
297
|
+
for (const anchor of anchors) {
|
|
298
|
+
anchor.addEventListener("pointerenter", this.handleSubmenuAnchorPointerEnter);
|
|
299
|
+
anchor.addEventListener("pointerleave", this.handleSubmenuAnchorPointerLeave);
|
|
300
|
+
anchor.addEventListener("focusin", this.handleSubmenuAnchorFocusIn);
|
|
301
|
+
anchor.addEventListener("focusout", this.handleSubmenuAnchorFocusOut);
|
|
302
|
+
}
|
|
287
303
|
} else {
|
|
288
304
|
this.visible = true;
|
|
289
305
|
return;
|
|
@@ -293,29 +309,24 @@ class UMenu extends FloatingElement {
|
|
|
293
309
|
window.addEventListener("pointerdown", this.handleWindowPointerDown);
|
|
294
310
|
}
|
|
295
311
|
/** 앵커에서 이벤트 바인딩 해제 */
|
|
296
|
-
unbind(_,
|
|
312
|
+
unbind(_, anchors) {
|
|
297
313
|
window.removeEventListener("focusout", this.handleWindowFocusOut);
|
|
298
314
|
window.removeEventListener("keydown", this.handleWindowKeydown);
|
|
299
315
|
window.removeEventListener("pointerdown", this.handleWindowPointerDown);
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
316
|
+
for (const anchor of anchors) {
|
|
317
|
+
anchor.removeEventListener("pointerdown", this.handleAnchorPointerDown);
|
|
318
|
+
anchor.removeEventListener("keydown", this.handleAnchorKeydown);
|
|
319
|
+
anchor.removeEventListener("contextmenu", this.handleAnchorContextMenu);
|
|
320
|
+
anchor.removeEventListener("pointerenter", this.handleSubmenuAnchorPointerEnter);
|
|
321
|
+
anchor.removeEventListener("pointerleave", this.handleSubmenuAnchorPointerLeave);
|
|
322
|
+
anchor.removeEventListener("focusin", this.handleSubmenuAnchorFocusIn);
|
|
323
|
+
anchor.removeEventListener("focusout", this.handleSubmenuAnchorFocusOut);
|
|
324
|
+
}
|
|
307
325
|
}
|
|
308
326
|
//#endregion
|
|
309
|
-
/** 이벤트로부터 활성화된 (비활성화되지 않은) 메뉴 아이템을 반환 */
|
|
310
|
-
getEnabledItemFrom(event) {
|
|
311
|
-
const target = event.target;
|
|
312
|
-
const item = target.closest("u-menu-item");
|
|
313
|
-
if (!item || item.disabled) return null;
|
|
314
|
-
return item;
|
|
315
|
-
}
|
|
316
327
|
}
|
|
317
328
|
__decorateClass([
|
|
318
|
-
queryAssignedElements({ flatten: false
|
|
329
|
+
queryAssignedElements({ flatten: false })
|
|
319
330
|
], UMenu.prototype, "items");
|
|
320
331
|
__decorateClass([
|
|
321
332
|
property({ type: String, reflect: true })
|
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
import { PropertyValues } from 'lit';
|
|
2
2
|
import { BaseElement } from '../BaseElement.js';
|
|
3
|
+
import { UMenu } from '../menu/UMenu.component.js';
|
|
3
4
|
export declare class UMenuItem extends BaseElement {
|
|
4
5
|
static styles: import('lit').CSSResultGroup[];
|
|
5
6
|
static dependencies: Record<string, typeof BaseElement>;
|
|
6
|
-
/**
|
|
7
|
-
|
|
7
|
+
/** 서브메뉴 요소 */
|
|
8
|
+
submenu: UMenu | null;
|
|
8
9
|
/** 비활성화 여부 @default false */
|
|
9
10
|
disabled: boolean;
|
|
11
|
+
/** 로딩 상태 @default false */
|
|
12
|
+
loading: boolean;
|
|
10
13
|
/** 선택 여부(multiple mode) @default false */
|
|
11
14
|
checked: boolean;
|
|
12
15
|
/** 선택 여부(single mode) @default false */
|
|
13
16
|
selected: boolean;
|
|
14
|
-
/** 값 */
|
|
15
|
-
value
|
|
17
|
+
/** 메뉴 아이템 값 */
|
|
18
|
+
value?: string;
|
|
16
19
|
protected updated(changedProperties: PropertyValues): void;
|
|
17
20
|
render(): import('lit-html').TemplateResult<1>;
|
|
21
|
+
/** 기본 슬롯 변경 감지 */
|
|
22
|
+
private handleSlotChange;
|
|
23
|
+
/** submenu 슬롯 변경 감지 */
|
|
18
24
|
private handleSubmenuSlotChange;
|
|
19
25
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { html } from 'lit';
|
|
2
2
|
import { state, property } from 'lit/decorators.js';
|
|
3
3
|
import { BaseElement } from '../BaseElement.js';
|
|
4
|
+
import { UIcon } from '../icon/UIcon.component.js';
|
|
5
|
+
import { UMenu } from '../menu/UMenu.component.js';
|
|
6
|
+
import { USpinner } from '../spinner/USpinner.component.js';
|
|
4
7
|
import { styles } from './UMenuItem.styles.js';
|
|
5
8
|
|
|
6
9
|
var __defProp = Object.defineProperty;
|
|
@@ -15,27 +18,29 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
15
18
|
class UMenuItem extends BaseElement {
|
|
16
19
|
constructor() {
|
|
17
20
|
super(...arguments);
|
|
18
|
-
this.
|
|
21
|
+
this.submenu = null;
|
|
19
22
|
this.disabled = false;
|
|
23
|
+
this.loading = false;
|
|
20
24
|
this.checked = false;
|
|
21
25
|
this.selected = false;
|
|
22
|
-
|
|
26
|
+
/** 기본 슬롯 변경 감지 */
|
|
27
|
+
this.handleSlotChange = (e) => {
|
|
28
|
+
const slot = e.target;
|
|
29
|
+
const elements = slot.assignedElements({ flatten: true });
|
|
30
|
+
const menu = elements.find((el) => el instanceof UMenu);
|
|
31
|
+
menu?.setAttribute("slot", "submenu");
|
|
32
|
+
};
|
|
33
|
+
/** submenu 슬롯 변경 감지 */
|
|
23
34
|
this.handleSubmenuSlotChange = (e) => {
|
|
24
35
|
const slot = e.target;
|
|
25
36
|
const elements = slot.assignedElements({ flatten: true });
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
37
|
+
const menu = elements.find((el) => el instanceof UMenu);
|
|
38
|
+
if (menu) {
|
|
39
|
+
menu.type = "submenu";
|
|
40
|
+
menu.anchors = [this];
|
|
41
|
+
this.submenu = menu;
|
|
29
42
|
} else {
|
|
30
|
-
|
|
31
|
-
if ("anchor" in submenu && "type" in submenu) {
|
|
32
|
-
submenu.anchor = this;
|
|
33
|
-
submenu.type = "submenu";
|
|
34
|
-
this.isNested = true;
|
|
35
|
-
} else {
|
|
36
|
-
console.warn(`the element assigned to the 'submenu' slot is not a valid UMenu component.`);
|
|
37
|
-
this.isNested = false;
|
|
38
|
-
}
|
|
43
|
+
this.submenu = null;
|
|
39
44
|
}
|
|
40
45
|
};
|
|
41
46
|
}
|
|
@@ -43,13 +48,15 @@ class UMenuItem extends BaseElement {
|
|
|
43
48
|
this.styles = [super.styles, styles];
|
|
44
49
|
}
|
|
45
50
|
static {
|
|
46
|
-
this.dependencies = {
|
|
51
|
+
this.dependencies = {
|
|
52
|
+
"u-icon": UIcon,
|
|
53
|
+
"u-spinner": USpinner
|
|
54
|
+
};
|
|
47
55
|
}
|
|
48
56
|
updated(changedProperties) {
|
|
49
57
|
super.updated(changedProperties);
|
|
50
58
|
if (changedProperties.has("disabled")) {
|
|
51
|
-
|
|
52
|
-
this.setAttribute("tabindex", tabIndex);
|
|
59
|
+
this.setAttribute("tabindex", this.disabled ? "-1" : "0");
|
|
53
60
|
}
|
|
54
61
|
}
|
|
55
62
|
render() {
|
|
@@ -57,36 +64,40 @@ class UMenuItem extends BaseElement {
|
|
|
57
64
|
<u-icon class="prefix icon"
|
|
58
65
|
?hidden=${!this.checked}
|
|
59
66
|
lib="internal"
|
|
60
|
-
name="check
|
|
67
|
+
name="check"
|
|
61
68
|
></u-icon>
|
|
62
69
|
|
|
70
|
+
<u-spinner class="prefix icon"
|
|
71
|
+
?hidden=${!this.loading}
|
|
72
|
+
></u-spinner>
|
|
73
|
+
|
|
63
74
|
<slot name="prefix"></slot>
|
|
64
75
|
|
|
65
|
-
<span class="
|
|
66
|
-
<slot></slot>
|
|
76
|
+
<span class="label">
|
|
77
|
+
<slot @slotchange=${this.handleSlotChange}></slot>
|
|
67
78
|
</span>
|
|
68
79
|
|
|
69
80
|
<slot name="suffix"></slot>
|
|
70
81
|
|
|
71
82
|
<u-icon class="suffix icon"
|
|
72
|
-
?hidden=${
|
|
83
|
+
?hidden=${this.submenu === null}
|
|
73
84
|
lib="internal"
|
|
74
85
|
name="chevron-right"
|
|
75
86
|
></u-icon>
|
|
76
87
|
|
|
77
|
-
<slot name="submenu"
|
|
78
|
-
?hidden=${!this.isNested}
|
|
79
|
-
@slotchange=${this.handleSubmenuSlotChange}
|
|
80
|
-
></slot>
|
|
88
|
+
<slot name="submenu" @slotchange=${this.handleSubmenuSlotChange}></slot>
|
|
81
89
|
`;
|
|
82
90
|
}
|
|
83
91
|
}
|
|
84
92
|
__decorateClass([
|
|
85
93
|
state()
|
|
86
|
-
], UMenuItem.prototype, "
|
|
94
|
+
], UMenuItem.prototype, "submenu");
|
|
87
95
|
__decorateClass([
|
|
88
96
|
property({ type: Boolean, reflect: true })
|
|
89
97
|
], UMenuItem.prototype, "disabled");
|
|
98
|
+
__decorateClass([
|
|
99
|
+
property({ type: Boolean, reflect: true })
|
|
100
|
+
], UMenuItem.prototype, "loading");
|
|
90
101
|
__decorateClass([
|
|
91
102
|
property({ type: Boolean, reflect: true })
|
|
92
103
|
], UMenuItem.prototype, "checked");
|