@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.
Files changed (77) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/dist/assets/icons/arrow-repeat.svg.js +3 -0
  3. package/dist/assets/icons/box-arrow-up-right.svg.js +3 -0
  4. package/dist/assets/icons/file-earmark.svg.js +3 -0
  5. package/dist/assets/icons/flag.svg.js +3 -0
  6. package/dist/assets/icons/globe.svg.js +3 -0
  7. package/dist/assets/icons/hand-thumbs-down-fill.svg.js +3 -0
  8. package/dist/assets/icons/hand-thumbs-down.svg.js +3 -0
  9. package/dist/assets/icons/hand-thumbs-up-fill.svg.js +3 -0
  10. package/dist/assets/icons/hand-thumbs-up.svg.js +3 -0
  11. package/dist/assets/icons/share.svg.js +3 -0
  12. package/dist/assets/icons/stop-circle.svg.js +3 -0
  13. package/dist/assets/icons/tools.svg.js +3 -0
  14. package/dist/components/FloatingElement.d.ts +13 -5
  15. package/dist/components/FloatingElement.js +32 -15
  16. package/dist/components/FloatingElement.styles.js +0 -4
  17. package/dist/components/button/UButton.component.d.ts +7 -0
  18. package/dist/components/button/UButton.component.js +20 -1
  19. package/dist/components/button/UButton.styles.js +51 -8
  20. package/dist/components/dialog/UDialog.component.d.ts +2 -0
  21. package/dist/components/dialog/UDialog.component.js +14 -9
  22. package/dist/components/divider/UDivider.component.d.ts +3 -18
  23. package/dist/components/divider/UDivider.component.js +3 -62
  24. package/dist/components/divider/UDivider.styles.js +11 -43
  25. package/dist/components/drawer/UDrawer.component.d.ts +2 -0
  26. package/dist/components/drawer/UDrawer.component.js +14 -9
  27. package/dist/components/form/UForm.component.js +3 -3
  28. package/dist/components/icon/UIcon.component.d.ts +4 -1
  29. package/dist/components/icon/UIcon.component.js +2 -2
  30. package/dist/components/menu/UMenu.component.d.ts +4 -7
  31. package/dist/components/menu/UMenu.component.js +94 -83
  32. package/dist/components/menu/UMenu.styles.js +1 -1
  33. package/dist/components/menu-item/UMenuItem.component.d.ts +10 -4
  34. package/dist/components/menu-item/UMenuItem.component.js +37 -26
  35. package/dist/components/menu-item/UMenuItem.styles.js +4 -4
  36. package/dist/components/split-panel/USplitPanel.component.d.ts +22 -8
  37. package/dist/components/split-panel/USplitPanel.component.js +121 -75
  38. package/dist/components/split-panel/USplitPanel.styles.js +30 -0
  39. package/dist/components/tag/UTag.component.d.ts +23 -0
  40. package/dist/components/tag/UTag.component.js +72 -0
  41. package/dist/components/tag/UTag.d.ts +8 -0
  42. package/dist/components/tag/UTag.js +5 -0
  43. package/dist/components/tag/UTag.styles.js +83 -0
  44. package/dist/components/tooltip/UTooltip.component.d.ts +8 -0
  45. package/dist/components/tooltip/UTooltip.component.js +59 -17
  46. package/dist/components/tooltip/UTooltip.styles.js +15 -0
  47. package/dist/components/tree-item/UTreeItem.component.d.ts +16 -8
  48. package/dist/components/tree-item/UTreeItem.component.js +69 -31
  49. package/dist/components/tree-item/UTreeItem.styles.js +8 -3
  50. package/dist/index.d.ts +4 -3
  51. package/dist/index.js +5 -4
  52. package/dist/react-components/UTag.d.ts +8 -0
  53. package/dist/react-components/UTag.js +10 -0
  54. package/dist/react-components/index.d.ts +1 -1
  55. package/dist/react-components/index.js +1 -1
  56. package/dist/utilities/{icons.d.ts → IconRegistry.d.ts} +20 -26
  57. package/dist/utilities/{icons.js → IconRegistry.js} +29 -20
  58. package/dist/utilities/{notifier.d.ts → Notifier.d.ts} +8 -13
  59. package/dist/utilities/{notifier.js → Notifier.js} +8 -10
  60. package/dist/utilities/{theme.d.ts → Theme.d.ts} +14 -20
  61. package/dist/utilities/{theme.js → Theme.js} +39 -35
  62. package/dist/{internals/attribute-converters.d.ts → utilities/converters.d.ts} +1 -1
  63. package/dist/{internals/attribute-converters.js → utilities/converters.js} +2 -2
  64. package/dist/{internals/node-helpers.js → utilities/elements.js} +6 -5
  65. package/package.json +7 -7
  66. package/dist/assets/icons/arrow-clockwise.svg.js +0 -3
  67. package/dist/assets/icons/speedometer.svg.js +0 -3
  68. package/dist/components/icon-button/UIconButton.component.d.ts +0 -20
  69. package/dist/components/icon-button/UIconButton.component.js +0 -59
  70. package/dist/components/icon-button/UIconButton.d.ts +0 -7
  71. package/dist/components/icon-button/UIconButton.js +0 -5
  72. package/dist/components/icon-button/UIconButton.styles.js +0 -54
  73. package/dist/internals/react-wrapper.d.ts +0 -21
  74. package/dist/react-components/UIconButton.d.ts +0 -8
  75. package/dist/react-components/UIconButton.js +0 -10
  76. /package/dist/components/{icon-button/UIconButton.styles.d.ts → tag/UTag.styles.d.ts} +0 -0
  77. /package/dist/{internals/node-helpers.d.ts → utilities/elements.d.ts} +0 -0
@@ -1,8 +1,9 @@
1
- import * as arrowClockwise from '../assets/icons/arrow-clockwise.svg.js';
2
1
  import * as arrowDown from '../assets/icons/arrow-down.svg.js';
2
+ import * as arrowRepeat from '../assets/icons/arrow-repeat.svg.js';
3
3
  import * as arrowUp from '../assets/icons/arrow-up.svg.js';
4
4
  import * as ban from '../assets/icons/ban.svg.js';
5
5
  import * as bellFill from '../assets/icons/bell-fill.svg.js';
6
+ import * as boxArrowUpRight from '../assets/icons/box-arrow-up-right.svg.js';
6
7
  import * as checkCircleFill from '../assets/icons/check-circle-fill.svg.js';
7
8
  import * as checkLg from '../assets/icons/check-lg.svg.js';
8
9
  import * as chevronDown from '../assets/icons/chevron-down.svg.js';
@@ -15,6 +16,13 @@ import * as exclamationCircleFill from '../assets/icons/exclamation-circle-fill.
15
16
  import * as exclamationTriangleFill from '../assets/icons/exclamation-triangle-fill.svg.js';
16
17
  import * as eyeSlash from '../assets/icons/eye-slash.svg.js';
17
18
  import * as eye from '../assets/icons/eye.svg.js';
19
+ import * as fileEarmark from '../assets/icons/file-earmark.svg.js';
20
+ import * as flag from '../assets/icons/flag.svg.js';
21
+ import * as globe from '../assets/icons/globe.svg.js';
22
+ import * as handThumbsDownFill from '../assets/icons/hand-thumbs-down-fill.svg.js';
23
+ import * as handThumbsDown from '../assets/icons/hand-thumbs-down.svg.js';
24
+ import * as handThumbsUpFill from '../assets/icons/hand-thumbs-up-fill.svg.js';
25
+ import * as handThumbsUp from '../assets/icons/hand-thumbs-up.svg.js';
18
26
  import * as infoCircleFill from '../assets/icons/info-circle-fill.svg.js';
19
27
  import * as layoutSidebar from '../assets/icons/layout-sidebar.svg.js';
20
28
  import * as lightbulbFill from '../assets/icons/lightbulb-fill.svg.js';
@@ -26,13 +34,21 @@ import * as paperclip from '../assets/icons/paperclip.svg.js';
26
34
  import * as pencilSquare from '../assets/icons/pencil-square.svg.js';
27
35
  import * as plusLg from '../assets/icons/plus-lg.svg.js';
28
36
  import * as search from '../assets/icons/search.svg.js';
29
- import * as speedometer from '../assets/icons/speedometer.svg.js';
37
+ import * as share from '../assets/icons/share.svg.js';
38
+ import * as stopCircle from '../assets/icons/stop-circle.svg.js';
39
+ import * as tools from '../assets/icons/tools.svg.js';
30
40
  import * as xLg from '../assets/icons/x-lg.svg.js';
31
41
 
32
42
  let defaultIconBaseUrl = "/assets/icons/";
43
+ function getDefaultBaseUrl() {
44
+ return defaultIconBaseUrl;
45
+ }
46
+ function setDefaultBaseUrl(url) {
47
+ defaultIconBaseUrl = url;
48
+ }
33
49
  const defaultIconCache = /* @__PURE__ */ new Map();
34
50
  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
51
+ Object.entries(/* #__PURE__ */ Object.assign({"../assets/icons/arrow-down.svg": arrowDown,"../assets/icons/arrow-repeat.svg": arrowRepeat,"../assets/icons/arrow-up.svg": arrowUp,"../assets/icons/ban.svg": ban,"../assets/icons/bell-fill.svg": bellFill,"../assets/icons/box-arrow-up-right.svg": boxArrowUpRight,"../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/file-earmark.svg": fileEarmark,"../assets/icons/flag.svg": flag,"../assets/icons/globe.svg": globe,"../assets/icons/hand-thumbs-down-fill.svg": handThumbsDownFill,"../assets/icons/hand-thumbs-down.svg": handThumbsDown,"../assets/icons/hand-thumbs-up-fill.svg": handThumbsUpFill,"../assets/icons/hand-thumbs-up.svg": handThumbsUp,"../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/share.svg": share,"../assets/icons/stop-circle.svg": stopCircle,"../assets/icons/tools.svg": tools,"../assets/icons/x-lg.svg": xLg
36
52
 
37
53
 
38
54
  })).map(([path, module]) => {
@@ -41,26 +57,23 @@ const internalIconBundle = new Map(
41
57
  }).filter(([name]) => name !== "")
42
58
  );
43
59
  class IconRegistry {
44
- constructor() {
60
+ static {
45
61
  this.libs = /* @__PURE__ */ new Map();
46
62
  }
47
- static get instance() {
48
- if (!this._instance) {
49
- this._instance = new IconRegistry();
50
- }
51
- return this._instance;
63
+ /** 클래스 생성 방지 */
64
+ constructor() {
52
65
  }
53
66
  /**
54
67
  * 지정된 아이콘 라이브러리가 등록되었는지 확인합니다.
55
68
  */
56
- has(lib) {
69
+ static has(lib) {
57
70
  return this.libs.has(lib);
58
71
  }
59
72
  /**
60
73
  * 지정된 아이콘 라이브러리를 등록합니다.
61
74
  * 이미 등록된 라이브러리 이름인 경우, 경고 메시지를 출력합니다.
62
75
  */
63
- register(lib, resolver) {
76
+ static register(lib, resolver) {
64
77
  if (this.libs.has(lib)) {
65
78
  console.warn(`Icon library "${lib}" is already registered`);
66
79
  } else {
@@ -70,23 +83,23 @@ class IconRegistry {
70
83
  /**
71
84
  * 지정된 아이콘 라이브러리를 등록 해제합니다.
72
85
  */
73
- unregister(lib) {
86
+ static unregister(lib) {
74
87
  this.libs.delete(lib);
75
88
  }
76
89
  /**
77
90
  * 지정된 아이콘 라이브러리의 svg 아이콘 소스를 가져옵니다.
78
91
  */
79
- async resolve(lib, name) {
92
+ static async resolve(lib, name) {
80
93
  const resolver = this.libs.get(lib);
81
94
  if (!resolver) return void 0;
82
95
  const svg = await resolver(name);
83
96
  return svg?.trim();
84
97
  }
85
98
  }
86
- IconRegistry.instance.register("internal", (name) => {
99
+ IconRegistry.register("internal", (name) => {
87
100
  return internalIconBundle.get(name);
88
101
  });
89
- IconRegistry.instance.register("default", async (name) => {
102
+ IconRegistry.register("default", async (name) => {
90
103
  if (defaultIconCache.has(name)) {
91
104
  return defaultIconCache.get(name);
92
105
  }
@@ -103,9 +116,5 @@ IconRegistry.instance.register("default", async (name) => {
103
116
  return void 0;
104
117
  }
105
118
  });
106
- const icons = IconRegistry.instance;
107
- function getDefaultBaseUrl() {
108
- return defaultIconBaseUrl;
109
- }
110
119
 
111
- export { getDefaultBaseUrl, icons };
120
+ export { IconRegistry, getDefaultBaseUrl, setDefaultBaseUrl };
@@ -1,4 +1,5 @@
1
1
  import { AlertType } from '../components/alert/UAlert.component.js';
2
+ /** 토스트 알림의 화면 위치 타입 */
2
3
  export type ScreenPosition = "top-left" | "top-center" | "top-right" | "middle-left" | "middle-center" | "middle-right" | "bottom-left" | "bottom-center" | "bottom-right";
3
4
  /** 토스트 알림 옵션 */
4
5
  export interface ToastOptions {
@@ -14,23 +15,17 @@ export interface ToastOptions {
14
15
  position?: ScreenPosition;
15
16
  }
16
17
  /**
17
- * Notifier 클래스 싱글톤 패턴으로 사용합니다.
18
+ * 알림 유틸리티 전역 인스턴스입니다.
18
19
  */
19
- declare class Notifier {
20
- private static _instance;
21
- private containers;
22
- private toasts;
20
+ export declare class Notifier {
21
+ private static containers;
22
+ private static toasts;
23
+ /** 개별 인스턴스 생성을 방지합니다. */
23
24
  private constructor();
24
- static get instance(): Notifier;
25
25
  /**
26
26
  * 토스트 알림을 생성합니다.
27
27
  */
28
- toast(options: ToastOptions): Promise<void>;
28
+ static toast(options: ToastOptions): Promise<void>;
29
29
  /** 위치에 맞는 컨테이너 엘리먼트를 가져오거나, 생성합니다. */
30
- private getOrCreateContainer;
30
+ private static getOrCreateContainer;
31
31
  }
32
- /**
33
- * 알림 유틸리티 싱글톤 인스턴스입니다.
34
- */
35
- export declare const notifier: Notifier;
36
- export {};
@@ -2,20 +2,19 @@ import { UAlert } from '../components/alert/UAlert.component.js';
2
2
 
3
3
  UAlert.define("u-alert");
4
4
  class Notifier {
5
- constructor() {
5
+ static {
6
6
  this.containers = /* @__PURE__ */ new Map();
7
+ }
8
+ static {
7
9
  this.toasts = /* @__PURE__ */ new Set();
8
10
  }
9
- static get instance() {
10
- if (!this._instance) {
11
- this._instance = new Notifier();
12
- }
13
- return this._instance;
11
+ /** 개별 인스턴스 생성을 방지합니다. */
12
+ constructor() {
14
13
  }
15
14
  /**
16
15
  * 토스트 알림을 생성합니다.
17
16
  */
18
- async toast(options) {
17
+ static async toast(options) {
19
18
  const el = new UAlert();
20
19
  el.type = options.type;
21
20
  el.heading = options.heading;
@@ -39,7 +38,7 @@ class Notifier {
39
38
  }, duration);
40
39
  }
41
40
  /** 위치에 맞는 컨테이너 엘리먼트를 가져오거나, 생성합니다. */
42
- getOrCreateContainer(position) {
41
+ static getOrCreateContainer(position) {
43
42
  let container = this.containers.get(position);
44
43
  if (container) return container;
45
44
  container = document.createElement("div");
@@ -76,6 +75,5 @@ class Notifier {
76
75
  return container;
77
76
  }
78
77
  }
79
- const notifier = Notifier.instance;
80
78
 
81
- export { notifier };
79
+ export { Notifier };
@@ -25,37 +25,31 @@ export interface ThemeInitOptions {
25
25
  useBuiltIn?: boolean;
26
26
  }
27
27
  /**
28
- * 현재 문서에 테마를 적용하고 관리하는 유틸리티 클래스입니다.
28
+ * 현재 문서에 테마를 적용하고 관리하는 유틸리티 전역 인스턴스입니다.
29
29
  */
30
- declare class Theme {
31
- private static _instance;
32
- private readonly STORAGE_THEME_KEY;
33
- private storage;
34
- private _isInitialized;
35
- private _isDebugMode;
30
+ export declare class Theme {
31
+ private static readonly STORAGE_THEME_KEY;
32
+ private static storage;
33
+ private static _isInitialized;
34
+ private static _isDebugMode;
35
+ /** 개별 인스턴스 생성을 방지합니다. */
36
36
  private constructor();
37
- static get instance(): Theme;
38
- get isInitialized(): boolean;
39
- get isDebugMode(): boolean;
37
+ static get isInitialized(): boolean;
38
+ static get isDebugMode(): boolean;
40
39
  /**
41
40
  * 테마 유틸리티를 초기화합니다.
42
41
  */
43
- init(options?: ThemeInitOptions): Promise<void>;
42
+ static init(options?: ThemeInitOptions): Promise<void>;
44
43
  /**
45
44
  * 현재 문서에 적용된 테마를 가져옵니다.
46
45
  */
47
- get(): ThemeType | undefined;
46
+ static get(): ThemeType | undefined;
48
47
  /**
49
48
  * 현재 문서에 적용할 테마를 설정합니다.
50
49
  */
51
- set(theme: ThemeType): void;
50
+ static set(theme: ThemeType): void;
52
51
  /** 시스템 테마 변경을 처리하는 메서드 */
53
- private handleSystemThemeChanged;
52
+ private static handleSystemThemeChanged;
54
53
  /** 디버그 모드시 로그 출력 함수 (인스턴스 스코프) */
55
- private log;
54
+ private static log;
56
55
  }
57
- /**
58
- * 테마 유틸리티의 싱글톤 인스턴스입니다.
59
- */
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 styleBundle = Object.entries(/* #__PURE__ */ Object.assign({"../assets/styles/dark.css": dark,"../assets/styles/light.css": light
5
+ const styleSheetBundle = 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,36 +10,31 @@ const styleBundle = Object.entries(/* #__PURE__ */ Object.assign({"../assets/sty
10
10
  return [name, module.default];
11
11
  }).filter(([name]) => name !== "");
12
12
  class Theme {
13
- constructor() {
13
+ static {
14
14
  this.STORAGE_THEME_KEY = "theme";
15
+ }
16
+ static {
15
17
  this.storage = null;
18
+ }
19
+ static {
16
20
  this._isInitialized = false;
21
+ }
22
+ static {
17
23
  this._isDebugMode = false;
18
- /** 시스템 테마 변경을 처리하는 메서드 */
19
- this.handleSystemThemeChanged = (_) => {
20
- if (document.documentElement.getAttribute("data-theme") === "system") {
21
- const isDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
22
- document.documentElement.setAttribute("theme", isDark ? "dark" : "light");
23
- this.log("system theme changed, applied", isDark ? "dark" : "light");
24
- }
25
- };
26
24
  }
27
- static get instance() {
28
- if (!this._instance) {
29
- this._instance = new Theme();
30
- }
31
- return this._instance;
25
+ /** 개별 인스턴스 생성을 방지합니다. */
26
+ constructor() {
32
27
  }
33
- get isInitialized() {
28
+ static get isInitialized() {
34
29
  return this._isInitialized;
35
30
  }
36
- get isDebugMode() {
31
+ static get isDebugMode() {
37
32
  return this._isDebugMode;
38
33
  }
39
34
  /**
40
35
  * 테마 유틸리티를 초기화합니다.
41
36
  */
42
- async init(options) {
37
+ static async init(options) {
43
38
  this._isDebugMode = options?.debug || false;
44
39
  this.log("init called", { options });
45
40
  if (options?.store) {
@@ -52,7 +47,7 @@ class Theme {
52
47
  const useBuiltIn = options?.useBuiltIn ?? true;
53
48
  if (useBuiltIn) {
54
49
  this.log("Import enabled: loading styles via internal assets");
55
- for (let [name, module] of styleBundle) {
50
+ for (let [name, module] of styleSheetBundle) {
56
51
  const style = document.createElement("style");
57
52
  style.setAttribute("data-name", name);
58
53
  style.textContent = module;
@@ -68,24 +63,24 @@ class Theme {
68
63
  styleHead.forEach((el) => el.remove());
69
64
  this.log("Import disabled: removed internal styles from head");
70
65
  }
71
- let theme2 = options?.default ?? "system";
66
+ let theme = options?.default ?? "system";
72
67
  if (this.storage !== null) {
73
68
  const savedTheme = await this.storage.get(this.STORAGE_THEME_KEY);
74
69
  if (savedTheme) {
75
- theme2 = savedTheme;
76
- this.log("loaded theme from storage", theme2);
70
+ theme = savedTheme;
71
+ this.log("loaded theme from storage", theme);
77
72
  } else {
78
- this.log("no saved theme in storage, using default", theme2);
73
+ this.log("no saved theme in storage, using default", theme);
79
74
  }
80
75
  }
81
- this.set(theme2);
76
+ this.set(theme);
82
77
  this._isInitialized = true;
83
78
  this.log("theme initialized");
84
79
  }
85
80
  /**
86
81
  * 현재 문서에 적용된 테마를 가져옵니다.
87
82
  */
88
- get() {
83
+ static get() {
89
84
  const attr = document.documentElement.getAttribute("data-theme");
90
85
  switch (attr) {
91
86
  case "system":
@@ -101,40 +96,49 @@ class Theme {
101
96
  /**
102
97
  * 현재 문서에 적용할 테마를 설정합니다.
103
98
  */
104
- set(theme2) {
99
+ static set(theme) {
105
100
  try {
106
101
  const media = window.matchMedia("(prefers-color-scheme: dark)");
107
- if (theme2 === "system") {
102
+ if (theme === "system") {
108
103
  document.documentElement.setAttribute("data-theme", "system");
109
104
  media.addEventListener("change", this.handleSystemThemeChanged);
110
105
  this.handleSystemThemeChanged();
111
106
  this.log("system theme applied (data-theme=system)");
112
- } else if (theme2 === "dark") {
107
+ } else if (theme === "dark") {
113
108
  media.removeEventListener("change", this.handleSystemThemeChanged);
114
109
  document.documentElement.setAttribute("data-theme", "dark");
115
110
  document.documentElement.setAttribute("theme", "dark");
116
111
  this.log("dark theme applied (data-theme=dark, theme=dark)");
117
- } else if (theme2 === "light") {
112
+ } else if (theme === "light") {
118
113
  media.removeEventListener("change", this.handleSystemThemeChanged);
119
114
  document.documentElement.setAttribute("data-theme", "light");
120
115
  document.documentElement.setAttribute("theme", "light");
121
116
  this.log("light theme applied (data-theme=light, theme=light)");
122
117
  } else {
123
- throw new Error(`Invalid theme: ${theme2}. Use 'light', 'dark', or 'system'.`);
118
+ throw new Error(`Invalid theme: ${theme}. Use 'light', 'dark', or 'system'.`);
124
119
  }
125
120
  } catch (e) {
126
121
  this.log("Error applying theme:", e);
127
122
  }
128
123
  if (this.storage !== null) {
129
- this.storage.set(this.STORAGE_THEME_KEY, theme2);
130
- this.log("saved theme to storage", theme2);
124
+ this.storage.set(this.STORAGE_THEME_KEY, theme);
125
+ this.log("saved theme to storage", theme);
131
126
  }
132
127
  }
128
+ static {
129
+ /** 시스템 테마 변경을 처리하는 메서드 */
130
+ this.handleSystemThemeChanged = (_) => {
131
+ if (document.documentElement.getAttribute("data-theme") === "system") {
132
+ const isDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
133
+ document.documentElement.setAttribute("theme", isDark ? "dark" : "light");
134
+ this.log("system theme changed, applied", isDark ? "dark" : "light");
135
+ }
136
+ };
137
+ }
133
138
  /** 디버그 모드시 로그 출력 함수 (인스턴스 스코프) */
134
- log(...args) {
139
+ static log(...args) {
135
140
  if (this._isDebugMode) console.log("[theme]", ...args);
136
141
  }
137
142
  }
138
- const theme = Theme.instance;
139
143
 
140
- export { theme };
144
+ export { Theme };
@@ -6,7 +6,7 @@
6
6
  * @param separator - 구분자 문자열 (default: `,`)
7
7
  * @returns lit 속성 컨버터 객체
8
8
  */
9
- export declare function arrayAttributeConverter<T>(parser: (value: string) => T, separator?: string): {
9
+ export declare function arrayAttrConverter<T>(parser: (value: string) => T, separator?: string): {
10
10
  fromAttribute: (value: string | null) => T[] | undefined;
11
11
  toAttribute: (value: T[] | undefined) => string | null;
12
12
  };
@@ -1,4 +1,4 @@
1
- function arrayAttributeConverter(parser, separator = ",") {
1
+ function arrayAttrConverter(parser, separator = ",") {
2
2
  return {
3
3
  fromAttribute: (value) => {
4
4
  if (!value) return void 0;
@@ -11,4 +11,4 @@ function arrayAttributeConverter(parser, separator = ",") {
11
11
  };
12
12
  }
13
13
 
14
- export { arrayAttributeConverter };
14
+ export { arrayAttrConverter };
@@ -6,14 +6,15 @@ function getParentElement(element) {
6
6
  return root instanceof Document ? root.documentElement : root instanceof ShadowRoot ? root.host : root instanceof HTMLElement ? root : void 0;
7
7
  }
8
8
  }
9
- function querySelectorWithin(element, selectors) {
10
- if (!selectors) return null;
9
+ function querySelectorAllWithin(element, selectors) {
10
+ if (!selectors) return [];
11
11
  const rootNode = element.getRootNode({ composed: false });
12
12
  if (rootNode instanceof ShadowRoot || rootNode instanceof Document) {
13
- return rootNode.querySelector(selectors);
13
+ const nodeList = rootNode.querySelectorAll(selectors);
14
+ return Array.from(nodeList);
14
15
  } else {
15
- return null;
16
+ return [];
16
17
  }
17
18
  }
18
19
 
19
- export { getParentElement, querySelectorWithin };
20
+ export { getParentElement, querySelectorAllWithin };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@iyulab/components",
3
3
  "description": "web-components library based on lit-element made by iyulab",
4
- "version": "0.1.10",
4
+ "version": "0.2.0",
5
5
  "keywords": [
6
6
  "iyulab",
7
7
  "components",
@@ -40,20 +40,20 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@floating-ui/dom": "^1.7.4",
43
- "lit": "^3.3.1",
43
+ "@lit/react": "^1.0.8",
44
+ "lit": "^3.3.2",
44
45
  "react": "^19.2.3",
45
46
  "reflect-metadata": "^0.2.2"
46
47
  },
47
48
  "devDependencies": {
48
- "@lit/react": "^1.0.8",
49
49
  "@eslint/js": "^9.39.2",
50
- "@types/node": "^25.0.3",
50
+ "@types/node": "^25.0.9",
51
51
  "eslint": "^9.39.2",
52
52
  "eslint-plugin-lit": "^2.1.1",
53
- "globals": "^16.5.0",
53
+ "globals": "^17.0.0",
54
54
  "typescript": "^5.9.3",
55
- "typescript-eslint": "^8.50.0",
56
- "vite": "^7.3.0",
55
+ "typescript-eslint": "^8.53.0",
56
+ "vite": "^7.3.1",
57
57
  "vite-plugin-dts": "^4.5.4",
58
58
  "vite-plugin-static-copy": "^3.1.4"
59
59
  }
@@ -1,3 +0,0 @@
1
- const arrowClockwise = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\">\n <path fill-rule=\"evenodd\" d=\"M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2z\"/>\n <path d=\"M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466\"/>\n</svg>";
2
-
3
- export { arrowClockwise as default };
@@ -1,3 +0,0 @@
1
- const speedometer = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\">\n <path d=\"M8 2a.5.5 0 0 1 .5.5V4a.5.5 0 0 1-1 0V2.5A.5.5 0 0 1 8 2M3.732 3.732a.5.5 0 0 1 .707 0l.915.914a.5.5 0 1 1-.708.708l-.914-.915a.5.5 0 0 1 0-.707M2 8a.5.5 0 0 1 .5-.5h1.586a.5.5 0 0 1 0 1H2.5A.5.5 0 0 1 2 8m9.5 0a.5.5 0 0 1 .5-.5h1.5a.5.5 0 0 1 0 1H12a.5.5 0 0 1-.5-.5m.754-4.246a.39.39 0 0 0-.527-.02L7.547 7.31A.91.91 0 1 0 8.85 8.569l3.434-4.297a.39.39 0 0 0-.029-.518z\"/>\n <path fill-rule=\"evenodd\" d=\"M6.664 15.889A8 8 0 1 1 9.336.11a8 8 0 0 1-2.672 15.78zm-4.665-4.283A11.95 11.95 0 0 1 8 10c2.186 0 4.236.585 6.001 1.606a7 7 0 1 0-12.002 0\"/>\n</svg>";
2
-
3
- export { speedometer as default };
@@ -1,20 +0,0 @@
1
- import { BaseElement } from '../BaseElement.js';
2
- import { IconLibrary } from '../icon/UIcon.component.js';
3
- /**
4
- * IconButton 컴포넌트는 아이콘만 표시하는 버튼입니다.
5
- */
6
- export declare class UIconButton extends BaseElement {
7
- static styles: import('lit').CSSResultGroup[];
8
- static dependencies: Record<string, typeof BaseElement>;
9
- /** 경계선이 없는 스타일을 적용합니다. */
10
- borderless: boolean;
11
- /** 버튼이 비활성화 상태인지 여부를 설정합니다. 비활성화된 버튼은 클릭할 수 없습니다. */
12
- disabled: boolean;
13
- /** 버튼이 로딩 상태인지 여부를 설정합니다. 로딩 중에는 버튼이 비활성화되고 스피너가 표시됩니다. */
14
- loading: boolean;
15
- /** 아이콘 라이브러리를 지정합니다. */
16
- lib: IconLibrary;
17
- /** 아이콘의 이름을 지정합니다. */
18
- name?: string;
19
- render(): import('lit-html').TemplateResult<1>;
20
- }
@@ -1,59 +0,0 @@
1
- import { html } from 'lit';
2
- import { property } from 'lit/decorators.js';
3
- import { BaseElement } from '../BaseElement.js';
4
- import { USpinner } from '../spinner/USpinner.component.js';
5
- import { UIcon } from '../icon/UIcon.component.js';
6
- import { styles } from './UIconButton.styles.js';
7
-
8
- var __defProp = Object.defineProperty;
9
- var __decorateClass = (decorators, target, key, kind) => {
10
- var result = void 0 ;
11
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
12
- if (decorator = decorators[i])
13
- result = (decorator(target, key, result) ) || result;
14
- if (result) __defProp(target, key, result);
15
- return result;
16
- };
17
- class UIconButton extends BaseElement {
18
- constructor() {
19
- super(...arguments);
20
- this.borderless = false;
21
- this.disabled = false;
22
- this.loading = false;
23
- this.lib = "default";
24
- }
25
- static {
26
- this.styles = [super.styles, styles];
27
- }
28
- static {
29
- this.dependencies = {
30
- "u-spinner": USpinner,
31
- "u-icon": UIcon
32
- };
33
- }
34
- render() {
35
- return html`
36
- <button part="base"
37
- ?disabled=${this.disabled || this.loading}>
38
- ${this.loading ? html`<u-spinner></u-spinner>` : html`<u-icon .lib=${this.lib} .name=${this.name}></u-icon>`}
39
- </button>
40
- `;
41
- }
42
- }
43
- __decorateClass([
44
- property({ type: Boolean, reflect: true })
45
- ], UIconButton.prototype, "borderless");
46
- __decorateClass([
47
- property({ type: Boolean, reflect: true })
48
- ], UIconButton.prototype, "disabled");
49
- __decorateClass([
50
- property({ type: Boolean, reflect: true })
51
- ], UIconButton.prototype, "loading");
52
- __decorateClass([
53
- property({ type: String })
54
- ], UIconButton.prototype, "lib");
55
- __decorateClass([
56
- property({ type: String })
57
- ], UIconButton.prototype, "name");
58
-
59
- export { UIconButton };
@@ -1,7 +0,0 @@
1
- import { UIconButton } from './UIconButton.component.js';
2
- declare global {
3
- interface HTMLElementTagNameMap {
4
- "u-icon-button": UIconButton;
5
- }
6
- }
7
- export { UIconButton };
@@ -1,5 +0,0 @@
1
- import { UIconButton } from './UIconButton.component.js';
2
-
3
- UIconButton.define("u-icon-button");
4
-
5
- export { UIconButton };
@@ -1,54 +0,0 @@
1
- import { css } from 'lit';
2
-
3
- const styles = css`
4
- :host {
5
- position: relative;
6
- display: inline-flex;
7
-
8
- font-size: 16px;
9
- padding: 0.5em;
10
- color: var(--u-icon-color);
11
- border: 1px solid var(--u-border-color);
12
- border-radius: 6px;
13
- background-color: var(--u-bg-color);
14
-
15
- transition: all 0.2s ease;
16
- user-select: none;
17
- cursor: pointer;
18
- }
19
- :host(:hover) {
20
- color: var(--u-icon-color-hover);
21
- background-color: var(--u-bg-color-hover);
22
- }
23
- :host(:active) {
24
- color: var(--u-icon-color-active);
25
- background-color: var(--u-bg-color-active);
26
- transform: translateY(1px);
27
- }
28
- :host([borderless]) {
29
- border: none;
30
- background-color: transparent;
31
- }
32
- :host([loading]),
33
- :host([disabled]) {
34
- color: var(--u-icon-color-disabled);
35
- pointer-events: none;
36
- }
37
-
38
- button {
39
- all: unset;
40
- display: inline-flex;
41
- }
42
- button:focus-visible {
43
- outline: 2px solid var(--u-blue-500, #3b82f6);
44
- outline-offset: 2px;
45
- }
46
-
47
- u-spinner,
48
- u-icon {
49
- color: inherit;
50
- font-size: inherit;
51
- }
52
- `;
53
-
54
- export { styles };