@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
@@ -9,31 +9,29 @@ const styles = css`
9
9
  font-weight: 500;
10
10
  line-height: 1.5;
11
11
  padding: 0.5em 1em;
12
- background-color: var(--u-bg-color);
13
12
  border: 1px solid var(--u-border-color);
14
13
  border-radius: 6px;
14
+ background-color: var(--u-bg-color);
15
15
 
16
16
  transition: all 0.2s ease;
17
+ overflow: hidden;
17
18
  user-select: none;
18
19
  cursor: pointer;
19
20
  }
20
- :host([loading]),
21
- :host([disabled]) {
22
- pointer-events: none;
23
- }
24
- :host([disabled]) {
25
- color: var(--u-text-color-disabled);
26
- }
27
21
  :host(:hover) {
28
- color: var(--u-text-color-hover);
22
+ color: var(--u-txt-color-hover);
29
23
  background-color: var(--u-bg-color-hover);
30
- border-color: var(--u-border-color-strong);
31
24
  }
32
25
  :host(:active) {
33
- color: var(--u-text-color-active);
26
+ color: var(--u-txt-color-active);
34
27
  background-color: var(--u-bg-color-active);
35
28
  transform: translateY(1px);
36
29
  }
30
+ :host([loading]),
31
+ :host([disabled]) {
32
+ color: var(--u-txt-color-disabled);
33
+ pointer-events: none;
34
+ }
37
35
 
38
36
  button {
39
37
  all: unset;
@@ -49,21 +47,16 @@ const styles = css`
49
47
  }
50
48
 
51
49
  slot {
52
- flex: 1 1 auto;
50
+ flex: 1 0 auto;
53
51
  min-width: 0;
54
52
  display: inline-flex;
55
- align-items: center;
56
53
  justify-content: center;
57
54
  }
58
- slot[name="prefix"],
59
- slot[name="suffix"] {
60
- flex: 0 0 auto;
61
- }
62
- /* 슬롯에 내용이 있을 때만 gap 적용 */
63
- slot[name="prefix"]:not(:empty) {
55
+ /* 슬롯에 내용이 있을 때 gap 적용 */
56
+ ::slotted([slot="prefix"]) {
64
57
  margin-right: 0.5em;
65
58
  }
66
- slot[name="suffix"]:not(:empty) {
59
+ ::slotted([slot="suffix"]) {
67
60
  margin-left: 0.5em;
68
61
  }
69
62
 
@@ -0,0 +1,5 @@
1
+ import { Button } from './Button.js';
2
+
3
+ Button.define("u-button");
4
+
5
+ export { Button };
@@ -0,0 +1,5 @@
1
+ import { ContextMenu } from './ContextMenu.js';
2
+
3
+ ContextMenu.define("u-context-menu");
4
+
5
+ export { ContextMenu };
@@ -5,11 +5,15 @@ import { BaseElement } from '../BaseElement.js';
5
5
  export declare class CopyButton extends BaseElement {
6
6
  static styles: import('lit').CSSResultGroup[];
7
7
  static dependencies: Record<string, typeof BaseElement>;
8
- /** 버튼의 테두리 유무를 설정합니다. 기본값은 true로, 테두리가 없습니다. */
8
+ /** 버튼의 복사 상태를 설정합니다. 복사가 완료되면 true 변경됩니다. */
9
+ copied: boolean;
10
+ /** 버튼의 테두리 유무를 설정합니다. 기본값은 false입니다. */
9
11
  borderless: boolean;
10
12
  /** 버튼이 비활성화 상태인지 여부를 설정합니다. 비활성화된 버튼은 클릭할 수 없습니다. */
11
13
  disabled: boolean;
12
- /** 버튼의 복사 상태를 설정합니다. 복사가 완료되면 true로 변경됩니다. */
13
- copied: boolean;
14
+ /** 복사할 텍스트를 설정합니다. */
15
+ value: string;
14
16
  render(): import('lit-html').TemplateResult<1>;
17
+ /** 복사 버튼 클릭 핸들러 */
18
+ private handleButtonClick;
15
19
  }
@@ -0,0 +1,69 @@
1
+ import { html } from 'lit';
2
+ import { state, property } from 'lit/decorators.js';
3
+ import { BaseElement } from '../BaseElement.js';
4
+ import { IconButton } from '../icon-button/IconButton.js';
5
+ import { styles } from './CopyButton.styles.js';
6
+
7
+ var __defProp = Object.defineProperty;
8
+ var __decorateClass = (decorators, target, key, kind) => {
9
+ var result = void 0 ;
10
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
11
+ if (decorator = decorators[i])
12
+ result = (decorator(target, key, result) ) || result;
13
+ if (result) __defProp(target, key, result);
14
+ return result;
15
+ };
16
+ class CopyButton extends BaseElement {
17
+ constructor() {
18
+ super(...arguments);
19
+ this.copied = false;
20
+ this.borderless = false;
21
+ this.disabled = false;
22
+ this.value = "";
23
+ /** 복사 버튼 클릭 핸들러 */
24
+ this.handleButtonClick = async () => {
25
+ try {
26
+ await navigator.clipboard.writeText(this.value);
27
+ this.copied = true;
28
+ this.emit("u-copy", { value: this.value });
29
+ setTimeout(() => this.copied = false, 2e3);
30
+ } catch (error) {
31
+ console.error("Failed to copy text: ", error);
32
+ }
33
+ };
34
+ }
35
+ static {
36
+ this.styles = [super.styles, styles];
37
+ }
38
+ static {
39
+ this.dependencies = {
40
+ "u-icon-button": IconButton
41
+ };
42
+ }
43
+ render() {
44
+ return html`
45
+ <u-icon-button part="base"
46
+ ?copied=${this.copied}
47
+ .borderless=${this.borderless}
48
+ .disabled=${this.disabled || this.copied}
49
+ .library=${"internal"}
50
+ .name=${this.copied ? "check-lg" : "copy"}
51
+ @click=${this.handleButtonClick}>
52
+ </u-icon-button>
53
+ `;
54
+ }
55
+ }
56
+ __decorateClass([
57
+ state()
58
+ ], CopyButton.prototype, "copied");
59
+ __decorateClass([
60
+ property({ type: Boolean })
61
+ ], CopyButton.prototype, "borderless");
62
+ __decorateClass([
63
+ property({ type: Boolean })
64
+ ], CopyButton.prototype, "disabled");
65
+ __decorateClass([
66
+ property({ type: String })
67
+ ], CopyButton.prototype, "value");
68
+
69
+ export { CopyButton };
@@ -0,0 +1,17 @@
1
+ import { css } from 'lit';
2
+
3
+ const styles = css`
4
+ :host {
5
+ display: inline-block;
6
+ font-size: 16px;
7
+ }
8
+
9
+ u-icon-button {
10
+ font-size: inherit;
11
+ }
12
+ u-icon-button[copied] {
13
+ color: var(--u-green-600, #16a34a);
14
+ }
15
+ `;
16
+
17
+ export { styles };
@@ -0,0 +1,5 @@
1
+ import { CopyButton } from './CopyButton.js';
2
+
3
+ CopyButton.define("u-copy-button");
4
+
5
+ export { CopyButton };
@@ -0,0 +1,5 @@
1
+ import { Dialog } from './Dialog.js';
2
+
3
+ Dialog.define("u-dialog");
4
+
5
+ export { Dialog };
@@ -0,0 +1,25 @@
1
+ import { nothing } from 'lit';
2
+ import { BaseElement } from '../BaseElement.js';
3
+ /**
4
+ * Divider 컴포넌트는 엘리먼트 사이에 움직임이 가능한 구분선을 제공합니다.
5
+ */
6
+ export declare class Divider extends BaseElement {
7
+ static styles: import('lit').CSSResultGroup[];
8
+ static dependencies: Record<string, typeof BaseElement>;
9
+ /** 마지막 마우스 위치를 저장합니다. */
10
+ private position;
11
+ /** 분할선이 움직이는지 여부를 나타냅니다. */
12
+ moving: boolean;
13
+ /** 분할 방향을 설정합니다. */
14
+ orientation: 'horizontal' | 'vertical';
15
+ /** 분할선을 움직일 수 있는지 여부를 설정합니다. */
16
+ movable: boolean;
17
+ disconnectedCallback(): void;
18
+ render(): typeof nothing | import('lit-html').TemplateResult<1>;
19
+ /** 마우스 다운 이벤트 핸들러 */
20
+ private handleMouseDown;
21
+ /** 마우스 무브 이벤트 핸들러 */
22
+ private handleMouseMove;
23
+ /** 마우스 업 이벤트 핸들러 */
24
+ private handleMouseUp;
25
+ }
@@ -0,0 +1,89 @@
1
+ import { html, nothing } from 'lit';
2
+ import { state, property } from 'lit/decorators.js';
3
+ import { BaseElement } from '../BaseElement.js';
4
+ import { styles } from './Divider.styles.js';
5
+
6
+ var __defProp = Object.defineProperty;
7
+ var __decorateClass = (decorators, target, key, kind) => {
8
+ var result = void 0 ;
9
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
10
+ if (decorator = decorators[i])
11
+ result = (decorator(target, key, result) ) || result;
12
+ if (result) __defProp(target, key, result);
13
+ return result;
14
+ };
15
+ class Divider extends BaseElement {
16
+ constructor() {
17
+ super(...arguments);
18
+ /** 마지막 마우스 위치를 저장합니다. */
19
+ this.position = 0;
20
+ this.moving = false;
21
+ this.orientation = "horizontal";
22
+ this.movable = false;
23
+ /** 마우스 다운 이벤트 핸들러 */
24
+ this.handleMouseDown = (e) => {
25
+ e.preventDefault();
26
+ this.moving = true;
27
+ this.position = this.orientation === "horizontal" ? e.clientX : e.clientY;
28
+ this.emit("u-movestart");
29
+ document.addEventListener("mousemove", this.handleMouseMove);
30
+ document.addEventListener("mouseup", this.handleMouseUp);
31
+ document.body.style.userSelect = "none";
32
+ document.body.style.cursor = this.orientation === "horizontal" ? "col-resize" : "row-resize";
33
+ };
34
+ /** 마우스 무브 이벤트 핸들러 */
35
+ this.handleMouseMove = (e) => {
36
+ if (!this.moving) return;
37
+ e.preventDefault();
38
+ const position = this.orientation === "horizontal" ? e.clientX : e.clientY;
39
+ const delta = position - this.position;
40
+ this.emit("u-move", { delta });
41
+ this.position = position;
42
+ };
43
+ /** 마우스 업 이벤트 핸들러 */
44
+ this.handleMouseUp = (_) => {
45
+ if (!this.moving) return;
46
+ this.moving = false;
47
+ this.emit("u-moveend");
48
+ document.removeEventListener("mousemove", this.handleMouseMove);
49
+ document.removeEventListener("mouseup", this.handleMouseUp);
50
+ document.body.style.userSelect = "";
51
+ document.body.style.cursor = "";
52
+ };
53
+ }
54
+ static {
55
+ this.styles = [super.styles, styles];
56
+ }
57
+ static {
58
+ this.dependencies = {};
59
+ }
60
+ disconnectedCallback() {
61
+ super.disconnectedCallback();
62
+ document.removeEventListener("mousemove", this.handleMouseMove);
63
+ document.removeEventListener("mouseup", this.handleMouseUp);
64
+ }
65
+ render() {
66
+ if (this.movable) {
67
+ return html`
68
+ <div class="handler"
69
+ ?moving=${this.moving}
70
+ orientation=${this.orientation}
71
+ @mousedown=${this.handleMouseDown}
72
+ ></div>
73
+ `;
74
+ } else {
75
+ return nothing;
76
+ }
77
+ }
78
+ }
79
+ __decorateClass([
80
+ state()
81
+ ], Divider.prototype, "moving");
82
+ __decorateClass([
83
+ property({ type: String, reflect: true })
84
+ ], Divider.prototype, "orientation");
85
+ __decorateClass([
86
+ property({ type: Boolean, reflect: true })
87
+ ], Divider.prototype, "movable");
88
+
89
+ export { Divider };
@@ -1,42 +1,54 @@
1
1
  import { css } from 'lit';
2
2
 
3
3
  const styles = css`
4
+ :host {
5
+ --divider-size: 2px;
6
+ --handler-size: 4px;
7
+ --handler-color: var(--u-blue-500, #3b82f6);
8
+ }
9
+
4
10
  :host {
5
11
  position: relative;
6
12
  display: block;
7
13
  flex-shrink: 0;
8
14
  background-color: var(--u-neutral-200, #e5e7eb);
9
- transition: background-color 0.2s ease;
10
-
11
- --splitter-size: 2px;
12
- --handler-size: 6px;
13
- --handler-color: var(--u-blue-500, #3b82f6);
14
15
  }
15
16
  :host([orientation="horizontal"]) {
16
- width: var(--splitter-size, 2px);
17
+ width: var(--divider-size, 2px);
17
18
  height: 100%;
18
19
  cursor: col-resize;
19
20
  }
20
21
  :host([orientation="vertical"]) {
21
22
  width: 100%;
22
- height: var(--splitter-size, 2px);
23
+ height: var(--divider-size, 2px);
23
24
  cursor: row-resize;
24
25
  }
25
26
 
26
27
  .handler {
27
28
  position: absolute;
28
29
  z-index: 100;
29
- top: 50%;
30
- left: 50%;
31
- transform: translate(-50%, -50%);
32
30
  display: block;
33
- width: 300%;
34
- height: 300%;
35
31
  background-color: var(--handler-color, #3b82f6);
36
32
  opacity: 0;
37
33
  transition: opacity 0.2s ease;
38
34
  }
39
- .handler[dragging],
35
+ .handler[orientation="horizontal"] {
36
+ top: 0;
37
+ bottom: 0;
38
+ left: 50%;
39
+ transform: translateX(-50%);
40
+ width: var(--handler-size, 4px);
41
+ height: 100%;
42
+ }
43
+ .handler[orientation="vertical"] {
44
+ left: 0;
45
+ right: 0;
46
+ top: 50%;
47
+ transform: translateY(-50%);
48
+ width: 100%;
49
+ height: var(--handler-size, 4px);
50
+ }
51
+ .handler[moving],
40
52
  .handler:hover {
41
53
  opacity: 1;
42
54
  }
@@ -0,0 +1,7 @@
1
+ import { Divider } from './Divider.js';
2
+ declare global {
3
+ interface HTMLElementTagNameMap {
4
+ 'u-divider': Divider;
5
+ }
6
+ }
7
+ export { Divider };
@@ -0,0 +1,5 @@
1
+ import { Divider } from './Divider.js';
2
+
3
+ Divider.define("u-divider");
4
+
5
+ export { Divider };
@@ -15,7 +15,9 @@ export declare class Form extends BaseElement {
15
15
  connectedCallback(): void;
16
16
  disconnectedCallback(): void;
17
17
  render(): import('lit-html').TemplateResult<1>;
18
- /** 폼 내의 모든 입력 요소를 검증합니다. */
18
+ /**
19
+ * 폼 내의 모든 입력 요소를 검증합니다.
20
+ */
19
21
  validate(): boolean;
20
22
  /** 입력 요소의 변경 이벤트를 처리합니다. */
21
23
  private handleChange;
@@ -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) || [];
@@ -12,6 +12,7 @@ const styles = css`
12
12
 
13
13
  :host * {
14
14
  width: 100%;
15
+ font-size: inherit;
15
16
  }
16
17
  `;
17
18
 
@@ -0,0 +1,5 @@
1
+ import { Form } from './Form.js';
2
+
3
+ Form.define("u-form");
4
+
5
+ export { Form };
@@ -6,28 +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
- * @default '/assets/icons/'
9
+ * 사용할 아이콘 라이브러리를 지정합니다.
10
+ *
11
+ * - 기본 내장: "internal" | "default"
12
+ * - 사용자 확장 라이브러리: icons.register()로 등록한 라이브러리 이름
13
+ * @default "default"
11
14
  */
12
- static remoteBaseUrl: string;
13
- /**
14
- * 아이콘을 외부에서 로드할때 사용하는 설정입니다.
15
- * @see {@link Icon.remoteBaseUrl}에서 외부 기본 경로를 설정할 수 있습니다.
16
- * @default false
17
- */
18
- remote: boolean;
15
+ library: "internal" | "default" | (string & {});
19
16
  /**
20
17
  * 사용할 아이콘의 이름을 지정합니다.
21
- * @description 외부에서 불러오는 SVG 아이콘인 경우, 이름은 파일명(확장자 제외)이어야 합니다.
22
18
  */
23
19
  name?: string;
24
20
  render(): import('lit-html/directive.js').DirectiveResult<typeof import('lit-html/directives/until.js').UntilDirective>;
25
- /**
26
- * 아이콘의 HTML 콘텐츠를 가져옵니다.
27
- * 외부 아이콘 경로를 사용하거나, 내부 레지스트리에서 아이콘을 찾습니다.
28
- * @param name 아이콘 이름
29
- */
30
- private load;
31
21
  /**
32
22
  * SVG 콘텐츠가 유효한 HTML인지 검사합니다.
33
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 { icons } from '../../internals/icons.js';
6
+ import { icons } from '../../utilities/icons.js';
7
7
  import { styles } from './Icon.styles.js';
8
8
 
9
9
  var __defProp = Object.defineProperty;
@@ -15,10 +15,10 @@ var __decorateClass = (decorators, target, key, kind) => {
15
15
  if (result) __defProp(target, key, result);
16
16
  return result;
17
17
  };
18
- const _Icon = class _Icon extends BaseElement {
18
+ class Icon extends BaseElement {
19
19
  constructor() {
20
20
  super(...arguments);
21
- this.remote = false;
21
+ this.library = "default";
22
22
  }
23
23
  static {
24
24
  this.styles = [super.styles, styles];
@@ -26,55 +26,32 @@ const _Icon = class _Icon extends BaseElement {
26
26
  static {
27
27
  this.dependencies = {};
28
28
  }
29
- static {
30
- /**
31
- * 아이콘을 외부에서 불러올 때 사용되는 기본 경로를 설정합니다.
32
- * @default '/assets/icons/'
33
- */
34
- this.remoteBaseUrl = "/assets/icons/";
35
- }
36
29
  render() {
37
30
  if (!this.name) return nothing;
38
- return until(this.load(this.name).then((html) => {
39
- if (!this.validate(html)) return nothing;
40
- return unsafeHTML(html);
31
+ return until(icons.resolve(this.library, this.name).then((html) => {
32
+ return this.validate(html) ? unsafeHTML(html) : nothing;
41
33
  }), nothing);
42
34
  }
43
- /**
44
- * 아이콘의 HTML 콘텐츠를 가져옵니다.
45
- * 외부 아이콘 경로를 사용하거나, 내부 레지스트리에서 아이콘을 찾습니다.
46
- * @param name 아이콘 이름
47
- */
48
- async load(name) {
49
- if (this.remote) {
50
- const remoteUrl = _Icon.remoteBaseUrl.endsWith("/") ? `${_Icon.remoteBaseUrl}${name}.svg` : `${_Icon.remoteBaseUrl}/${name}.svg`;
51
- try {
52
- const response = await fetch(remoteUrl);
53
- if (!response.ok) return void 0;
54
- return (await response.text())?.trim();
55
- } catch (error) {
56
- console.error(error);
57
- return void 0;
58
- }
59
- } else {
60
- return icons.get(name)?.trim();
61
- }
62
- }
63
35
  /**
64
36
  * SVG 콘텐츠가 유효한 HTML인지 검사합니다.
65
37
  */
66
38
  validate(html) {
67
39
  if (!html) return false;
68
- if (!html.endsWith("</svg>")) return false;
69
- return true;
40
+ const trimmed = html.trim();
41
+ try {
42
+ const doc = new DOMParser().parseFromString(trimmed, "image/svg+xml");
43
+ if (doc.querySelector("parsererror")) return false;
44
+ return doc.documentElement?.tagName.toLowerCase() === "svg";
45
+ } catch {
46
+ return false;
47
+ }
70
48
  }
71
- };
49
+ }
72
50
  __decorateClass([
73
- property({ type: Boolean })
74
- ], _Icon.prototype, "remote");
51
+ property({ type: String, attribute: "lib" })
52
+ ], Icon.prototype, "library");
75
53
  __decorateClass([
76
54
  property({ type: String })
77
- ], _Icon.prototype, "name");
78
- let Icon = _Icon;
55
+ ], Icon.prototype, "name");
79
56
 
80
57
  export { Icon };
@@ -3,8 +3,8 @@ import { css } from 'lit';
3
3
  const styles = css`
4
4
  :host {
5
5
  display: inline-flex;
6
- font-size: inherit;
7
6
  color: var(--u-icon-color, currentColor);
7
+ font-size: inherit;
8
8
  }
9
9
 
10
10
  svg {
@@ -0,0 +1,5 @@
1
+ import { Icon } from './Icon.js';
2
+
3
+ Icon.define("u-icon");
4
+
5
+ export { Icon };
@@ -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
- remote: boolean;
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.remote = false;
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" ?disabled=${this.disabled || this.loading}>
38
- ${this.loading ? html`<u-spinner></u-spinner>` : html`<u-icon ?remote=${this.remote} name=${ifDefined(this.name)}></u-icon>`}
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: Boolean })
54
- ], IconButton.prototype, "remote");
53
+ property({ type: String, attribute: "lib" })
54
+ ], IconButton.prototype, "library");
55
55
  __decorateClass([
56
56
  property({ type: String })
57
57
  ], IconButton.prototype, "name");