@iyulab/components 0.1.3 → 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.
Files changed (124) hide show
  1. package/CHANGELOG.md +18 -15
  2. package/LICENSE +20 -20
  3. package/README.md +33 -33
  4. package/dist/assets/icons/arrow-clockwise.svg.js +1 -1
  5. package/dist/assets/icons/arrow-down.svg.js +1 -1
  6. package/dist/assets/icons/arrow-up.svg.js +1 -1
  7. package/dist/assets/icons/ban.svg.js +1 -1
  8. package/dist/assets/icons/check-circle-fill.svg.js +1 -1
  9. package/dist/assets/icons/check-lg.svg.js +1 -1
  10. package/dist/assets/icons/chevron-down.svg.js +1 -1
  11. package/dist/assets/icons/chevron-left.svg.js +1 -1
  12. package/dist/assets/icons/chevron-right.svg.js +1 -1
  13. package/dist/assets/icons/chevron-up.svg.js +1 -1
  14. package/dist/assets/icons/copy.svg.js +1 -1
  15. package/dist/assets/icons/dash-lg.svg.js +1 -1
  16. package/dist/assets/icons/exclamation-circle-fill.svg.js +1 -1
  17. package/dist/assets/icons/exclamation-triangle-fill.svg.js +1 -1
  18. package/dist/assets/icons/info-circle-fill.svg.js +1 -1
  19. package/dist/assets/icons/layout-sidebar.svg.js +1 -1
  20. package/dist/assets/icons/lightbulb-fill.svg.js +1 -1
  21. package/dist/assets/icons/lightbulb-off.svg.js +1 -1
  22. package/dist/assets/icons/lightbulb.svg.js +1 -1
  23. package/dist/assets/icons/mic-fill.svg.js +1 -1
  24. package/dist/assets/icons/mic-mute-fill.svg.js +1 -1
  25. package/dist/assets/icons/paperclip.svg.js +1 -1
  26. package/dist/assets/icons/pencil-square.svg.js +1 -1
  27. package/dist/assets/icons/plus-lg.svg.js +1 -1
  28. package/dist/assets/icons/search.svg.js +1 -1
  29. package/dist/assets/icons/speedometer.svg.js +1 -1
  30. package/dist/assets/icons/x-lg.svg.js +1 -1
  31. package/dist/assets/styles/dark.css +129 -125
  32. package/dist/assets/styles/dark.css.js +1 -1
  33. package/dist/assets/styles/light.css +129 -126
  34. package/dist/assets/styles/light.css.js +1 -1
  35. package/dist/components/BaseElement.styles.js +2 -3
  36. package/dist/components/alert/Alert.d.ts +8 -4
  37. package/dist/components/alert/Alert.js +24 -15
  38. package/dist/components/alert/Alert.styles.js +32 -39
  39. package/dist/components/alert/index.js +5 -0
  40. package/dist/components/button/Button.js +4 -2
  41. package/dist/components/button/Button.styles.js +13 -20
  42. package/dist/components/button/index.js +5 -0
  43. package/dist/components/context-menu/index.js +5 -0
  44. package/dist/components/copy-button/CopyButton.d.ts +7 -3
  45. package/dist/components/copy-button/CopyButton.js +69 -0
  46. package/dist/components/copy-button/CopyButton.styles.js +17 -0
  47. package/dist/components/copy-button/index.js +5 -0
  48. package/dist/components/dialog/index.js +5 -0
  49. package/dist/components/divider/Divider.d.ts +25 -0
  50. package/dist/components/divider/Divider.js +89 -0
  51. package/dist/components/{split-panel/Splitter.styles.js → divider/Divider.styles.js} +25 -13
  52. package/dist/components/divider/index.d.ts +7 -0
  53. package/dist/components/divider/index.js +5 -0
  54. package/dist/components/form/Form.d.ts +3 -1
  55. package/dist/components/form/Form.js +3 -1
  56. package/dist/components/form/Form.styles.js +1 -0
  57. package/dist/components/form/index.js +5 -0
  58. package/dist/components/icon/Icon.d.ts +6 -16
  59. package/dist/components/icon/Icon.js +17 -40
  60. package/dist/components/icon/Icon.styles.js +1 -1
  61. package/dist/components/icon/index.js +5 -0
  62. package/dist/components/icon-button/IconButton.d.ts +3 -3
  63. package/dist/components/icon-button/IconButton.js +6 -6
  64. package/dist/components/icon-button/IconButton.styles.js +14 -29
  65. package/dist/components/icon-button/index.js +5 -0
  66. package/dist/components/index.d.ts +2 -1
  67. package/dist/components/input/Input.d.ts +14 -13
  68. package/dist/components/input/Input.js +56 -55
  69. package/dist/components/input/Input.styles.js +52 -54
  70. package/dist/components/input/index.js +5 -0
  71. package/dist/components/menu/index.js +5 -0
  72. package/dist/components/progress-bar/ProgressBar.d.ts +2 -2
  73. package/dist/components/progress-bar/ProgressBar.js +2 -2
  74. package/dist/components/progress-bar/ProgressBar.styles.js +10 -10
  75. package/dist/components/progress-bar/index.js +5 -0
  76. package/dist/components/progress-ring/ProgressRing.d.ts +2 -2
  77. package/dist/components/progress-ring/ProgressRing.js +9 -6
  78. package/dist/components/progress-ring/ProgressRing.styles.js +8 -9
  79. package/dist/components/progress-ring/index.js +5 -0
  80. package/dist/components/spinner/Spinner.styles.js +5 -3
  81. package/dist/components/spinner/index.js +5 -0
  82. package/dist/components/split-panel/SplitPanel.d.ts +8 -12
  83. package/dist/components/split-panel/SplitPanel.js +64 -91
  84. package/dist/components/split-panel/SplitPanel.styles.js +16 -1
  85. package/dist/components/split-panel/index.js +5 -0
  86. package/dist/components/tooltip/Tooltip.d.ts +8 -12
  87. package/dist/components/tooltip/Tooltip.js +39 -38
  88. package/dist/components/tooltip/Tooltip.styles.js +5 -5
  89. package/dist/components/tooltip/index.js +5 -0
  90. package/dist/components/tree/Tree.d.ts +2 -14
  91. package/dist/components/tree/Tree.js +9 -49
  92. package/dist/components/tree/Tree.styles.js +5 -5
  93. package/dist/components/tree/index.js +5 -0
  94. package/dist/components/tree-item/TreeItem.d.ts +10 -29
  95. package/dist/components/tree-item/TreeItem.js +63 -95
  96. package/dist/components/tree-item/TreeItem.styles.js +10 -41
  97. package/dist/components/tree-item/index.js +5 -0
  98. package/dist/index.js +25 -5
  99. package/dist/integrations/react/UDivider.d.ts +8 -0
  100. package/dist/integrations/react/UDivider.js +10 -0
  101. package/dist/integrations/react/index.d.ts +1 -1
  102. package/dist/integrations/react/index.js +1 -1
  103. package/dist/internals/index.d.ts +0 -1
  104. package/dist/utilities/decorators.js +2 -0
  105. package/dist/utilities/icons.d.ts +46 -0
  106. package/dist/{internals → utilities}/icons.js +74 -2
  107. package/dist/utilities/index.d.ts +1 -0
  108. package/dist/utilities/notifier.d.ts +17 -7
  109. package/dist/utilities/notifier.js +51 -41
  110. package/dist/utilities/theme.d.ts +15 -20
  111. package/dist/utilities/theme.js +36 -29
  112. package/package.json +59 -58
  113. package/dist/components/panel/Panel.d.ts +0 -10
  114. package/dist/components/panel/Panel.js +0 -21
  115. package/dist/components/panel/Panel.styles.js +0 -12
  116. package/dist/components/panel/index.d.ts +0 -7
  117. package/dist/components/split-panel/SplitPanel.types.d.ts +0 -2
  118. package/dist/components/split-panel/Splitter.d.ts +0 -17
  119. package/dist/components/split-panel/Splitter.js +0 -45
  120. package/dist/components/split-panel/Splitter.styles.d.ts +0 -1
  121. package/dist/integrations/react/UPanel.d.ts +0 -8
  122. package/dist/integrations/react/UPanel.js +0 -10
  123. package/dist/internals/icons.d.ts +0 -6
  124. /package/dist/components/{panel/Panel.styles.d.ts → divider/Divider.styles.d.ts} +0 -0
@@ -16,59 +16,55 @@ var __decorateClass = (decorators, target, key, kind) => {
16
16
  };
17
17
  class Tooltip extends BaseElement {
18
18
  constructor() {
19
- super(...arguments);
20
- /** 슬롯이 비어있는지 여부를 나타냅니다. */
21
- this.isSlotEmpty = true;
19
+ super();
22
20
  this.triggers = [];
23
- this.open = false;
24
21
  this.hoist = false;
25
22
  this.distance = 8;
23
+ this.delay = 0;
26
24
  /** 툴팁을 표시합니다. */
27
- this.show = async (e) => {
25
+ this.show = async (event) => {
28
26
  await this.updateComplete;
29
- const trigger = e?.currentTarget || this.triggers[0] || null;
30
- if (!trigger || this.isSlotEmpty) return;
27
+ const trigger = event?.currentTarget;
28
+ if (trigger instanceof HTMLElement === false) {
29
+ return;
30
+ }
31
31
  const middleware = [
32
32
  offset({ mainAxis: this.distance }),
33
33
  shift(),
34
34
  flip()
35
35
  ];
36
- if (!this.placement)
36
+ if (!this.placement) {
37
37
  middleware.push(autoPlacement());
38
+ }
38
39
  const position = await computePosition(trigger, this, {
40
+ strategy: this.hoist ? "fixed" : "absolute",
39
41
  placement: this.placement,
40
- middleware,
41
- strategy: this.hoist ? "fixed" : "absolute"
42
+ middleware
42
43
  });
43
44
  Object.assign(this.style, {
44
45
  left: `${position.x}px`,
45
46
  top: `${position.y}px`,
46
47
  transformOrigin: this.getTransformOrigin(position.placement)
47
48
  });
48
- await this.updateComplete;
49
+ if (this.delay > 0) {
50
+ await new Promise((resolve) => setTimeout(resolve, this.delay));
51
+ }
49
52
  requestAnimationFrame(() => {
50
- this.open = true;
53
+ this.setAttribute("open", "");
51
54
  });
52
55
  };
53
56
  /** 툴팁을 숨깁니다. */
54
- this.hide = async (_) => {
57
+ this.hide = async (event) => {
55
58
  await this.updateComplete;
56
- requestAnimationFrame(() => {
57
- this.open = false;
58
- });
59
- };
60
- /**
61
- * slot에 콘텐츠가 존재하는지 확인합니다.
62
- */
63
- this.handleSlotChange = (e) => {
64
- const slot = e.target;
65
- const nodes = slot.assignedNodes({ flatten: true }) ?? [];
66
- this.isSlotEmpty = !nodes.some((node) => {
67
- if (node.nodeType === Node.ELEMENT_NODE) return true;
68
- if (node.nodeType === Node.TEXT_NODE && node.textContent?.trim()) return true;
69
- return false;
70
- });
59
+ if ("relatedTarget" in event) {
60
+ const relatedTarget = event["relatedTarget"];
61
+ if (this.contains(relatedTarget)) {
62
+ return;
63
+ }
64
+ }
65
+ this.removeAttribute("open");
71
66
  };
67
+ this.setAttribute("tabindex", "0");
72
68
  }
73
69
  static {
74
70
  this.styles = [super.styles, styles];
@@ -82,6 +78,8 @@ class Tooltip extends BaseElement {
82
78
  const parent = getParentElement(this);
83
79
  if (parent) this.triggers = [parent];
84
80
  }
81
+ this.addEventListener("mouseleave", this.hide);
82
+ this.addEventListener("focusout", this.hide);
85
83
  }
86
84
  disconnectedCallback() {
87
85
  this.detachTriggers(this.triggers);
@@ -89,18 +87,21 @@ class Tooltip extends BaseElement {
89
87
  }
90
88
  willUpdate(changedProperties) {
91
89
  super.willUpdate(changedProperties);
92
- if (changedProperties.has("triggers") && this.triggers) {
90
+ if (changedProperties.has("triggerSelectors") && this.triggerSelectors) {
91
+ this.triggers = findElementsBy(this, this.triggerSelectors);
92
+ }
93
+ }
94
+ updated(changedProperties) {
95
+ super.updated(changedProperties);
96
+ if (changedProperties.has("triggers")) {
93
97
  const oldTriggers = changedProperties.get("triggers");
94
98
  this.detachTriggers(oldTriggers);
95
99
  this.attachTriggers(this.triggers);
96
100
  }
97
- if (changedProperties.has("triggerSelectors") && this.triggerSelectors) {
98
- this.triggers = findElementsBy(this, this.triggerSelectors);
99
- }
100
101
  }
101
102
  render() {
102
103
  return html`
103
- <slot @slotchange=${this.handleSlotChange}></slot>
104
+ <slot></slot>
104
105
  `;
105
106
  }
106
107
  /** 대상 엘리먼트에 툴팁 이벤트를 바인딩 합니다. */
@@ -124,8 +125,8 @@ class Tooltip extends BaseElement {
124
125
  }
125
126
  }
126
127
  /**
127
- * 툴팁이 나타날 위치에 따라 transform-origin 값을 반환합니다.
128
- */
128
+ * 툴팁이 나타날 위치에 따라 transform-origin 값을 반환합니다.
129
+ */
129
130
  getTransformOrigin(placement) {
130
131
  switch (placement) {
131
132
  case "top":
@@ -155,9 +156,6 @@ __decorateClass([
155
156
  __decorateClass([
156
157
  property({ type: String, attribute: "trigger-selectors" })
157
158
  ], Tooltip.prototype, "triggerSelectors");
158
- __decorateClass([
159
- property({ type: Boolean, reflect: true })
160
- ], Tooltip.prototype, "open");
161
159
  __decorateClass([
162
160
  property({ type: Boolean, reflect: true })
163
161
  ], Tooltip.prototype, "hoist");
@@ -167,5 +165,8 @@ __decorateClass([
167
165
  __decorateClass([
168
166
  property({ type: Number })
169
167
  ], Tooltip.prototype, "distance");
168
+ __decorateClass([
169
+ property({ type: Number })
170
+ ], Tooltip.prototype, "delay");
170
171
 
171
172
  export { Tooltip };
@@ -6,11 +6,11 @@ const styles = css`
6
6
  z-index: 1000;
7
7
  top: 0;
8
8
  left: 0;
9
+
9
10
  display: block;
10
11
  width: max-content;
11
-
12
12
  padding: 8px;
13
- color: var(--u-tooltip-text-color);
13
+ color: var(--u-tooltip-txt-color);
14
14
  font-family: var(--u-font-modern, inherit);
15
15
  font-size: 14px;
16
16
  line-height: 1.5;
@@ -23,14 +23,14 @@ const styles = css`
23
23
  transform: scale(0);
24
24
  transition: opacity 0.15s ease, transform 0.15s ease;
25
25
  }
26
+ :host([hoist]) {
27
+ position: fixed;
28
+ }
26
29
  :host([open]) {
27
30
  opacity: 0.8;
28
31
  transform: scale(1);
29
32
  pointer-events: auto;
30
33
  }
31
- :host([hoist]) {
32
- position: fixed;
33
- }
34
34
  `;
35
35
 
36
36
  export { styles };
@@ -0,0 +1,5 @@
1
+ import { Tooltip } from './Tooltip.js';
2
+
3
+ Tooltip.define("u-tooltip");
4
+
5
+ export { Tooltip };
@@ -7,33 +7,21 @@ import { TreeItem } from '../tree-item/TreeItem.js';
7
7
  export declare class Tree extends BaseElement {
8
8
  static styles: import('lit').CSSResultGroup[];
9
9
  static dependencies: Record<string, typeof BaseElement>;
10
+ private selectedItems;
11
+ treeItems: TreeItem[];
10
12
  /** 트리가 비활성화 상태인지 여부입니다. */
11
13
  disabled: boolean;
12
14
  /** 다중 선택을 허용할지 여부입니다. */
13
15
  multiple: boolean;
14
16
  /** 선택 가능한 트리인지 여부입니다. */
15
17
  selectable: boolean;
16
- private treeItems;
17
- private selectedItems;
18
18
  connectedCallback(): void;
19
19
  disconnectedCallback(): void;
20
20
  render(): import('lit-html').TemplateResult<1>;
21
- /** 슬롯 변경 이벤트를 처리합니다. */
22
- private handleSlotChange;
23
- /** 트리 항목의 레벨을 업데이트합니다. */
24
- private updateTreeItemsLevel;
25
21
  /** 트리 항목 선택 이벤트를 처리합니다. */
26
22
  private handleItemSelect;
27
23
  /** 트리 항목 확장/축소 이벤트를 처리합니다. */
28
24
  private handleItemToggle;
29
- /**
30
- * 모든 트리 항목을 확장합니다.
31
- */
32
- expandAll(): void;
33
- /**
34
- * 모든 트리 항목을 축소합니다.
35
- */
36
- collapseAll(): void;
37
25
  /**
38
26
  * 선택된 모든 항목을 반환합니다.
39
27
  */
@@ -1,5 +1,5 @@
1
1
  import { html } from 'lit';
2
- import { property, queryAssignedElements } from 'lit/decorators.js';
2
+ import { queryAssignedElements, property } from 'lit/decorators.js';
3
3
  import { BaseElement } from '../BaseElement.js';
4
4
  import { TreeItem } from '../tree-item/TreeItem.js';
5
5
  import { styles } from './Tree.styles.js';
@@ -16,14 +16,10 @@ var __decorateClass = (decorators, target, key, kind) => {
16
16
  class Tree extends BaseElement {
17
17
  constructor() {
18
18
  super(...arguments);
19
+ this.selectedItems = /* @__PURE__ */ new Set();
19
20
  this.disabled = false;
20
21
  this.multiple = false;
21
22
  this.selectable = true;
22
- this.selectedItems = /* @__PURE__ */ new Set();
23
- /** 슬롯 변경 이벤트를 처리합니다. */
24
- this.handleSlotChange = () => {
25
- this.updateTreeItemsLevel();
26
- };
27
23
  /** 트리 항목 선택 이벤트를 처리합니다. */
28
24
  this.handleItemSelect = (e) => {
29
25
  if (!this.selectable || this.disabled) {
@@ -84,42 +80,11 @@ class Tree extends BaseElement {
84
80
  }
85
81
  render() {
86
82
  return html`
87
- <div class="tree-container">
88
- <slot @slotchange=${this.handleSlotChange}></slot>
83
+ <div class="container">
84
+ <slot></slot>
89
85
  </div>
90
86
  `;
91
87
  }
92
- /** 트리 항목의 레벨을 업데이트합니다. */
93
- updateTreeItemsLevel(items = this.treeItems, level = 0) {
94
- items.forEach((item) => {
95
- if (item instanceof TreeItem) {
96
- item.level = level;
97
- const childrenSlot = item.shadowRoot?.querySelector('slot[name="children"]');
98
- if (childrenSlot) {
99
- const children = childrenSlot.assignedElements();
100
- if (children.length > 0) {
101
- this.updateTreeItemsLevel(children, level + 1);
102
- }
103
- }
104
- }
105
- });
106
- }
107
- /**
108
- * 모든 트리 항목을 확장합니다.
109
- */
110
- expandAll() {
111
- this.getAllTreeItems().forEach((item) => {
112
- item.expand();
113
- });
114
- }
115
- /**
116
- * 모든 트리 항목을 축소합니다.
117
- */
118
- collapseAll() {
119
- this.getAllTreeItems().forEach((item) => {
120
- item.collapse();
121
- });
122
- }
123
88
  /**
124
89
  * 선택된 모든 항목을 반환합니다.
125
90
  */
@@ -143,18 +108,16 @@ class Tree extends BaseElement {
143
108
  items.forEach((item) => {
144
109
  if (item instanceof TreeItem) {
145
110
  allItems.push(item);
146
- const childrenSlot = item.shadowRoot?.querySelector('slot[name="children"]');
147
- if (childrenSlot) {
148
- const children = childrenSlot.assignedElements();
149
- if (children.length > 0) {
150
- allItems = allItems.concat(this.getAllTreeItems(children));
151
- }
152
- }
111
+ const childItems = this.getAllTreeItems(item.childrenItems);
112
+ allItems = allItems.concat(childItems);
153
113
  }
154
114
  });
155
115
  return allItems;
156
116
  }
157
117
  }
118
+ __decorateClass([
119
+ queryAssignedElements({ selector: "u-tree-item" })
120
+ ], Tree.prototype, "treeItems");
158
121
  __decorateClass([
159
122
  property({ type: Boolean, reflect: true })
160
123
  ], Tree.prototype, "disabled");
@@ -164,8 +127,5 @@ __decorateClass([
164
127
  __decorateClass([
165
128
  property({ type: Boolean })
166
129
  ], Tree.prototype, "selectable");
167
- __decorateClass([
168
- queryAssignedElements({ selector: "u-tree-item" })
169
- ], Tree.prototype, "treeItems");
170
130
 
171
131
  export { Tree };
@@ -3,8 +3,11 @@ import { css } from 'lit';
3
3
  const styles = css`
4
4
  :host {
5
5
  display: block;
6
- width: 100%;
7
6
  min-width: 0;
7
+ width: 100%;
8
+ padding: 4px;
9
+ background-color: transparent;
10
+ border-radius: 4px;
8
11
  }
9
12
 
10
13
  :host([disabled]) {
@@ -13,13 +16,10 @@ const styles = css`
13
16
  cursor: not-allowed;
14
17
  }
15
18
 
16
- .tree-container {
19
+ .container {
17
20
  display: flex;
18
21
  flex-direction: column;
19
22
  gap: 2px;
20
- padding: 4px;
21
- background-color: transparent;
22
- border-radius: 4px;
23
23
  }
24
24
  `;
25
25
 
@@ -0,0 +1,5 @@
1
+ import { Tree } from './Tree.js';
2
+
3
+ customElements.define("u-tree", Tree);
4
+
5
+ export { Tree, Tree as default };
@@ -7,46 +7,27 @@ import { BaseElement } from '../BaseElement.js';
7
7
  export declare class TreeItem extends BaseElement {
8
8
  static styles: import('lit').CSSResultGroup[];
9
9
  static dependencies: Record<string, typeof BaseElement>;
10
+ headerEl: HTMLElement;
11
+ childrenItems: TreeItem[];
12
+ /** 트리 항목이 리프 노드인지 여부입니다. */
13
+ leaf: boolean;
14
+ /** 트리 항목의 들여쓰기 레벨입니다. */
15
+ level: number;
10
16
  /** 트리 항목이 비활성화 상태인지 여부입니다. */
11
17
  disabled: boolean;
12
18
  /** 트리 항목이 선택된 상태인지 여부입니다. */
13
19
  selected: boolean;
14
20
  /** 트리 항목이 확장된 상태인지 여부입니다. */
15
21
  expanded: boolean;
16
- /** 트리 항목이 리프 노드인지 여부입니다. */
17
- leaf: boolean;
18
- /** 트리 항목의 들여쓰기 레벨입니다. */
19
- level: number;
20
22
  /** 트리 항목의 값입니다. */
21
23
  value: string;
22
- /** 트리 항목의 아이콘입니다. */
23
- icon: string;
24
- private hasChildren;
25
24
  connectedCallback(): void;
26
25
  protected updated(changedProperties: PropertyValues): void;
27
26
  render(): import('lit-html').TemplateResult<1>;
28
- /** 확장/축소 아이콘을 렌더링합니다. */
29
- private renderExpandIcon;
30
- /** 커스텀 아이콘을 렌더링합니다. */
31
- private renderIcon;
27
+ /** 슬롯 변경 헤더용 노드와 자식 노드 분리 */
28
+ private handleSlotChange;
29
+ /** 자식 슬롯 변경 시 자식 노드 재설정 */
30
+ private handleChildrenSlotChange;
32
31
  /** 헤더 클릭 이벤트를 처리합니다. */
33
32
  private handleHeaderClick;
34
- /** 확장/축소 아이콘 클릭 이벤트를 처리합니다. */
35
- private handleExpandClick;
36
- /** 슬롯 변경 시 자식 노드 확인 */
37
- private handleSlotChange;
38
- /** 자식 노드가 있는지 확인합니다. */
39
- private checkForChildren;
40
- /**
41
- * 트리 항목을 확장합니다.
42
- */
43
- expand(): void;
44
- /**
45
- * 트리 항목을 축소합니다.
46
- */
47
- collapse(): void;
48
- /**
49
- * 트리 항목의 확장 상태를 토글합니다.
50
- */
51
- toggle(): void;
52
33
  }
@@ -1,6 +1,7 @@
1
- import { html, nothing } from 'lit';
2
- import { property, state } from 'lit/decorators.js';
1
+ import { html } from 'lit';
2
+ import { query, queryAssignedElements, state, property } from 'lit/decorators.js';
3
3
  import { BaseElement } from '../BaseElement.js';
4
+ import { Icon } from '../icon/Icon.js';
4
5
  import { styles } from './TreeItem.styles.js';
5
6
 
6
7
  var __defProp = Object.defineProperty;
@@ -12,17 +13,32 @@ var __decorateClass = (decorators, target, key, kind) => {
12
13
  if (result) __defProp(target, key, result);
13
14
  return result;
14
15
  };
15
- class TreeItem extends BaseElement {
16
+ const _TreeItem = class _TreeItem extends BaseElement {
16
17
  constructor() {
17
18
  super(...arguments);
19
+ this.leaf = true;
20
+ this.level = 0;
18
21
  this.disabled = false;
19
22
  this.selected = false;
20
23
  this.expanded = false;
21
- this.leaf = false;
22
- this.level = 0;
23
24
  this.value = "";
24
- this.icon = "";
25
- this.hasChildren = false;
25
+ /** 슬롯 변경 시 헤더용 노드와 자식 노드 분리 */
26
+ this.handleSlotChange = (e) => {
27
+ const slot = e.target;
28
+ const nodes = slot.assignedNodes({ flatten: true });
29
+ nodes.forEach((node) => {
30
+ if (node instanceof _TreeItem) {
31
+ node.setAttribute("slot", "children");
32
+ }
33
+ });
34
+ };
35
+ /** 자식 슬롯 변경 시 자식 노드 재설정 */
36
+ this.handleChildrenSlotChange = () => {
37
+ this.leaf = this.childrenItems.length === 0;
38
+ this.childrenItems.forEach((child) => {
39
+ child.level = this.level + 1;
40
+ });
41
+ };
26
42
  /** 헤더 클릭 이벤트를 처리합니다. */
27
43
  this.handleHeaderClick = (e) => {
28
44
  if (this.disabled) {
@@ -30,34 +46,27 @@ class TreeItem extends BaseElement {
30
46
  e.stopPropagation();
31
47
  return;
32
48
  }
33
- this.selected = true;
34
- this.emit("u-select", { value: this.value, item: this });
35
- };
36
- /** 확장/축소 아이콘 클릭 이벤트를 처리합니다. */
37
- this.handleExpandClick = (e) => {
38
- e.stopPropagation();
39
- if (this.disabled || this.leaf || !this.hasChildren) {
40
- return;
49
+ if (this.leaf) {
50
+ this.selected = true;
51
+ this.emit("u-select", { value: this.value, item: this });
52
+ } else {
53
+ this.expanded = !this.expanded;
54
+ this.emit("u-toggle", { expanded: this.expanded, item: this });
41
55
  }
42
- this.expanded = !this.expanded;
43
- this.emit("u-toggle", { expanded: this.expanded, item: this });
44
- };
45
- /** 슬롯 변경 시 자식 노드 확인 */
46
- this.handleSlotChange = () => {
47
- this.checkForChildren();
48
56
  };
49
57
  }
50
58
  static {
51
59
  this.styles = [super.styles, styles];
52
60
  }
53
61
  static {
54
- this.dependencies = {};
62
+ this.dependencies = {
63
+ "u-icon": Icon
64
+ };
55
65
  }
56
66
  connectedCallback() {
57
67
  super.connectedCallback();
58
68
  this.setAttribute("role", "treeitem");
59
69
  this.setAttribute("tabindex", this.disabled ? "-1" : "0");
60
- this.checkForChildren();
61
70
  }
62
71
  updated(changedProperties) {
63
72
  super.updated(changedProperties);
@@ -66,98 +75,57 @@ class TreeItem extends BaseElement {
66
75
  this.setAttribute("aria-disabled", this.disabled ? "true" : "false");
67
76
  }
68
77
  if (changedProperties.has("expanded")) {
69
- this.setAttribute("aria-expanded", this.hasChildren ? String(this.expanded) : "false");
78
+ this.setAttribute("aria-expanded", this.expanded ? "true" : "false");
70
79
  }
71
80
  if (changedProperties.has("selected")) {
72
81
  this.setAttribute("aria-selected", this.selected ? "true" : "false");
73
82
  }
83
+ if (changedProperties.has("level")) {
84
+ this.setAttribute("aria-level", String(this.level + 1));
85
+ this.headerEl.style.paddingLeft = `calc(${this.level} * var(--indent-size, 20px))`;
86
+ }
74
87
  }
75
88
  render() {
76
89
  return html`
77
- <div class="header" @click=${this.handleHeaderClick} style="padding-left: calc(${this.level} * 20px)">
78
- ${this.renderExpandIcon()}
79
- ${this.renderIcon()}
80
- <span class="label">
81
- <slot name="label"></slot>
82
- <slot></slot>
83
- </span>
90
+ <div class="header" @click=${this.handleHeaderClick}>
91
+ <u-icon class="expand-icon"
92
+ ?hidden=${this.leaf}
93
+ name=${this.expanded ? "chevron-down" : "chevron-right"}
94
+ ></u-icon>
95
+ <slot name="prefix"></slot>
96
+ <slot @slotchange=${this.handleSlotChange}></slot>
97
+ <slot name="suffix"></slot>
84
98
  </div>
85
99
  <div class="children" ?hidden=${!this.expanded}>
86
- <slot name="children" @slotchange=${this.handleSlotChange}></slot>
100
+ <slot name="children" @slotchange=${this.handleChildrenSlotChange}></slot>
87
101
  </div>
88
102
  `;
89
103
  }
90
- /** 확장/축소 아이콘을 렌더링합니다. */
91
- renderExpandIcon() {
92
- if (this.leaf || !this.hasChildren) {
93
- return html`<span class="expand-icon placeholder"></span>`;
94
- }
95
- return html`
96
- <span class="expand-icon" @click=${this.handleExpandClick}>
97
- ${this.expanded ? "▼" : "▶"}
98
- </span>
99
- `;
100
- }
101
- /** 커스텀 아이콘을 렌더링합니다. */
102
- renderIcon() {
103
- if (!this.icon) {
104
- return nothing;
105
- }
106
- return html`<span class="icon">${this.icon}</span>`;
107
- }
108
- /** 자식 노드가 있는지 확인합니다. */
109
- checkForChildren() {
110
- const childrenSlot = this.shadowRoot?.querySelector('slot[name="children"]');
111
- const children = childrenSlot?.assignedElements() || [];
112
- this.hasChildren = children.length > 0;
113
- this.setAttribute("aria-expanded", this.hasChildren ? String(this.expanded) : "false");
114
- }
115
- /**
116
- * 트리 항목을 확장합니다.
117
- */
118
- expand() {
119
- if (!this.leaf && this.hasChildren) {
120
- this.expanded = true;
121
- }
122
- }
123
- /**
124
- * 트리 항목을 축소합니다.
125
- */
126
- collapse() {
127
- this.expanded = false;
128
- }
129
- /**
130
- * 트리 항목의 확장 상태를 토글합니다.
131
- */
132
- toggle() {
133
- if (!this.leaf && this.hasChildren) {
134
- this.expanded = !this.expanded;
135
- }
136
- }
137
- }
104
+ };
138
105
  __decorateClass([
139
- property({ type: Boolean, reflect: true })
140
- ], TreeItem.prototype, "disabled");
106
+ query(".header")
107
+ ], _TreeItem.prototype, "headerEl");
141
108
  __decorateClass([
142
- property({ type: Boolean, reflect: true })
143
- ], TreeItem.prototype, "selected");
109
+ queryAssignedElements({ slot: "children", selector: "u-tree-item", flatten: true })
110
+ ], _TreeItem.prototype, "childrenItems");
144
111
  __decorateClass([
145
- property({ type: Boolean, reflect: true })
146
- ], TreeItem.prototype, "expanded");
112
+ state()
113
+ ], _TreeItem.prototype, "leaf");
114
+ __decorateClass([
115
+ state()
116
+ ], _TreeItem.prototype, "level");
147
117
  __decorateClass([
148
118
  property({ type: Boolean, reflect: true })
149
- ], TreeItem.prototype, "leaf");
119
+ ], _TreeItem.prototype, "disabled");
150
120
  __decorateClass([
151
- property({ type: Number, reflect: true })
152
- ], TreeItem.prototype, "level");
121
+ property({ type: Boolean, reflect: true })
122
+ ], _TreeItem.prototype, "selected");
153
123
  __decorateClass([
154
- property({ type: String })
155
- ], TreeItem.prototype, "value");
124
+ property({ type: Boolean, reflect: true })
125
+ ], _TreeItem.prototype, "expanded");
156
126
  __decorateClass([
157
127
  property({ type: String })
158
- ], TreeItem.prototype, "icon");
159
- __decorateClass([
160
- state()
161
- ], TreeItem.prototype, "hasChildren");
128
+ ], _TreeItem.prototype, "value");
129
+ let TreeItem = _TreeItem;
162
130
 
163
131
  export { TreeItem };