@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.
Files changed (142) hide show
  1. package/CHANGELOG.md +18 -18
  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/bell-fill.svg.js +1 -1
  9. package/dist/assets/icons/check-circle-fill.svg.js +1 -1
  10. package/dist/assets/icons/check-lg.svg.js +1 -1
  11. package/dist/assets/icons/chevron-down.svg.js +1 -1
  12. package/dist/assets/icons/chevron-left.svg.js +1 -1
  13. package/dist/assets/icons/chevron-right.svg.js +1 -1
  14. package/dist/assets/icons/chevron-up.svg.js +1 -1
  15. package/dist/assets/icons/copy.svg.js +1 -1
  16. package/dist/assets/icons/dash-lg.svg.js +1 -1
  17. package/dist/assets/icons/exclamation-circle-fill.svg.js +1 -1
  18. package/dist/assets/icons/exclamation-triangle-fill.svg.js +1 -1
  19. package/dist/assets/icons/eye-slash.svg.js +1 -1
  20. package/dist/assets/icons/eye.svg.js +1 -1
  21. package/dist/assets/icons/info-circle-fill.svg.js +1 -1
  22. package/dist/assets/icons/layout-sidebar.svg.js +1 -1
  23. package/dist/assets/icons/lightbulb-fill.svg.js +1 -1
  24. package/dist/assets/icons/lightbulb-off.svg.js +1 -1
  25. package/dist/assets/icons/lightbulb.svg.js +1 -1
  26. package/dist/assets/icons/mic-fill.svg.js +1 -1
  27. package/dist/assets/icons/mic-mute-fill.svg.js +1 -1
  28. package/dist/assets/icons/paperclip.svg.js +1 -1
  29. package/dist/assets/icons/pencil-square.svg.js +1 -1
  30. package/dist/assets/icons/plus-lg.svg.js +1 -1
  31. package/dist/assets/icons/search.svg.js +1 -1
  32. package/dist/assets/icons/speedometer.svg.js +1 -1
  33. package/dist/assets/icons/x-lg.svg.js +1 -1
  34. package/dist/assets/styles/dark.css +129 -125
  35. package/dist/assets/styles/dark.css.js +1 -1
  36. package/dist/assets/styles/light.css +129 -126
  37. package/dist/assets/styles/light.css.js +1 -1
  38. package/dist/components/BaseElement.styles.js +2 -2
  39. package/dist/components/FloatingElement.d.ts +84 -0
  40. package/dist/components/FloatingElement.js +166 -0
  41. package/dist/components/FloatingElement.styles.js +26 -0
  42. package/dist/components/alert/Alert.d.ts +8 -4
  43. package/dist/components/alert/Alert.js +24 -15
  44. package/dist/components/alert/Alert.styles.js +32 -39
  45. package/dist/components/alert/index.js +5 -0
  46. package/dist/components/button/Button.js +4 -2
  47. package/dist/components/button/Button.styles.js +13 -20
  48. package/dist/components/button/index.js +5 -0
  49. package/dist/components/context-menu/ContextMenu.d.ts +20 -39
  50. package/dist/components/context-menu/ContextMenu.js +92 -137
  51. package/dist/components/context-menu/ContextMenu.styles.js +3 -28
  52. package/dist/components/context-menu/index.d.ts +1 -1
  53. package/dist/components/context-menu/index.js +5 -0
  54. package/dist/components/copy-button/CopyButton.d.ts +7 -3
  55. package/dist/components/copy-button/CopyButton.js +69 -0
  56. package/dist/components/copy-button/CopyButton.styles.js +17 -0
  57. package/dist/components/copy-button/index.js +5 -0
  58. package/dist/components/dialog/Dialog.d.ts +14 -7
  59. package/dist/components/dialog/Dialog.js +88 -27
  60. package/dist/components/dialog/Dialog.styles.js +60 -11
  61. package/dist/components/dialog/index.js +5 -0
  62. package/dist/components/divider/Divider.d.ts +10 -10
  63. package/dist/components/divider/Divider.js +32 -32
  64. package/dist/components/divider/Divider.styles.js +10 -10
  65. package/dist/components/divider/index.js +5 -0
  66. package/dist/components/dropdown-menu/DropdownMenu.d.ts +27 -0
  67. package/dist/components/dropdown-menu/DropdownMenu.js +135 -0
  68. package/dist/components/dropdown-menu/DropdownMenu.styles.d.ts +1 -0
  69. package/dist/components/dropdown-menu/DropdownMenu.styles.js +15 -0
  70. package/dist/components/dropdown-menu/index.d.ts +7 -0
  71. package/dist/components/dropdown-menu/index.js +5 -0
  72. package/dist/components/form/Form.d.ts +3 -1
  73. package/dist/components/form/Form.js +3 -1
  74. package/dist/components/form/Form.styles.js +1 -0
  75. package/dist/components/form/index.js +5 -0
  76. package/dist/components/icon/Icon.d.ts +6 -12
  77. package/dist/components/icon/Icon.js +15 -30
  78. package/dist/components/icon/Icon.styles.js +1 -1
  79. package/dist/components/icon/index.js +5 -0
  80. package/dist/components/icon-button/IconButton.d.ts +3 -3
  81. package/dist/components/icon-button/IconButton.js +6 -6
  82. package/dist/components/icon-button/IconButton.styles.js +14 -29
  83. package/dist/components/icon-button/index.js +5 -0
  84. package/dist/components/index.d.ts +3 -1
  85. package/dist/components/input/Input.d.ts +14 -13
  86. package/dist/components/input/Input.js +57 -56
  87. package/dist/components/input/Input.styles.js +54 -56
  88. package/dist/components/input/index.js +5 -0
  89. package/dist/components/menu/Menu.d.ts +4 -15
  90. package/dist/components/menu/Menu.js +43 -28
  91. package/dist/components/menu/Menu.styles.js +7 -19
  92. package/dist/components/menu/index.js +5 -0
  93. package/dist/components/menu-item/MenuItem.d.ts +21 -12
  94. package/dist/components/menu-item/MenuItem.js +184 -15
  95. package/dist/components/menu-item/MenuItem.styles.js +6 -0
  96. package/dist/components/menu-item/index.js +5 -0
  97. package/dist/components/progress-bar/ProgressBar.d.ts +1 -1
  98. package/dist/components/progress-bar/ProgressBar.js +2 -2
  99. package/dist/components/progress-bar/ProgressBar.styles.js +10 -10
  100. package/dist/components/progress-bar/index.js +5 -0
  101. package/dist/components/progress-ring/ProgressRing.d.ts +2 -2
  102. package/dist/components/progress-ring/ProgressRing.js +7 -6
  103. package/dist/components/progress-ring/ProgressRing.styles.js +8 -9
  104. package/dist/components/progress-ring/index.js +5 -0
  105. package/dist/components/spinner/Spinner.styles.js +5 -3
  106. package/dist/components/spinner/index.js +5 -0
  107. package/dist/components/split-panel/SplitPanel.d.ts +11 -3
  108. package/dist/components/split-panel/SplitPanel.js +44 -27
  109. package/dist/components/split-panel/SplitPanel.styles.js +1 -16
  110. package/dist/components/split-panel/index.js +5 -0
  111. package/dist/components/tooltip/Tooltip.d.ts +9 -29
  112. package/dist/components/tooltip/Tooltip.js +27 -149
  113. package/dist/components/tooltip/Tooltip.styles.js +9 -23
  114. package/dist/components/tooltip/index.js +5 -0
  115. package/dist/components/tree/index.js +5 -0
  116. package/dist/components/tree-item/index.js +5 -0
  117. package/dist/index.js +28 -5
  118. package/dist/integrations/react/UDropdownMenu.d.ts +8 -0
  119. package/dist/integrations/react/UDropdownMenu.js +10 -0
  120. package/dist/integrations/react/index.d.ts +1 -1
  121. package/dist/integrations/react/index.js +1 -1
  122. package/dist/internals/index.d.ts +0 -1
  123. package/dist/internals/node-helpers.d.ts +6 -1
  124. package/dist/internals/node-helpers.js +5 -6
  125. package/dist/utilities/decorators.js +2 -0
  126. package/dist/utilities/icons.d.ts +46 -0
  127. package/dist/utilities/icons.js +114 -0
  128. package/dist/utilities/index.d.ts +1 -0
  129. package/dist/utilities/notifier.d.ts +17 -7
  130. package/dist/utilities/notifier.js +51 -41
  131. package/dist/utilities/theme.d.ts +15 -20
  132. package/dist/utilities/theme.js +24 -20
  133. package/package.json +59 -58
  134. package/dist/components/panel/Panel.d.ts +0 -9
  135. package/dist/components/panel/Panel.js +0 -17
  136. package/dist/components/panel/Panel.styles.js +0 -12
  137. package/dist/components/panel/index.d.ts +0 -7
  138. package/dist/integrations/react/UPanel.d.ts +0 -8
  139. package/dist/integrations/react/UPanel.js +0 -10
  140. package/dist/internals/icon-helpers.d.ts +0 -32
  141. package/dist/internals/icon-helpers.js +0 -48
  142. /package/dist/components/{panel/Panel.styles.d.ts → FloatingElement.styles.d.ts} +0 -0
@@ -0,0 +1,114 @@
1
+ import * as arrowClockwise from '../assets/icons/arrow-clockwise.svg.js';
2
+ import * as arrowDown from '../assets/icons/arrow-down.svg.js';
3
+ import * as arrowUp from '../assets/icons/arrow-up.svg.js';
4
+ import * as ban from '../assets/icons/ban.svg.js';
5
+ import * as bellFill from '../assets/icons/bell-fill.svg.js';
6
+ import * as checkCircleFill from '../assets/icons/check-circle-fill.svg.js';
7
+ import * as checkLg from '../assets/icons/check-lg.svg.js';
8
+ import * as chevronDown from '../assets/icons/chevron-down.svg.js';
9
+ import * as chevronLeft from '../assets/icons/chevron-left.svg.js';
10
+ import * as chevronRight from '../assets/icons/chevron-right.svg.js';
11
+ import * as chevronUp from '../assets/icons/chevron-up.svg.js';
12
+ import * as copy from '../assets/icons/copy.svg.js';
13
+ import * as dashLg from '../assets/icons/dash-lg.svg.js';
14
+ import * as exclamationCircleFill from '../assets/icons/exclamation-circle-fill.svg.js';
15
+ import * as exclamationTriangleFill from '../assets/icons/exclamation-triangle-fill.svg.js';
16
+ import * as eyeSlash from '../assets/icons/eye-slash.svg.js';
17
+ import * as eye from '../assets/icons/eye.svg.js';
18
+ import * as infoCircleFill from '../assets/icons/info-circle-fill.svg.js';
19
+ import * as layoutSidebar from '../assets/icons/layout-sidebar.svg.js';
20
+ import * as lightbulbFill from '../assets/icons/lightbulb-fill.svg.js';
21
+ import * as lightbulbOff from '../assets/icons/lightbulb-off.svg.js';
22
+ import * as lightbulb from '../assets/icons/lightbulb.svg.js';
23
+ import * as micFill from '../assets/icons/mic-fill.svg.js';
24
+ import * as micMuteFill from '../assets/icons/mic-mute-fill.svg.js';
25
+ import * as paperclip from '../assets/icons/paperclip.svg.js';
26
+ import * as pencilSquare from '../assets/icons/pencil-square.svg.js';
27
+ import * as plusLg from '../assets/icons/plus-lg.svg.js';
28
+ import * as search from '../assets/icons/search.svg.js';
29
+ import * as speedometer from '../assets/icons/speedometer.svg.js';
30
+ import * as xLg from '../assets/icons/x-lg.svg.js';
31
+
32
+ let defaultIconBaseUrl = "/assets/icons/";
33
+ const defaultIconCache = /* @__PURE__ */ new Map();
34
+ const internalIconBundle = new Map(
35
+ Object.entries(/* #__PURE__ */ Object.assign({"../assets/icons/arrow-clockwise.svg": arrowClockwise,"../assets/icons/arrow-down.svg": arrowDown,"../assets/icons/arrow-up.svg": arrowUp,"../assets/icons/ban.svg": ban,"../assets/icons/bell-fill.svg": bellFill,"../assets/icons/check-circle-fill.svg": checkCircleFill,"../assets/icons/check-lg.svg": checkLg,"../assets/icons/chevron-down.svg": chevronDown,"../assets/icons/chevron-left.svg": chevronLeft,"../assets/icons/chevron-right.svg": chevronRight,"../assets/icons/chevron-up.svg": chevronUp,"../assets/icons/copy.svg": copy,"../assets/icons/dash-lg.svg": dashLg,"../assets/icons/exclamation-circle-fill.svg": exclamationCircleFill,"../assets/icons/exclamation-triangle-fill.svg": exclamationTriangleFill,"../assets/icons/eye-slash.svg": eyeSlash,"../assets/icons/eye.svg": eye,"../assets/icons/info-circle-fill.svg": infoCircleFill,"../assets/icons/layout-sidebar.svg": layoutSidebar,"../assets/icons/lightbulb-fill.svg": lightbulbFill,"../assets/icons/lightbulb-off.svg": lightbulbOff,"../assets/icons/lightbulb.svg": lightbulb,"../assets/icons/mic-fill.svg": micFill,"../assets/icons/mic-mute-fill.svg": micMuteFill,"../assets/icons/paperclip.svg": paperclip,"../assets/icons/pencil-square.svg": pencilSquare,"../assets/icons/plus-lg.svg": plusLg,"../assets/icons/search.svg": search,"../assets/icons/speedometer.svg": speedometer,"../assets/icons/x-lg.svg": xLg
36
+
37
+
38
+ })).map(([path, module]) => {
39
+ const name = path.split("/").pop()?.replace(".svg", "") || "";
40
+ return [name, module.default];
41
+ }).filter(([name]) => name !== "")
42
+ );
43
+ class IconRegistry {
44
+ constructor() {
45
+ this.libs = /* @__PURE__ */ new Map();
46
+ }
47
+ static get instance() {
48
+ if (!this._instance) {
49
+ this._instance = new IconRegistry();
50
+ }
51
+ return this._instance;
52
+ }
53
+ /**
54
+ * 지정된 아이콘 라이브러리가 등록되었는지 확인합니다.
55
+ */
56
+ has(lib) {
57
+ return this.libs.has(lib);
58
+ }
59
+ /**
60
+ * 지정된 아이콘 라이브러리를 등록합니다.
61
+ * 이미 등록된 라이브러리 이름인 경우, 경고 메시지를 출력합니다.
62
+ */
63
+ register(lib, resolver) {
64
+ if (this.libs.has(lib)) {
65
+ console.warn(`Icon library "${lib}" is already registered`);
66
+ } else {
67
+ this.libs.set(lib, resolver);
68
+ }
69
+ }
70
+ /**
71
+ * 지정된 아이콘 라이브러리를 등록 해제합니다.
72
+ */
73
+ unregister(lib) {
74
+ this.libs.delete(lib);
75
+ }
76
+ /**
77
+ * 지정된 아이콘 라이브러리의 svg 아이콘 소스를 가져옵니다.
78
+ */
79
+ async resolve(lib, name) {
80
+ const resolver = this.libs.get(lib);
81
+ if (!resolver) return void 0;
82
+ const svg = await resolver(name);
83
+ return svg?.trim();
84
+ }
85
+ }
86
+ IconRegistry.instance.register("internal", (name) => {
87
+ return internalIconBundle.get(name);
88
+ });
89
+ IconRegistry.instance.register("default", async (name) => {
90
+ if (defaultIconCache.has(name)) {
91
+ return defaultIconCache.get(name);
92
+ }
93
+ const baseUrl = getDefaultBaseUrl();
94
+ const remoteUrl = baseUrl.endsWith("/") ? `${baseUrl}${name}.svg` : `${baseUrl}/${name}.svg`;
95
+ try {
96
+ const response = await fetch(remoteUrl);
97
+ if (!response.ok) return void 0;
98
+ const svg = await response.text();
99
+ defaultIconCache.set(name, svg);
100
+ return svg;
101
+ } catch (error) {
102
+ console.error(error);
103
+ return void 0;
104
+ }
105
+ });
106
+ const icons = IconRegistry.instance;
107
+ function getDefaultBaseUrl() {
108
+ return defaultIconBaseUrl;
109
+ }
110
+ function setDefaultBaseUrl(url) {
111
+ defaultIconBaseUrl = url;
112
+ }
113
+
114
+ export { getDefaultBaseUrl, icons, setDefaultBaseUrl };
@@ -1,4 +1,5 @@
1
1
  export * from './BrowserStorage.js';
2
2
  export * from './decorators';
3
+ export * from './icons.js';
3
4
  export * from './notifier.js';
4
5
  export * from './theme.js';
@@ -1,11 +1,11 @@
1
- import { Alert, AlertType } from '../components/alert/Alert.js';
1
+ import { AlertType } from '../components/alert/Alert.js';
2
2
  export type ScreenPosition = "top-left" | "top-center" | "top-right" | "middle-left" | "middle-center" | "middle-right" | "bottom-left" | "bottom-center" | "bottom-right";
3
3
  /** 토스트 알림 옵션 */
4
4
  export interface ToastOptions {
5
5
  /** 알림 유형 */
6
6
  type: AlertType;
7
7
  /** 알림 제목 */
8
- label?: string;
8
+ heading?: string;
9
9
  /** 알림 내용 */
10
10
  content?: string;
11
11
  /** 알림 표시 시간 (밀리초 단위) */
@@ -14,13 +14,23 @@ export interface ToastOptions {
14
14
  position?: ScreenPosition;
15
15
  }
16
16
  /**
17
- * notifier 객체 여러 위치에 알림을 표시하는 유틸리티입니다.
17
+ * Notifier 클래스 싱글톤 패턴으로 사용합니다.
18
18
  */
19
- export declare const notifier: {
20
- container: Map<ScreenPosition, HTMLDivElement>;
21
- toasts: Set<Alert>;
19
+ declare class Notifier {
20
+ private static _instance;
21
+ private containers;
22
+ private toasts;
23
+ private constructor();
24
+ static get instance(): Notifier;
22
25
  /**
23
26
  * 토스트 알림을 생성합니다.
24
27
  */
25
28
  toast(options: ToastOptions): Promise<void>;
26
- };
29
+ /** 위치에 맞는 컨테이너 엘리먼트를 가져오거나, 생성합니다. */
30
+ private getOrCreateContainer;
31
+ }
32
+ /**
33
+ * 알림 유틸리티 싱글톤 인스턴스입니다.
34
+ */
35
+ export declare const notifier: Notifier;
36
+ export {};
@@ -1,20 +1,28 @@
1
1
  import { Alert } from '../components/alert/Alert.js';
2
2
 
3
3
  Alert.define("u-alert");
4
- const notifier = {
5
- container: /* @__PURE__ */ new Map(),
6
- toasts: /* @__PURE__ */ new Set(),
4
+ class Notifier {
5
+ constructor() {
6
+ this.containers = /* @__PURE__ */ new Map();
7
+ this.toasts = /* @__PURE__ */ new Set();
8
+ }
9
+ static get instance() {
10
+ if (!this._instance) {
11
+ this._instance = new Notifier();
12
+ }
13
+ return this._instance;
14
+ }
7
15
  /**
8
16
  * 토스트 알림을 생성합니다.
9
17
  */
10
18
  async toast(options) {
11
19
  const el = new Alert();
12
20
  el.type = options.type;
13
- el.label = options.label;
21
+ el.heading = options.heading;
14
22
  el.content = options.content;
15
23
  this.toasts.add(el);
16
24
  const position = options.position || "top-right";
17
- const container = getOrCreateContainer(position);
25
+ const container = this.getOrCreateContainer(position);
18
26
  container.appendChild(el);
19
27
  await el.updateComplete;
20
28
  el.show();
@@ -26,46 +34,48 @@ const notifier = {
26
34
  this.toasts.delete(el);
27
35
  if (!container.hasChildNodes()) {
28
36
  container.remove();
29
- this.container.delete(position);
37
+ this.containers.delete(position);
30
38
  }
31
39
  }, duration);
32
40
  }
33
- };
34
- function getOrCreateContainer(position) {
35
- let container = notifier.container.get(position);
36
- if (container) return container;
37
- container = document.createElement("div");
38
- container.style.position = "fixed";
39
- container.style.zIndex = "9999";
40
- container.style.display = "flex";
41
- container.style.gap = "10px";
42
- const transformParts = [];
43
- if (position.startsWith("top")) {
44
- container.style.top = "20px";
45
- container.style.flexDirection = "column";
46
- } else if (position.startsWith("bottom")) {
47
- container.style.bottom = "20px";
48
- container.style.flexDirection = "column-reverse";
49
- } else {
50
- container.style.top = "50%";
51
- container.style.flexDirection = "column";
52
- transformParts.push("translateY(-50%)");
53
- }
54
- if (position.endsWith("left")) {
55
- container.style.left = "20px";
56
- container.style.alignItems = "flex-start";
57
- } else if (position.endsWith("right")) {
58
- container.style.right = "20px";
59
- container.style.alignItems = "flex-end";
60
- } else {
61
- container.style.left = "50%";
62
- container.style.alignItems = "center";
63
- transformParts.unshift("translateX(-50%)");
41
+ /** 위치에 맞는 컨테이너 엘리먼트를 가져오거나, 생성합니다. */
42
+ getOrCreateContainer(position) {
43
+ let container = this.containers.get(position);
44
+ if (container) return container;
45
+ container = document.createElement("div");
46
+ container.style.position = "fixed";
47
+ container.style.zIndex = "9999";
48
+ container.style.display = "flex";
49
+ container.style.gap = "10px";
50
+ const transformParts = [];
51
+ if (position.startsWith("top")) {
52
+ container.style.top = "20px";
53
+ container.style.flexDirection = "column";
54
+ } else if (position.startsWith("bottom")) {
55
+ container.style.bottom = "20px";
56
+ container.style.flexDirection = "column-reverse";
57
+ } else {
58
+ container.style.top = "50%";
59
+ container.style.flexDirection = "column";
60
+ transformParts.push("translateY(-50%)");
61
+ }
62
+ if (position.endsWith("left")) {
63
+ container.style.left = "20px";
64
+ container.style.alignItems = "flex-start";
65
+ } else if (position.endsWith("right")) {
66
+ container.style.right = "20px";
67
+ container.style.alignItems = "flex-end";
68
+ } else {
69
+ container.style.left = "50%";
70
+ container.style.alignItems = "center";
71
+ transformParts.unshift("translateX(-50%)");
72
+ }
73
+ container.style.transform = transformParts.length ? transformParts.join(" ") : "";
74
+ document.body.appendChild(container);
75
+ this.containers.set(position, container);
76
+ return container;
64
77
  }
65
- container.style.transform = transformParts.length ? transformParts.join(" ") : "";
66
- document.body.appendChild(container);
67
- notifier.container.set(position, container);
68
- return container;
69
78
  }
79
+ const notifier = Notifier.instance;
70
80
 
71
81
  export { notifier };
@@ -8,11 +8,6 @@ export interface ThemeInitOptions {
8
8
  * @default false
9
9
  */
10
10
  debug?: boolean;
11
- /**
12
- * 내부적으로 제공되는 스타일 시트를 사용할지 여부
13
- * @default true
14
- */
15
- useBuiltIn?: boolean;
16
11
  /**
17
12
  * 테마 설정을 브라우저 스토리지에 영구 저장할지 여부 또는 옵션
18
13
  * @default false
@@ -23,24 +18,27 @@ export interface ThemeInitOptions {
23
18
  * @default 'system'
24
19
  */
25
20
  default?: ThemeType;
21
+ /**
22
+ * 내부적으로 제공되는 스타일 시트를 사용할지 여부
23
+ * @default true
24
+ */
25
+ useBuiltIn?: boolean;
26
26
  }
27
27
  /**
28
- * Theme 클래스 싱글톤 패턴으로 사용합니다.
28
+ * 현재 문서에 테마를 적용하고 관리하는 유틸리티 클래스입니다.
29
29
  */
30
- export declare class Theme {
30
+ declare class Theme {
31
31
  private static _instance;
32
- private readonly STORAGE_KEY_DEFAULT;
32
+ private readonly STORAGE_THEME_KEY;
33
33
  private storage;
34
34
  private _isInitialized;
35
35
  private _isDebugMode;
36
- /** private 생성자 — 외부에서 new Theme()를 할 수 없게 함 */
37
36
  private constructor();
38
- /** 싱글톤 인스턴스 접근자 */
39
37
  static get instance(): Theme;
40
- /** 외부에서 현재 초기화 상태를 확인할 수 있게 getter 제공 */
41
38
  get isInitialized(): boolean;
39
+ get isDebugMode(): boolean;
42
40
  /**
43
- * 테마 유틸리티 초기화
41
+ * 테마 유틸리티를 초기화합니다.
44
42
  */
45
43
  init(options?: ThemeInitOptions): Promise<void>;
46
44
  /**
@@ -48,19 +46,16 @@ export declare class Theme {
48
46
  */
49
47
  get(): ThemeType | undefined;
50
48
  /**
51
- * 현재 문서 테마를 설정합니다.
49
+ * 현재 문서에 적용할 테마를 설정합니다.
52
50
  */
53
51
  set(theme: ThemeType): void;
54
- /**
55
- * 시스템 테마 변경을 처리하는 메서드
56
- */
52
+ /** 시스템 테마 변경을 처리하는 메서드 */
57
53
  private handleSystemThemeChanged;
58
- /**
59
- * 디버그 모드시 로그 출력 함수 (인스턴스 스코프)
60
- */
54
+ /** 디버그 모드시 로그 출력 함수 (인스턴스 스코프) */
61
55
  private log;
62
56
  }
63
57
  /**
64
- * 테마 유틸리티 싱글톤 인스턴스입니다.
58
+ * 테마 유틸리티의 싱글톤 인스턴스입니다.
65
59
  */
66
60
  export declare const theme: Theme;
61
+ export {};
@@ -2,7 +2,7 @@ import * as dark from '../assets/styles/dark.css.js';
2
2
  import * as light from '../assets/styles/light.css.js';
3
3
  import { BrowserStorage } from './BrowserStorage.js';
4
4
 
5
- const styleAssets = Object.entries(/* #__PURE__ */ Object.assign({"../assets/styles/dark.css": dark,"../assets/styles/light.css": light
5
+ const styleBundle = Object.entries(/* #__PURE__ */ Object.assign({"../assets/styles/dark.css": dark,"../assets/styles/light.css": light
6
6
 
7
7
 
8
8
  })).map(([path, module]) => {
@@ -10,61 +10,67 @@ const styleAssets = Object.entries(/* #__PURE__ */ Object.assign({"../assets/sty
10
10
  return [name, module.default];
11
11
  }).filter(([name]) => name !== "");
12
12
  class Theme {
13
- /** private 생성자 — 외부에서 new Theme()를 할 수 없게 함 */
14
13
  constructor() {
15
- this.STORAGE_KEY_DEFAULT = "theme";
14
+ this.STORAGE_THEME_KEY = "theme";
16
15
  this.storage = null;
17
16
  this._isInitialized = false;
18
17
  this._isDebugMode = false;
19
- /**
20
- * 시스템 테마 변경을 처리하는 메서드
21
- */
18
+ /** 시스템 테마 변경을 처리하는 메서드 */
22
19
  this.handleSystemThemeChanged = (_) => {
23
20
  if (document.documentElement.getAttribute("data-theme") === "system") {
24
21
  const isDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
25
22
  document.documentElement.setAttribute("theme", isDark ? "dark" : "light");
23
+ this.log("system theme changed, applied", isDark ? "dark" : "light");
26
24
  }
27
25
  };
28
26
  }
29
- /** 싱글톤 인스턴스 접근자 */
30
27
  static get instance() {
31
28
  if (!this._instance) {
32
29
  this._instance = new Theme();
33
30
  }
34
31
  return this._instance;
35
32
  }
36
- /** 외부에서 현재 초기화 상태를 확인할 수 있게 getter 제공 */
37
33
  get isInitialized() {
38
34
  return this._isInitialized;
39
35
  }
36
+ get isDebugMode() {
37
+ return this._isDebugMode;
38
+ }
40
39
  /**
41
- * 테마 유틸리티 초기화
40
+ * 테마 유틸리티를 초기화합니다.
42
41
  */
43
42
  async init(options) {
44
43
  this._isDebugMode = options?.debug || false;
45
44
  this.log("init called", { options });
46
45
  if (options?.store) {
47
- this.log("store option provided, initializing BrowserStorage");
48
46
  this.storage = new BrowserStorage(options.store);
47
+ this.log("store option provided, initializing BrowserStorage");
48
+ } else {
49
+ this.storage = null;
50
+ this.log("no store option provided, skipping BrowserStorage initialization");
49
51
  }
50
52
  const useBuiltIn = options?.useBuiltIn ?? true;
51
53
  if (useBuiltIn) {
52
54
  this.log("Import enabled: loading styles via internal assets");
53
- for (let [name, module] of styleAssets) {
55
+ for (let [name, module] of styleBundle) {
54
56
  const style = document.createElement("style");
55
- style.setAttribute("data-path", name);
57
+ style.setAttribute("data-name", name);
56
58
  style.textContent = module;
57
- if (document.head.querySelector(`style[data-path="${name}"]`)) {
59
+ if (document.head.querySelector(`style[data-name="${name}"]`)) {
58
60
  this.log("style already present, skipping", name);
59
61
  continue;
60
62
  }
61
63
  document.head.appendChild(style);
62
64
  this.log("appended style to head", name);
63
65
  }
66
+ } else {
67
+ const styleHead = document.head.querySelectorAll("style[data-name]");
68
+ styleHead.forEach((el) => el.remove());
69
+ this.log("Import disabled: removed internal styles from head");
64
70
  }
65
71
  let theme2 = options?.default ?? "system";
66
72
  if (this.storage !== null) {
67
- const savedTheme = await this.storage.get(this.STORAGE_KEY_DEFAULT);
73
+ const savedTheme = await this.storage.get(this.STORAGE_THEME_KEY);
68
74
  if (savedTheme) {
69
75
  theme2 = savedTheme;
70
76
  this.log("loaded theme from storage", theme2);
@@ -93,7 +99,7 @@ class Theme {
93
99
  }
94
100
  }
95
101
  /**
96
- * 현재 문서 테마를 설정합니다.
102
+ * 현재 문서에 적용할 테마를 설정합니다.
97
103
  */
98
104
  set(theme2) {
99
105
  try {
@@ -120,17 +126,15 @@ class Theme {
120
126
  this.log("Error applying theme:", e);
121
127
  }
122
128
  if (this.storage !== null) {
123
- this.storage.set(this.STORAGE_KEY_DEFAULT, theme2);
129
+ this.storage.set(this.STORAGE_THEME_KEY, theme2);
124
130
  this.log("saved theme to storage", theme2);
125
131
  }
126
132
  }
127
- /**
128
- * 디버그 모드시 로그 출력 함수 (인스턴스 스코프)
129
- */
133
+ /** 디버그 모드시 로그 출력 함수 (인스턴스 스코프) */
130
134
  log(...args) {
131
135
  if (this._isDebugMode) console.log("[theme]", ...args);
132
136
  }
133
137
  }
134
138
  const theme = Theme.instance;
135
139
 
136
- export { Theme, theme };
140
+ export { theme };
package/package.json CHANGED
@@ -1,58 +1,59 @@
1
- {
2
- "name": "@iyulab/components",
3
- "description": "web-components library by iyulab based on lit-element",
4
- "version": "0.1.4",
5
- "keywords": [
6
- "iyulab",
7
- "web-components",
8
- "lit-element"
9
- ],
10
- "license": "MIT",
11
- "author": "iyulab",
12
- "repository": {
13
- "type": "git",
14
- "url": "https://github.com/iyulab/node-components.git"
15
- },
16
- "files": [
17
- "dist",
18
- "LICENSE",
19
- "README.md",
20
- "CHANGELOG.md",
21
- "package.json"
22
- ],
23
- "type": "module",
24
- "types": "./dist/index.d.ts",
25
- "exports": {
26
- ".": {
27
- "types": "./dist/index.d.ts",
28
- "import": "./dist/index.js"
29
- },
30
- "./dist/*": {
31
- "types": "./dist/*.d.ts",
32
- "import": "./dist/*"
33
- }
34
- },
35
- "scripts": {
36
- "start": "vite --force",
37
- "build": "eslint && vite build"
38
- },
39
- "dependencies": {
40
- "@floating-ui/dom": "^1.7.4",
41
- "lit": "^3.3.1",
42
- "react": "^19.2.1",
43
- "reflect-metadata": "^0.2.2"
44
- },
45
- "devDependencies": {
46
- "@lit/react": "^1.0.8",
47
- "@eslint/js": "^9.39.1",
48
- "@types/node": "^24.10.1",
49
- "eslint": "^9.39.1",
50
- "eslint-plugin-lit": "^2.1.1",
51
- "globals": "^16.5.0",
52
- "typescript": "^5.9.3",
53
- "typescript-eslint": "^8.48.1",
54
- "vite": "^7.2.6",
55
- "vite-plugin-dts": "^4.5.4",
56
- "vite-plugin-static-copy": "^3.1.4"
57
- }
58
- }
1
+ {
2
+ "name": "@iyulab/components",
3
+ "description": "web-components library based on lit-element made by iyulab",
4
+ "version": "0.1.6",
5
+ "keywords": [
6
+ "iyulab",
7
+ "components",
8
+ "web-components",
9
+ "lit-element"
10
+ ],
11
+ "license": "MIT",
12
+ "author": "iyulab",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/iyulab/node-components.git"
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "LICENSE",
20
+ "README.md",
21
+ "CHANGELOG.md",
22
+ "package.json"
23
+ ],
24
+ "type": "module",
25
+ "types": "./dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./src/index.d.ts",
29
+ "import": "./src/index.js"
30
+ },
31
+ "./dist/*": {
32
+ "types": "./src/*.d.ts",
33
+ "import": "./src/*"
34
+ }
35
+ },
36
+ "scripts": {
37
+ "start": "vite --force",
38
+ "build": "eslint && vite build"
39
+ },
40
+ "dependencies": {
41
+ "@floating-ui/dom": "^1.7.4",
42
+ "lit": "^3.3.1",
43
+ "react": "^19.2.3",
44
+ "reflect-metadata": "^0.2.2"
45
+ },
46
+ "devDependencies": {
47
+ "@lit/react": "^1.0.8",
48
+ "@eslint/js": "^9.39.1",
49
+ "@types/node": "^25.0.1",
50
+ "eslint": "^9.39.1",
51
+ "eslint-plugin-lit": "^2.1.1",
52
+ "globals": "^16.5.0",
53
+ "typescript": "^5.9.3",
54
+ "typescript-eslint": "^8.49.0",
55
+ "vite": "^7.2.7",
56
+ "vite-plugin-dts": "^4.5.4",
57
+ "vite-plugin-static-copy": "^3.1.4"
58
+ }
59
+ }
@@ -1,9 +0,0 @@
1
- import { BaseElement } from '../BaseElement.js';
2
- /**
3
- * 각 패널은 독립적인 크기와 콘텐츠를 가질 수 있습니다.
4
- */
5
- export declare class Panel extends BaseElement {
6
- static styles: import('lit').CSSResultGroup[];
7
- static dependencies: Record<string, typeof BaseElement>;
8
- render(): import('lit-html').TemplateResult<1>;
9
- }
@@ -1,17 +0,0 @@
1
- import { html } from 'lit';
2
- import { BaseElement } from '../BaseElement.js';
3
- import { styles } from './Panel.styles.js';
4
-
5
- class Panel extends BaseElement {
6
- static {
7
- this.styles = [super.styles, styles];
8
- }
9
- static {
10
- this.dependencies = {};
11
- }
12
- render() {
13
- return html`<slot></slot>`;
14
- }
15
- }
16
-
17
- export { Panel };
@@ -1,12 +0,0 @@
1
- import { css } from 'lit';
2
-
3
- const styles = css`
4
- :host {
5
- position: relative;
6
- display: block;
7
- width: 100%;
8
- height: 100%;
9
- }
10
- `;
11
-
12
- export { styles };
@@ -1,7 +0,0 @@
1
- import { Panel } from './Panel.js';
2
- declare global {
3
- interface HTMLElementTagNameMap {
4
- 'u-panel': Panel;
5
- }
6
- }
7
- export { Panel };
@@ -1,8 +0,0 @@
1
- import React from 'react';
2
- import { Panel } from '../../components/panel/index';
3
-
4
- export declare const UPanel: React.ForwardRefExoticComponent<
5
- Partial<Panel> & React.HTMLAttributes<Panel>
6
- >;
7
-
8
- export type UPanelProps = React.ComponentProps<typeof UPanel>;