@iyulab/components 1.3.4 β†’ 1.4.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 (126) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/_virtual/_glob-assets_raw/dark.css.e8ac080d.js +1 -1
  3. package/dist/assets/locales/ar.json.js +23 -0
  4. package/dist/assets/locales/de.json.js +23 -0
  5. package/dist/assets/locales/en.json.js +23 -0
  6. package/dist/assets/locales/es.json.js +23 -0
  7. package/dist/assets/locales/fr.json.js +23 -0
  8. package/dist/assets/locales/id.json.js +23 -0
  9. package/dist/assets/locales/ja.json.js +23 -0
  10. package/dist/assets/locales/ko.json.js +23 -0
  11. package/dist/assets/locales/pt-BR.json.js +23 -0
  12. package/dist/assets/locales/ru.json.js +23 -0
  13. package/dist/assets/locales/th.json.js +23 -0
  14. package/dist/assets/locales/vi.json.js +23 -0
  15. package/dist/assets/locales/zh-CN.json.js +23 -0
  16. package/dist/assets/locales/zh-TW.json.js +23 -0
  17. package/dist/components/UFloatingElement.js +13 -4
  18. package/dist/components/UFormControlElement.d.ts +38 -8
  19. package/dist/components/UFormControlElement.js +61 -6
  20. package/dist/components/UOverlayElement.d.ts +4 -0
  21. package/dist/components/UOverlayElement.js +14 -4
  22. package/dist/components/alert/UAlert.js +10 -4
  23. package/dist/components/alert/UAlert.styles.js +0 -6
  24. package/dist/components/avatar/UAvatar.js +1 -1
  25. package/dist/components/badge/UBadge.d.ts +1 -1
  26. package/dist/components/badge/UBadge.js +2 -2
  27. package/dist/components/badge/UBadge.styles.js +1 -1
  28. package/dist/components/breadcrumb/UBreadcrumb.js +1 -1
  29. package/dist/components/breadcrumb-item/UBreadcrumbItem.js +1 -1
  30. package/dist/components/button/UButton.d.ts +6 -11
  31. package/dist/components/button/UButton.js +1 -1
  32. package/dist/components/button/UButton.styles.js +50 -51
  33. package/dist/components/button-group/UButtonGroup.js +1 -1
  34. package/dist/components/card/UCard.js +1 -1
  35. package/dist/components/carousel/UCarousel.js +2 -2
  36. package/dist/components/checkbox/UCheckbox.d.ts +4 -1
  37. package/dist/components/checkbox/UCheckbox.js +11 -8
  38. package/dist/components/checkbox/UCheckbox.styles.js +12 -7
  39. package/dist/components/chip/UChip.js +6 -3
  40. package/dist/components/dialog/UDialog.js +2 -2
  41. package/dist/components/divider/UDivider.js +1 -1
  42. package/dist/components/drawer/UDrawer.js +2 -2
  43. package/dist/components/drawer/UDrawer.styles.js +0 -6
  44. package/dist/components/field/UField.js +1 -1
  45. package/dist/components/form/UForm.js +1 -1
  46. package/dist/components/icon/UIcon.js +1 -1
  47. package/dist/components/icon-button/UIconButton.d.ts +0 -1
  48. package/dist/components/icon-button/UIconButton.js +2 -7
  49. package/dist/components/input/UInput.d.ts +2 -3
  50. package/dist/components/input/UInput.js +37 -9
  51. package/dist/components/input/UInput.styles.js +1 -4
  52. package/dist/components/menu/UMenu.js +1 -1
  53. package/dist/components/menu-item/UMenuItem.js +1 -1
  54. package/dist/components/menu-item/UMenuItem.styles.js +4 -3
  55. package/dist/components/option/UOption.d.ts +4 -1
  56. package/dist/components/option/UOption.js +10 -4
  57. package/dist/components/option/UOption.styles.js +5 -4
  58. package/dist/components/panel/UPanel.js +1 -1
  59. package/dist/components/popover/UPopover.js +1 -1
  60. package/dist/components/progress-bar/UProgressBar.js +1 -1
  61. package/dist/components/progress-bar/UProgressBar.styles.js +2 -2
  62. package/dist/components/progress-ring/UProgressRing.js +1 -1
  63. package/dist/components/progress-ring/UProgressRing.styles.js +2 -2
  64. package/dist/components/radio/URadio.d.ts +1 -1
  65. package/dist/components/radio/URadio.js +5 -6
  66. package/dist/components/radio/URadio.styles.js +21 -16
  67. package/dist/components/rating/URating.d.ts +3 -2
  68. package/dist/components/rating/URating.js +30 -37
  69. package/dist/components/select/USelect.d.ts +8 -5
  70. package/dist/components/select/USelect.js +29 -41
  71. package/dist/components/select/USelect.styles.js +5 -5
  72. package/dist/components/skeleton/USkeleton.js +1 -1
  73. package/dist/components/slider/USlider.d.ts +3 -2
  74. package/dist/components/slider/USlider.js +20 -30
  75. package/dist/components/slider/USlider.styles.js +2 -2
  76. package/dist/components/spinner/USpinner.js +1 -1
  77. package/dist/components/spinner/USpinner.styles.js +1 -1
  78. package/dist/components/split-panel/USplitPanel.js +25 -13
  79. package/dist/components/switch/USwitch.d.ts +4 -1
  80. package/dist/components/switch/USwitch.js +11 -8
  81. package/dist/components/switch/USwitch.styles.js +5 -1
  82. package/dist/components/tab/UTab.js +6 -3
  83. package/dist/components/tab-panel/UTabPanel.d.ts +5 -0
  84. package/dist/components/tab-panel/UTabPanel.js +12 -4
  85. package/dist/components/tab-panel/UTabPanel.styles.js +7 -3
  86. package/dist/components/tag/UTag.js +1 -1
  87. package/dist/components/tag/UTag.styles.js +14 -13
  88. package/dist/components/textarea/UTextarea.d.ts +1 -1
  89. package/dist/components/textarea/UTextarea.js +17 -6
  90. package/dist/components/tooltip/UTooltip.js +1 -1
  91. package/dist/components/tree/UTree.js +1 -1
  92. package/dist/components/tree-item/UTreeItem.js +10 -4
  93. package/dist/components/tree-item/UTreeItem.styles.js +5 -4
  94. package/dist/index.d.ts +2 -4
  95. package/dist/index.js +6 -8
  96. package/dist/react/UTabPanel.d.ts +1 -0
  97. package/dist/react/UTabPanel.js +3 -1
  98. package/dist/styles/dark.css +99 -99
  99. package/dist/utilities/Locale.d.ts +38 -0
  100. package/dist/utilities/Locale.js +93 -0
  101. package/dist/utilities/Toast.d.ts +9 -0
  102. package/dist/utilities/Toast.js +15 -7
  103. package/dist/utilities/elements.d.ts +0 -23
  104. package/dist/utilities/elements.js +1 -34
  105. package/package.json +2 -3
  106. package/skills/iyulab-components/SKILL.md +2 -3
  107. package/skills/iyulab-components/references/components/input.md +1 -2
  108. package/skills/iyulab-components/references/components/option.md +1 -0
  109. package/skills/iyulab-components/references/components/select.md +1 -2
  110. package/skills/iyulab-components/references/components/tab-panel.md +6 -0
  111. package/skills/iyulab-components/references/extensions/form-control.md +22 -6
  112. package/skills/iyulab-components/references/usage.md +11 -0
  113. package/skills/iyulab-components/references/utilities/elements.md +1 -17
  114. package/skills/iyulab-components/references/utilities/locale.md +36 -0
  115. package/skills/iyulab-components/references/utilities/theme.md +12 -0
  116. package/skills/iyulab-components/references/utilities/toast.md +6 -0
  117. package/dist/components/UDataElement.d.ts +0 -44
  118. package/dist/components/UDataElement.js +0 -101
  119. package/dist/components/UDataElement.styles.d.ts +0 -1
  120. package/dist/components/UDataElement.styles.js +0 -95
  121. package/dist/core/locale.d.ts +0 -69
  122. package/dist/core/locale.js +0 -85
  123. package/dist/utilities/sanitizers.d.ts +0 -35
  124. package/dist/utilities/sanitizers.js +0 -75
  125. package/skills/iyulab-components/references/extensions/data.md +0 -60
  126. package/skills/iyulab-components/references/utilities/sanitizers.md +0 -32
@@ -0,0 +1,93 @@
1
+ import ar_default from "../assets/locales/ar.json.js";
2
+ import de_default from "../assets/locales/de.json.js";
3
+ import en_default from "../assets/locales/en.json.js";
4
+ import es_default from "../assets/locales/es.json.js";
5
+ import fr_default from "../assets/locales/fr.json.js";
6
+ import id_default from "../assets/locales/id.json.js";
7
+ import ja_default from "../assets/locales/ja.json.js";
8
+ import ko_default from "../assets/locales/ko.json.js";
9
+ import pt_BR_default from "../assets/locales/pt-BR.json.js";
10
+ import ru_default from "../assets/locales/ru.json.js";
11
+ import th_default from "../assets/locales/th.json.js";
12
+ import vi_default from "../assets/locales/vi.json.js";
13
+ import zh_CN_default from "../assets/locales/zh-CN.json.js";
14
+ import zh_TW_default from "../assets/locales/zh-TW.json.js";
15
+ //#region src/utilities/Locale.ts
16
+ var builtins = new Map(Object.entries(/* #__PURE__ */ Object.assign({
17
+ "../assets/locales/ar.json": ar_default,
18
+ "../assets/locales/de.json": de_default,
19
+ "../assets/locales/en.json": en_default,
20
+ "../assets/locales/es.json": es_default,
21
+ "../assets/locales/fr.json": fr_default,
22
+ "../assets/locales/id.json": id_default,
23
+ "../assets/locales/ja.json": ja_default,
24
+ "../assets/locales/ko.json": ko_default,
25
+ "../assets/locales/pt-BR.json": pt_BR_default,
26
+ "../assets/locales/ru.json": ru_default,
27
+ "../assets/locales/th.json": th_default,
28
+ "../assets/locales/vi.json": vi_default,
29
+ "../assets/locales/zh-CN.json": zh_CN_default,
30
+ "../assets/locales/zh-TW.json": zh_TW_default
31
+ })).map(([path, mod]) => {
32
+ return [(path.split("/").pop()?.replace(".json", "") || "").toLowerCase(), mod];
33
+ }));
34
+ var overrides = /* @__PURE__ */ new Map();
35
+ /** λΈŒλΌμš°μ € ν™˜κ²½μ΄λ©΄ `navigator.language`/`document.lang`으둜 초기 λ‘œμΌ€μΌμ„ μΆ”μΈ‘ν•œλ‹€. */
36
+ function detectLocale() {
37
+ if (typeof navigator !== "undefined" && navigator.language) return navigator.language;
38
+ if (typeof document !== "undefined" && document.documentElement?.lang) return document.documentElement.lang;
39
+ return "en";
40
+ }
41
+ var active = detectLocale();
42
+ /** μ •ν™• 일치 β†’ base μ–Έμ–΄(ko-KR β†’ ko) β†’ en 순으둜 값을 μ°ΎλŠ”λ‹€. */
43
+ function lookup(locale, key) {
44
+ const norm = locale.toLowerCase();
45
+ const base = norm.split("-")[0];
46
+ const chain = base === norm ? [norm, "en"] : [
47
+ norm,
48
+ base,
49
+ "en"
50
+ ];
51
+ for (const tag of chain) {
52
+ const value = overrides.get(tag)?.[key] ?? builtins.get(tag)?.[key];
53
+ if (value) return value;
54
+ }
55
+ return builtins.get("en")[key];
56
+ }
57
+ /**
58
+ * 검증 λ©”μ‹œμ§€ λ‘œμΌ€μΌμ„ κ΄€λ¦¬ν•˜λŠ” 정적 μœ ν‹Έλ¦¬ν‹°μž…λ‹ˆλ‹€.
59
+ */
60
+ var Locale = class {
61
+ /** κ°œλ³„ μΈμŠ€ν„΄μŠ€ 생성을 λ°©μ§€ν•©λ‹ˆλ‹€. */
62
+ constructor() {}
63
+ /** μ „μ—­ ν™œμ„± λ‘œμΌ€μΌμ„ μ§€μ •ν•©λ‹ˆλ‹€. */
64
+ static set(locale) {
65
+ active = locale;
66
+ }
67
+ /** μ „μ—­ ν™œμ„± λ‘œμΌ€μΌμ„ λ°˜ν™˜ν•©λ‹ˆλ‹€ (μ΄ˆκΈ°κ°’μ€ λΈŒλΌμš°μ € μ–Έμ–΄ μžλ™ 감지, μ‹€νŒ¨ μ‹œ 'en'). */
68
+ static get() {
69
+ return active;
70
+ }
71
+ /**
72
+ * λ‘œμΌ€μΌ ν•˜λ‚˜μ˜ λ©”μ‹œμ§€ ν…Œμ΄λΈ”(전체 λ˜λŠ” 일뢀)을 λ“±λ‘ν•©λ‹ˆλ‹€.
73
+ * 이미 μ‘΄μž¬ν•˜λŠ” κ°’(λ‚΄μž₯ 포함) μœ„μ— λ³‘ν•©λ˜λ―€λ‘œ, 일뢀 ν‚€λ§Œ λ„˜κ²¨λ„ λ‚˜λ¨Έμ§€ ν‚€κ°€ 사라지지 μ•ŠμŠ΅λ‹ˆλ‹€.
74
+ */
75
+ static register(locale, table) {
76
+ const norm = locale.toLowerCase();
77
+ const current = overrides.get(norm) ?? builtins.get(norm) ?? builtins.get("en");
78
+ overrides.set(norm, {
79
+ ...current,
80
+ ...table
81
+ });
82
+ }
83
+ /**
84
+ * ν˜„μž¬ ν™œμ„± λ‘œμΌ€μΌ κΈ°μ€€μœΌλ‘œ λ©”μ‹œμ§€λ₯Ό μ‘°νšŒν•©λ‹ˆλ‹€.
85
+ * `params`κ°€ 있으면 ν…œν”Œλ¦Ώμ˜ `{name}` 자리λ₯Ό μΉ˜ν™˜ν•©λ‹ˆλ‹€.
86
+ */
87
+ static getValue(key, params) {
88
+ const template = lookup(active, key);
89
+ return params ? template.replace(/\{(\w+)\}/g, (_, name) => params[name] != null ? String(params[name]) : `{${name}}`) : template;
90
+ }
91
+ };
92
+ //#endregion
93
+ export { Locale };
@@ -22,6 +22,15 @@ export interface ToastOptions {
22
22
  export declare class Toast {
23
23
  private static containers;
24
24
  private static elements;
25
+ /**
26
+ * λͺ¨λ“  Toast ν˜ΈμΆœμ— 적용될 μ „μ—­ κΈ°λ³Έ μ˜΅μ…˜μž…λ‹ˆλ‹€. κ°œλ³„ 호좜의 `options`κ°€ μš°μ„ ν•©λ‹ˆλ‹€.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * Toast.DefaultOptions = { position: 'bottom-center', duration: 3000 };
31
+ * ```
32
+ */
33
+ static DefaultOptions: Partial<ToastOptions>;
25
34
  /** κ°œλ³„ μΈμŠ€ν„΄μŠ€ 생성을 λ°©μ§€ν•©λ‹ˆλ‹€. */
26
35
  private constructor();
27
36
  /** κΈ°λ³Έ λ©”μ‹œμ§€ μ•Œλ¦Ό */
@@ -10,6 +10,9 @@ var Toast = class {
10
10
  static {
11
11
  this.elements = /* @__PURE__ */ new Set();
12
12
  }
13
+ static {
14
+ this.DefaultOptions = {};
15
+ }
13
16
  /** κ°œλ³„ μΈμŠ€ν„΄μŠ€ 생성을 λ°©μ§€ν•©λ‹ˆλ‹€. */
14
17
  constructor() {}
15
18
  /** κΈ°λ³Έ λ©”μ‹œμ§€ μ•Œλ¦Ό */
@@ -38,21 +41,26 @@ var Toast = class {
38
41
  }
39
42
  /** ν† μŠ€νŠΈ μ•Œλ¦Όμ„ μƒμ„±ν•©λ‹ˆλ‹€. */
40
43
  static async show(status, content, options) {
44
+ const merged = {
45
+ ...this.DefaultOptions,
46
+ ...options
47
+ };
41
48
  const el = new UAlert();
42
49
  el.status = status;
43
50
  el.innerHTML = content || "";
44
- el.variant = options?.variant || "solid";
45
- el.title = options?.title || "";
46
- el.closable = options?.closable ?? true;
47
- el.duration = options?.duration && options.duration > 0 ? options.duration : 4e3;
51
+ el.variant = merged.variant || "solid";
52
+ el.title = merged.title || "";
53
+ el.closable = merged.closable ?? true;
54
+ el.duration = merged.duration ?? 4e3;
48
55
  this.elements.add(el);
49
- const position = options?.position || "top-right";
50
- const target = options?.target || document.body;
56
+ const position = merged.position || "top-right";
57
+ const target = merged.target || document.body;
51
58
  const container = this.getOrCreateContainer(position, target);
52
59
  container.appendChild(el);
53
60
  await el.updateComplete;
54
61
  el.show();
55
- el.addEventListener("hide", async () => {
62
+ el.addEventListener("hide", async (e) => {
63
+ if (e.target !== el) return;
56
64
  await new Promise((resolve) => setTimeout(resolve, 200));
57
65
  el.remove();
58
66
  this.elements.delete(el);
@@ -15,26 +15,3 @@ export declare function querySelectorWithin(element: Element, selectors: string)
15
15
  * - 탐색은 elementκ°€ μ‘΄μž¬ν•˜λŠ” shadow DOM λ˜λŠ” document 루트 λ²”μœ„μ—μ„œ μ΄λ£¨μ–΄μ§‘λ‹ˆλ‹€.
16
16
  */
17
17
  export declare function querySelectorAllWithin(element: Element, selectors: string): HTMLElement[];
18
- /**
19
- * μ§€μ •ν•œ νƒœκ·Έ, 속성, λ‚΄μš©μœΌλ‘œ μ»€μŠ€ν…€ μ—˜λ¦¬λ¨ΌνŠΈ HTML λ¬Έμžμ—΄μ„ μƒμ„±ν•©λ‹ˆλ‹€.
20
- *
21
- * 속성 κ°’ 처리 κ·œμΉ™:
22
- * - `null` / `undefined` β†’ ν•΄λ‹Ή 속성 μƒλž΅
23
- * - `false` (boolean) β†’ ν•΄λ‹Ή 속성 μƒλž΅
24
- * - `true` (boolean) β†’ κ°’ 없이 ν‚€λ§Œ 좜λ ₯ (예: `disabled`)
25
- * - `object` β†’ `JSON.stringify` ν›„ `escapeHtmlAttr`
26
- * - `href` / `src` ν‚€ β†’ `escapeHtmlHref` 적용
27
- * - κ·Έ μ™Έ string β†’ `escapeHtmlAttr` 적용
28
- *
29
- * `content`λŠ” 이미 μ•ˆμ „ν•œ HTML λ¬Έμžμ—΄μ΄λΌκ³  κ°€μ •ν•©λ‹ˆλ‹€ (λ‚΄λΆ€ escape μ—†μŒ).
30
- *
31
- * @param tag - μ»€μŠ€ν…€ μ—˜λ¦¬λ¨ΌνŠΈ νƒœκ·Έ 이름 (예: `"u-ref-tag"`)
32
- * @param attrs - 속성 객체
33
- * @param content - λ‚΄λΆ€ HTML λ¬Έμžμ—΄ (κΈ°λ³Έκ°’: `""`)
34
- * @returns μƒμ„±λœ HTML λ¬Έμžμ—΄
35
- *
36
- * @example
37
- * buildElementHTML('u-ref-tag', { href: 'https://example.com', disabled: true }, 'Click');
38
- * // β†’ '<u-ref-tag href="https://example.com" disabled>Click</u-ref-tag>'
39
- */
40
- export declare function buildElementHTML(tag: string, attrs?: Record<string, string | boolean | object | null | undefined>, content?: string): string;
@@ -1,4 +1,3 @@
1
- import { escapeHtmlAttr, escapeHtmlHref } from "./sanitizers.js";
2
1
  //#region src/utilities/elements.ts
3
2
  /**
4
3
  * μ—˜λ¦¬λ¨ΌνŠΈμ˜ λΆ€λͺ¨ μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.
@@ -35,37 +34,5 @@ function querySelectorAllWithin(element, selectors) {
35
34
  return Array.from(nodeList);
36
35
  } else return [];
37
36
  }
38
- /**
39
- * μ§€μ •ν•œ νƒœκ·Έ, 속성, λ‚΄μš©μœΌλ‘œ μ»€μŠ€ν…€ μ—˜λ¦¬λ¨ΌνŠΈ HTML λ¬Έμžμ—΄μ„ μƒμ„±ν•©λ‹ˆλ‹€.
40
- *
41
- * 속성 κ°’ 처리 κ·œμΉ™:
42
- * - `null` / `undefined` β†’ ν•΄λ‹Ή 속성 μƒλž΅
43
- * - `false` (boolean) β†’ ν•΄λ‹Ή 속성 μƒλž΅
44
- * - `true` (boolean) β†’ κ°’ 없이 ν‚€λ§Œ 좜λ ₯ (예: `disabled`)
45
- * - `object` β†’ `JSON.stringify` ν›„ `escapeHtmlAttr`
46
- * - `href` / `src` ν‚€ β†’ `escapeHtmlHref` 적용
47
- * - κ·Έ μ™Έ string β†’ `escapeHtmlAttr` 적용
48
- *
49
- * `content`λŠ” 이미 μ•ˆμ „ν•œ HTML λ¬Έμžμ—΄μ΄λΌκ³  κ°€μ •ν•©λ‹ˆλ‹€ (λ‚΄λΆ€ escape μ—†μŒ).
50
- *
51
- * @param tag - μ»€μŠ€ν…€ μ—˜λ¦¬λ¨ΌνŠΈ νƒœκ·Έ 이름 (예: `"u-ref-tag"`)
52
- * @param attrs - 속성 객체
53
- * @param content - λ‚΄λΆ€ HTML λ¬Έμžμ—΄ (κΈ°λ³Έκ°’: `""`)
54
- * @returns μƒμ„±λœ HTML λ¬Έμžμ—΄
55
- *
56
- * @example
57
- * buildElementHTML('u-ref-tag', { href: 'https://example.com', disabled: true }, 'Click');
58
- * // β†’ '<u-ref-tag href="https://example.com" disabled>Click</u-ref-tag>'
59
- */
60
- function buildElementHTML(tag, attrs = {}, content = "") {
61
- const URL_ATTR = /* @__PURE__ */ new Set(["href", "src"]);
62
- const attrStr = Object.entries(attrs).flatMap(([k, v]) => {
63
- if (v === void 0 || v == null || v === false) return [];
64
- if (v === true) return [k];
65
- const raw = typeof v === "object" ? JSON.stringify(v) : String(v);
66
- return [`${k}="${URL_ATTR.has(k) ? escapeHtmlHref(raw) : escapeHtmlAttr(raw)}"`];
67
- }).join(" ");
68
- return attrStr ? `<${tag} ${attrStr}>${content}</${tag}>` : `<${tag}>${content}</${tag}>`;
69
- }
70
37
  //#endregion
71
- export { buildElementHTML, getParentElement, querySelectorAllWithin, querySelectorWithin };
38
+ export { getParentElement, querySelectorAllWithin, querySelectorWithin };
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": "1.3.4",
4
+ "version": "1.4.0",
5
5
  "keywords": [
6
6
  "iyulab",
7
7
  "components",
@@ -39,9 +39,8 @@
39
39
  "./plugins/*": "./plugins/*"
40
40
  },
41
41
  "scripts": {
42
- "dev": "vite --force",
42
+ "start": "vite --force",
43
43
  "test": "vitest run",
44
- "test:watch": "vitest",
45
44
  "test:browser": "vitest run --project=browser",
46
45
  "build:plugins": "tsc -p plugins/tsconfig.json",
47
46
  "build": "eslint && vite build && npm run build:plugins"
@@ -4,7 +4,7 @@ description: Web component library built on Lit. Covers all u-* custom elements
4
4
  license: MIT
5
5
  metadata:
6
6
  author: iyulab
7
- version: "1.0.6"
7
+ version: "1.4.0"
8
8
  ---
9
9
 
10
10
  # @iyulab/components
@@ -119,7 +119,7 @@ import { UButton, UInput } from '@iyulab/components/react';
119
119
  - [`IconRegistry`](./references/utilities/icons.md) β€” Register and resolve icon libraries
120
120
  - [`BrowserStorage`](./references/utilities/browser-storage.md) β€” Unified localStorage / Cookie API
121
121
  - [`converters`](./references/utilities/converters.md) β€” Lit property attribute converters (array, JSON, date, url…)
122
- - [`sanitizers`](./references/utilities/sanitizers.md) β€” XSS-safe HTML/URL escape helpers
122
+ - [`Locale`](./references/utilities/locale.md) β€” Validation-message locale registry and lookup utility
123
123
  - [`elements`](./references/utilities/elements.md) β€” Shadow-DOM-aware DOM query helpers
124
124
  - [`OverlayManager`](./references/utilities/overlay-manager.md) β€” Internal overlay stack and z-index manager
125
125
 
@@ -135,4 +135,3 @@ import { UButton, UInput } from '@iyulab/components/react';
135
135
  - [`UFormControlElement<T>`](./references/extensions/form-control.md) β€” Base for form-associated controls; handles `disabled`, `readonly`, `invalid`, validation lifecycle
136
136
  - [`UFloatingElement`](./references/extensions/floating.md) β€” Base for anchored floating UI (popover, tooltip); wraps `@floating-ui/dom`
137
137
  - [`UOverlayElement`](./references/extensions/overlay.md) β€” Base for full-screen overlays (dialog, drawer); manages focus-trap, scroll-lock, ESC/backdrop close
138
- - [`UDataElement`](./references/extensions/data.md) β€” Base for data-driven components; auto-loads JSON from inline `<script type="application/json">`
@@ -89,7 +89,6 @@ Text input field with prefix/suffix slots and label. Add `u-option` children for
89
89
 
90
90
  | Property | Description |
91
91
  |----------|-------------|
92
- | `--input-popover-min-width` | Combobox popover min-width |
93
- | `--input-popover-max-width` | Combobox popover max-width |
92
+ | `--input-popover-width` | Combobox popover width (fixed to anchor width by default) |
94
93
  | `--input-popover-min-height` | Combobox popover min-height |
95
94
  | `--input-popover-max-height` | Combobox popover max-height |
@@ -51,6 +51,7 @@ Selectable option item. Used inside `u-select`, `u-radio`, and `u-input` (combob
51
51
  | Method | Returns | Description |
52
52
  |--------|---------|-------------|
53
53
  | `getText()` | `string` | Returns the visible text content of the option |
54
+ | `getContent()` | `Node[]` | Returns cloned rich-content nodes used for display rendering |
54
55
 
55
56
  ## CSS Parts
56
57
 
@@ -80,7 +80,6 @@ Dropdown select with single or multiple selection, search, and clear support. Fo
80
80
 
81
81
  | Property | Description |
82
82
  |----------|-------------|
83
- | `--select-popover-min-width` | Dropdown min-width |
84
- | `--select-popover-max-width` | Dropdown max-width |
83
+ | `--select-popover-width` | Dropdown width (fixed to anchor width by default; long option text ellipsizes instead of widening the popover) |
85
84
  | `--select-popover-min-height` | Dropdown min-height |
86
85
  | `--select-popover-max-height` | Dropdown max-height |
@@ -50,6 +50,12 @@ Tab-based content switcher. Pair each `u-tab` with a `u-panel` of the same `valu
50
50
  | `draggable` | `boolean` | `false` | βœ“ | Allow reordering tabs by drag |
51
51
  | `disabled` | `boolean` | `false` | βœ“ | Disable all tabs |
52
52
 
53
+ ### Events
54
+
55
+ | Event | Description |
56
+ |-------|-------------|
57
+ | `change` | Fires on user-driven tab changes (click/keyboard). Not emitted for initial mount or direct `value` assignment. |
58
+
53
59
  ### CSS Parts
54
60
 
55
61
  | Part | Description |
@@ -14,6 +14,8 @@ Use when building a custom input that should participate in forms (`formAssociat
14
14
  import { UFormControlElement } from '@iyulab/components';
15
15
  import { customElement, property } from 'lit/decorators.js';
16
16
  import { html } from 'lit';
17
+ import type { PropertyValues } from 'lit';
18
+ import { Locale } from '@iyulab/components';
17
19
 
18
20
  @customElement('my-input')
19
21
  export class MyInput extends UFormControlElement<string> {
@@ -33,17 +35,22 @@ export class MyInput extends UFormControlElement<string> {
33
35
  `;
34
36
  }
35
37
 
36
- validate(): boolean {
38
+ protected override setValidity(): void {
37
39
  if (this.required && !this.value) {
38
- this.invalid = true;
39
- return false;
40
+ this.commit({ valueMissing: true }, Locale.getValue('valueMissing'));
41
+ return;
40
42
  }
41
- this.invalid = false;
42
- return true;
43
+ this.commit({}, '');
44
+ }
45
+
46
+ protected override shouldValidate(changed: PropertyValues): boolean {
47
+ return super.shouldValidate(changed);
43
48
  }
44
49
 
45
50
  reset(): void {
46
51
  this.value = '';
52
+ this.setCustomValidity('');
53
+ this.commit({}, '');
47
54
  this.invalid = false;
48
55
  }
49
56
  }
@@ -75,5 +82,14 @@ export class MyInput extends UFormControlElement<string> {
75
82
 
76
83
  | Method | Returns | Description |
77
84
  |--------|---------|-------------|
78
- | `validate()` | `boolean` | Run validation logic; set `this.invalid` accordingly |
85
+ | `setValidity()` | `void` | Compute current validity and call `commit(flags, message, anchor?)` |
79
86
  | `reset()` | `void` | Reset value and clear validation state |
87
+
88
+ ## Validation Helpers (inherited)
89
+
90
+ | Member | Type | Description |
91
+ |--------|------|-------------|
92
+ | `validate(report?)` | `boolean` | Validate now (`true` = report/update invalid UI, `false` = silent check) |
93
+ | `setCustomValidity(message)` | `void` | Set or clear custom error text (`''` clears) |
94
+ | `commit(flags, message, anchor?)` | `void` | Apply validity state to `ElementInternals` with native-like custom-error precedence |
95
+ | `shouldValidate(changed)` | `boolean` | Select which property updates should trigger re-validation (`value`/`required` by default) |
@@ -62,6 +62,16 @@ Theme.set('system');
62
62
  const current = Theme.get(); // 'system' | 'light' | 'dark' | undefined
63
63
  ```
64
64
 
65
+ ### Brand color customization
66
+
67
+ ```css
68
+ :root {
69
+ --u-primary-color: #7c3aed;
70
+ }
71
+ ```
72
+
73
+ Interactive components derive hover/active/surface/outline styles from this token.
74
+
65
75
  ---
66
76
 
67
77
  ## Icon Setup
@@ -210,6 +220,7 @@ const confirmed = await Dialog.confirm('Delete this item?');
210
220
  const name = await Dialog.prompt('Enter your name:', { default: 'Alice' });
211
221
 
212
222
  // Toast
223
+ Toast.DefaultOptions = { position: 'bottom-center', duration: 3000 };
213
224
  Toast.success('Saved!');
214
225
  Toast.error('Something went wrong.', { duration: 5000 });
215
226
  Toast.message('Hello world', { position: 'bottom-center' });
@@ -1,7 +1,7 @@
1
1
  # elements
2
2
 
3
3
  ```ts
4
- import { getParentElement, querySelectorWithin, querySelectorAllWithin, buildElementHTML } from '@iyulab/components';
4
+ import { getParentElement, querySelectorWithin, querySelectorAllWithin } from '@iyulab/components';
5
5
  ```
6
6
 
7
7
  Shadow-DOM-aware DOM utility helpers.
@@ -37,19 +37,3 @@ Same as `querySelectorWithin` but returns all matches.
37
37
  ```ts
38
38
  const inputs = querySelectorAllWithin(this, 'u-input');
39
39
  ```
40
-
41
- ---
42
-
43
- ### `buildElementHTML(tag, attrs, content?)`
44
-
45
- Builds an XSS-safe custom element HTML string. All attribute values and content are sanitized.
46
-
47
- ```ts
48
- const html = buildElementHTML('u-alert', {
49
- status: 'success',
50
- open: '',
51
- }, 'File saved.');
52
- // β†’ '<u-alert status="success" open="">File saved.</u-alert>'
53
- ```
54
-
55
- > Use this when dynamically constructing HTML strings for `innerHTML` or server-side rendering.
@@ -0,0 +1,36 @@
1
+ # Locale
2
+
3
+ ```ts
4
+ import { Locale } from '@iyulab/components';
5
+ ```
6
+
7
+ Locale registry utility for library-generated validation messages.
8
+
9
+ ## Built-in Locales
10
+
11
+ Built in: `en`, `ko`, `ja`, `zh-CN`, `zh-TW`, `es`, `fr`, `de`, `pt-BR`, `vi`, `th`, `id`, `ru`, `ar`.
12
+
13
+ Initial locale is auto-detected from `navigator.language` / `document.documentElement.lang`, with English fallback.
14
+
15
+ ## API
16
+
17
+ | Method | Description |
18
+ |--------|-------------|
19
+ | `Locale.set(locale)` | Set active locale |
20
+ | `Locale.get()` | Get active locale |
21
+ | `Locale.register(locale, table)` | Register/override locale messages (partial merge supported) |
22
+ | `Locale.getValue(key, params?)` | Resolve a localized message for current locale |
23
+
24
+ ## Example
25
+
26
+ ```ts
27
+ import { Locale } from '@iyulab/components';
28
+
29
+ Locale.set('ko');
30
+
31
+ Locale.register('en', {
32
+ valueMissing: 'Please fill out this field.'
33
+ });
34
+
35
+ const message = Locale.getValue('valueMissing');
36
+ ```
@@ -22,6 +22,18 @@ await Theme.init({
22
22
  });
23
23
  ```
24
24
 
25
+ ## Primary Color Customization
26
+
27
+ Interactive components derive their accent palette from `--u-primary-color`.
28
+
29
+ ```css
30
+ :root {
31
+ --u-primary-color: #7c3aed; /* global brand/accent color */
32
+ }
33
+ ```
34
+
35
+ With this single token override, components such as buttons, checkbox/radio/switch, tab-panel, badge, and tag recalculate hover/active/surface/outline colors automatically.
36
+
25
37
  ## API
26
38
 
27
39
  | Member | Type | Description |
@@ -17,6 +17,11 @@ Toast.info('Update available.');
17
17
  Toast.notice('New message received.', { position: 'bottom-right' });
18
18
  Toast.message('Hello!', { title: 'Greetings' });
19
19
 
20
+ Toast.DefaultOptions = {
21
+ position: 'bottom-center',
22
+ duration: 3000
23
+ };
24
+
20
25
  // Full control
21
26
  await Toast.show('success', 'Custom message', {
22
27
  title: 'Done',
@@ -38,6 +43,7 @@ await Toast.show('success', 'Custom message', {
38
43
  | `Toast.warning(content, options?)` | Warning toast |
39
44
  | `Toast.error(content, options?)` | Error toast |
40
45
  | `Toast.show(status?, content?, options?)` | Generic toast with custom options |
46
+ | `Toast.DefaultOptions` | Global default options applied to every toast call (per-call options win) |
41
47
 
42
48
  ## ToastOptions
43
49
 
@@ -1,44 +0,0 @@
1
- import { UElement } from './UElement.js';
2
- /**
3
- * `UDataElement`λŠ” light DOM λ‚΄ `<script type="application/json">` νƒœκ·Έμ—μ„œ
4
- * JSON 데이터λ₯Ό 읽어 μ»΄ν¬λ„ŒνŠΈ ν”„λ‘œνΌν‹°μ— μžλ™μœΌλ‘œ λ§€ν•‘ν•˜λŠ” 기반 ν΄λž˜μŠ€μž…λ‹ˆλ‹€.
5
- *
6
- * μ‚¬μš© μ˜ˆμ‹œ:
7
- * ```html
8
- * <my-component>
9
- * <script type="application/json">{ "items": [1, 2, 3] }</script>
10
- * </my-component>
11
- * ```
12
- *
13
- * JSON μ΅œμƒμœ„ ν‚€κ°€ μ»΄ν¬λ„ŒνŠΈμ˜ ν”„λ‘œνΌν‹° 이름과 μΌμΉ˜ν•˜λ©΄ μžλ™μœΌλ‘œ ν• λ‹Ήλ©λ‹ˆλ‹€.
14
- */
15
- export declare class UDataElement extends UElement {
16
- static styles: import('lit').CSSResultGroup[];
17
- connectedCallback(): void;
18
- /**
19
- * μ§€μ •ν•œ νƒœκ·Έμ™€ λ°μ΄ν„°λ‘œ μ»€μŠ€ν…€ μ—˜λ¦¬λ¨ΌνŠΈ HTML λ¬Έμžμ—΄μ„ μƒμ„±ν•©λ‹ˆλ‹€.
20
- * λ°μ΄ν„°λŠ” `<script type="application/json">` νƒœκ·Έλ‘œ μ£Όμž…λ©λ‹ˆλ‹€.
21
- * νƒœκ·Έμ΄λ¦„μ΄ λ“±λ‘λ˜μ§€ μ•Šμ€ 경우 빈 λ¬Έμžμ—΄μ„ λ°˜ν™˜ν•©λ‹ˆλ‹€.
22
- *
23
- * @param json - JSON 데이터 객체 λ˜λŠ” λ¬Έμžμ—΄
24
- * @param attrs - μΆ”κ°€ 속성 객체 (선택적, `buildElementHTML` κ·œμΉ™ 적용)
25
- * @returns μƒμ„±λœ HTML λ¬Έμžμ—΄
26
- */
27
- static buildHTML(json: object | string, attrs?: Record<string, string | boolean | object | null | undefined>): string;
28
- /**
29
- * `data` 객체λ₯Ό μ»΄ν¬λ„ŒνŠΈ ν”„λ‘œνΌν‹°μ— ν• λ‹Ήν•©λ‹ˆλ‹€.
30
- * `data`κ°€ μ œκ³΅λ˜μ§€ μ•Šμ€ 경우 light DOM λ‚΄ `<script type="application/json">` νƒœκ·Έμ—μ„œ JSON 데이터λ₯Ό 읽어 ν”„λ‘œνΌν‹°μ— μžλ™μœΌλ‘œ ν• λ‹Ήν•©λ‹ˆλ‹€.
31
- * 였λ₯˜κ°€ λ°œμƒν•  경우 `error()`λ₯Ό ν˜ΈμΆœν•˜μ—¬ μ—λŸ¬ UI둜 λŒ€μ²΄ν•©λ‹ˆλ‹€.
32
- *
33
- * @param data - JSON 데이터 객체 (선택적)
34
- */
35
- protected load(data?: object): Promise<void>;
36
- /**
37
- * 였λ₯˜ λ°œμƒ μ‹œ Lit이 μ£Όμž…ν•œ μŠ€νƒ€μΌμ‹œνŠΈλ₯Ό λ³΄μ‘΄ν•˜κ³  λ‚˜λ¨Έμ§€ λ Œλ”λ§ κ²°κ³Όλ₯Ό μ—λŸ¬ UI둜 κ΅μ²΄ν•©λ‹ˆλ‹€.
38
- * 일반적으둜 JSON νŒŒμ‹± 였λ₯˜μ˜ 경우 `data`κ°€ 객체가 μ•„λ‹Œ λ¬Έμžμ—΄μ΄κ±°λ‚˜ JSON ν˜•μ‹μ΄ 잘λͺ»λœ κ²½μš°μž…λ‹ˆλ‹€.
39
- * 이 ν•¨μˆ˜λŠ” Lit λ Œλ”λ§μ΄ μ™„λ£Œλœ 후에 ν˜ΈμΆœλ©λ‹ˆλ‹€.
40
- *
41
- * @param error - λ°œμƒν•œ 였λ₯˜ 객체
42
- */
43
- protected error(error: unknown): Promise<void>;
44
- }
@@ -1,101 +0,0 @@
1
- import { UElement } from "./UElement.js";
2
- import "./icon/UIcon.js";
3
- import { buildElementHTML } from "../utilities/elements.js";
4
- import { styles } from "./UDataElement.styles.js";
5
- import { html } from "lit";
6
- //#region src/components/UDataElement.ts
7
- /**
8
- * `UDataElement`λŠ” light DOM λ‚΄ `<script type="application/json">` νƒœκ·Έμ—μ„œ
9
- * JSON 데이터λ₯Ό 읽어 μ»΄ν¬λ„ŒνŠΈ ν”„λ‘œνΌν‹°μ— μžλ™μœΌλ‘œ λ§€ν•‘ν•˜λŠ” 기반 ν΄λž˜μŠ€μž…λ‹ˆλ‹€.
10
- *
11
- * μ‚¬μš© μ˜ˆμ‹œ:
12
- * ```html
13
- * <my-component>
14
- * <script type="application/json">{ "items": [1, 2, 3] }<\/script>
15
- * </my-component>
16
- * ```
17
- *
18
- * JSON μ΅œμƒμœ„ ν‚€κ°€ μ»΄ν¬λ„ŒνŠΈμ˜ ν”„λ‘œνΌν‹° 이름과 μΌμΉ˜ν•˜λ©΄ μžλ™μœΌλ‘œ ν• λ‹Ήλ©λ‹ˆλ‹€.
19
- */
20
- var UDataElement = class extends UElement {
21
- static {
22
- this.styles = [super.styles, styles];
23
- }
24
- connectedCallback() {
25
- super.connectedCallback();
26
- queueMicrotask(() => this.load());
27
- }
28
- /**
29
- * μ§€μ •ν•œ νƒœκ·Έμ™€ λ°μ΄ν„°λ‘œ μ»€μŠ€ν…€ μ—˜λ¦¬λ¨ΌνŠΈ HTML λ¬Έμžμ—΄μ„ μƒμ„±ν•©λ‹ˆλ‹€.
30
- * λ°μ΄ν„°λŠ” `<script type="application/json">` νƒœκ·Έλ‘œ μ£Όμž…λ©λ‹ˆλ‹€.
31
- * νƒœκ·Έμ΄λ¦„μ΄ λ“±λ‘λ˜μ§€ μ•Šμ€ 경우 빈 λ¬Έμžμ—΄μ„ λ°˜ν™˜ν•©λ‹ˆλ‹€.
32
- *
33
- * @param json - JSON 데이터 객체 λ˜λŠ” λ¬Έμžμ—΄
34
- * @param attrs - μΆ”κ°€ 속성 객체 (선택적, `buildElementHTML` κ·œμΉ™ 적용)
35
- * @returns μƒμ„±λœ HTML λ¬Έμžμ—΄
36
- */
37
- static buildHTML(json, attrs = {}) {
38
- const tag = customElements.getName(this);
39
- if (!tag) {
40
- console.warn(`Custom element for ${this.name} is not defined.`);
41
- return "";
42
- }
43
- return buildElementHTML(tag, attrs, `<script type="application/json">${(typeof json === "string" ? json : JSON.stringify(json)).replace(/&/g, "\\u0026").replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029").replace(/-->/g, "--\\>")}<\/script>`);
44
- }
45
- /**
46
- * `data` 객체λ₯Ό μ»΄ν¬λ„ŒνŠΈ ν”„λ‘œνΌν‹°μ— ν• λ‹Ήν•©λ‹ˆλ‹€.
47
- * `data`κ°€ μ œκ³΅λ˜μ§€ μ•Šμ€ 경우 light DOM λ‚΄ `<script type="application/json">` νƒœκ·Έμ—μ„œ JSON 데이터λ₯Ό 읽어 ν”„λ‘œνΌν‹°μ— μžλ™μœΌλ‘œ ν• λ‹Ήν•©λ‹ˆλ‹€.
48
- * 였λ₯˜κ°€ λ°œμƒν•  경우 `error()`λ₯Ό ν˜ΈμΆœν•˜μ—¬ μ—λŸ¬ UI둜 λŒ€μ²΄ν•©λ‹ˆλ‹€.
49
- *
50
- * @param data - JSON 데이터 객체 (선택적)
51
- */
52
- async load(data) {
53
- try {
54
- if (!data) {
55
- const script = this.querySelector("script[type=\"application/json\"]");
56
- if (!script) throw new Error("Missing <script type=\"application/json\">");
57
- data = JSON.parse(script.textContent ?? "{}");
58
- script.remove();
59
- }
60
- if (typeof data !== "object" || data === null || Array.isArray(data)) throw new Error("Invalid JSON data: expected an object at the top level");
61
- Object.assign(this, data);
62
- } catch (error) {
63
- await this.error(error);
64
- }
65
- }
66
- /**
67
- * 였λ₯˜ λ°œμƒ μ‹œ Lit이 μ£Όμž…ν•œ μŠ€νƒ€μΌμ‹œνŠΈλ₯Ό λ³΄μ‘΄ν•˜κ³  λ‚˜λ¨Έμ§€ λ Œλ”λ§ κ²°κ³Όλ₯Ό μ—λŸ¬ UI둜 κ΅μ²΄ν•©λ‹ˆλ‹€.
68
- * 일반적으둜 JSON νŒŒμ‹± 였λ₯˜μ˜ 경우 `data`κ°€ 객체가 μ•„λ‹Œ λ¬Έμžμ—΄μ΄κ±°λ‚˜ JSON ν˜•μ‹μ΄ 잘λͺ»λœ κ²½μš°μž…λ‹ˆλ‹€.
69
- * 이 ν•¨μˆ˜λŠ” Lit λ Œλ”λ§μ΄ μ™„λ£Œλœ 후에 ν˜ΈμΆœλ©λ‹ˆλ‹€.
70
- *
71
- * @param error - λ°œμƒν•œ 였λ₯˜ 객체
72
- */
73
- async error(error) {
74
- await this.updateComplete;
75
- if (!this.shadowRoot) return;
76
- const tag = this.localName;
77
- const type = error instanceof Error ? error.constructor.name : "UnknownError";
78
- const message = error instanceof Error ? error.message : String(error);
79
- this.replace(html`
80
- <div class="error-container">
81
- <div class="error-header">
82
- <u-icon class="error-icon" lib="internal" name="exclamation-triangle-fill"></u-icon>
83
- <span class="error-title">Render Error</span>
84
- <code class="error-tag">&lt;${tag}&gt;</code>
85
- </div>
86
- <div class="error-body">
87
- <div class="error-row">
88
- <span class="error-label">Type</span>
89
- <code class="error-type">${type}</code>
90
- </div>
91
- <div class="error-row">
92
- <span class="error-label">Message</span>
93
- <pre class="error-message">${message}</pre>
94
- </div>
95
- </div>
96
- </div>
97
- `);
98
- }
99
- };
100
- //#endregion
101
- export { UDataElement };
@@ -1 +0,0 @@
1
- export declare const styles: import('lit').CSSResult;