@iyulab/components 1.3.3 → 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 (127) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +6 -0
  3. package/dist/_virtual/_glob-assets_raw/dark.css.e8ac080d.js +1 -1
  4. package/dist/assets/locales/ar.json.js +23 -0
  5. package/dist/assets/locales/de.json.js +23 -0
  6. package/dist/assets/locales/en.json.js +23 -0
  7. package/dist/assets/locales/es.json.js +23 -0
  8. package/dist/assets/locales/fr.json.js +23 -0
  9. package/dist/assets/locales/id.json.js +23 -0
  10. package/dist/assets/locales/ja.json.js +23 -0
  11. package/dist/assets/locales/ko.json.js +23 -0
  12. package/dist/assets/locales/pt-BR.json.js +23 -0
  13. package/dist/assets/locales/ru.json.js +23 -0
  14. package/dist/assets/locales/th.json.js +23 -0
  15. package/dist/assets/locales/vi.json.js +23 -0
  16. package/dist/assets/locales/zh-CN.json.js +23 -0
  17. package/dist/assets/locales/zh-TW.json.js +23 -0
  18. package/dist/components/UFloatingElement.js +13 -4
  19. package/dist/components/UFormControlElement.d.ts +38 -8
  20. package/dist/components/UFormControlElement.js +61 -6
  21. package/dist/components/UOverlayElement.d.ts +4 -0
  22. package/dist/components/UOverlayElement.js +14 -4
  23. package/dist/components/alert/UAlert.js +10 -4
  24. package/dist/components/alert/UAlert.styles.js +0 -6
  25. package/dist/components/avatar/UAvatar.js +1 -1
  26. package/dist/components/badge/UBadge.d.ts +1 -1
  27. package/dist/components/badge/UBadge.js +2 -2
  28. package/dist/components/badge/UBadge.styles.js +1 -1
  29. package/dist/components/breadcrumb/UBreadcrumb.js +1 -1
  30. package/dist/components/breadcrumb-item/UBreadcrumbItem.js +1 -1
  31. package/dist/components/button/UButton.d.ts +6 -11
  32. package/dist/components/button/UButton.js +1 -1
  33. package/dist/components/button/UButton.styles.js +50 -51
  34. package/dist/components/button-group/UButtonGroup.js +1 -1
  35. package/dist/components/card/UCard.js +1 -1
  36. package/dist/components/carousel/UCarousel.js +2 -2
  37. package/dist/components/checkbox/UCheckbox.d.ts +4 -1
  38. package/dist/components/checkbox/UCheckbox.js +11 -8
  39. package/dist/components/checkbox/UCheckbox.styles.js +12 -7
  40. package/dist/components/chip/UChip.js +6 -3
  41. package/dist/components/dialog/UDialog.js +2 -2
  42. package/dist/components/divider/UDivider.js +1 -1
  43. package/dist/components/drawer/UDrawer.js +2 -2
  44. package/dist/components/drawer/UDrawer.styles.js +0 -6
  45. package/dist/components/field/UField.js +1 -1
  46. package/dist/components/form/UForm.js +1 -1
  47. package/dist/components/icon/UIcon.js +1 -1
  48. package/dist/components/icon-button/UIconButton.d.ts +0 -1
  49. package/dist/components/icon-button/UIconButton.js +2 -7
  50. package/dist/components/input/UInput.d.ts +2 -3
  51. package/dist/components/input/UInput.js +37 -9
  52. package/dist/components/input/UInput.styles.js +1 -4
  53. package/dist/components/menu/UMenu.js +1 -1
  54. package/dist/components/menu-item/UMenuItem.js +1 -1
  55. package/dist/components/menu-item/UMenuItem.styles.js +4 -3
  56. package/dist/components/option/UOption.d.ts +4 -1
  57. package/dist/components/option/UOption.js +10 -4
  58. package/dist/components/option/UOption.styles.js +5 -4
  59. package/dist/components/panel/UPanel.js +1 -1
  60. package/dist/components/popover/UPopover.js +1 -1
  61. package/dist/components/progress-bar/UProgressBar.js +1 -1
  62. package/dist/components/progress-bar/UProgressBar.styles.js +2 -2
  63. package/dist/components/progress-ring/UProgressRing.js +1 -1
  64. package/dist/components/progress-ring/UProgressRing.styles.js +2 -2
  65. package/dist/components/radio/URadio.d.ts +1 -1
  66. package/dist/components/radio/URadio.js +5 -6
  67. package/dist/components/radio/URadio.styles.js +21 -16
  68. package/dist/components/rating/URating.d.ts +3 -2
  69. package/dist/components/rating/URating.js +30 -37
  70. package/dist/components/select/USelect.d.ts +8 -5
  71. package/dist/components/select/USelect.js +29 -41
  72. package/dist/components/select/USelect.styles.js +5 -5
  73. package/dist/components/skeleton/USkeleton.js +1 -1
  74. package/dist/components/slider/USlider.d.ts +3 -2
  75. package/dist/components/slider/USlider.js +20 -30
  76. package/dist/components/slider/USlider.styles.js +2 -2
  77. package/dist/components/spinner/USpinner.js +1 -1
  78. package/dist/components/spinner/USpinner.styles.js +1 -1
  79. package/dist/components/split-panel/USplitPanel.js +25 -13
  80. package/dist/components/switch/USwitch.d.ts +4 -1
  81. package/dist/components/switch/USwitch.js +11 -8
  82. package/dist/components/switch/USwitch.styles.js +5 -1
  83. package/dist/components/tab/UTab.js +6 -3
  84. package/dist/components/tab-panel/UTabPanel.d.ts +5 -0
  85. package/dist/components/tab-panel/UTabPanel.js +12 -4
  86. package/dist/components/tab-panel/UTabPanel.styles.js +7 -3
  87. package/dist/components/tag/UTag.js +1 -1
  88. package/dist/components/tag/UTag.styles.js +14 -13
  89. package/dist/components/textarea/UTextarea.d.ts +1 -1
  90. package/dist/components/textarea/UTextarea.js +17 -6
  91. package/dist/components/tooltip/UTooltip.js +1 -1
  92. package/dist/components/tree/UTree.js +1 -1
  93. package/dist/components/tree-item/UTreeItem.js +10 -4
  94. package/dist/components/tree-item/UTreeItem.styles.js +5 -4
  95. package/dist/index.d.ts +2 -4
  96. package/dist/index.js +6 -8
  97. package/dist/react/UTabPanel.d.ts +1 -0
  98. package/dist/react/UTabPanel.js +3 -1
  99. package/dist/styles/dark.css +99 -99
  100. package/dist/utilities/Locale.d.ts +38 -0
  101. package/dist/utilities/Locale.js +93 -0
  102. package/dist/utilities/Toast.d.ts +9 -0
  103. package/dist/utilities/Toast.js +15 -7
  104. package/dist/utilities/elements.d.ts +0 -23
  105. package/dist/utilities/elements.js +1 -34
  106. package/package.json +2 -3
  107. package/skills/iyulab-components/SKILL.md +2 -3
  108. package/skills/iyulab-components/references/components/input.md +1 -2
  109. package/skills/iyulab-components/references/components/option.md +1 -0
  110. package/skills/iyulab-components/references/components/select.md +1 -2
  111. package/skills/iyulab-components/references/components/tab-panel.md +6 -0
  112. package/skills/iyulab-components/references/extensions/form-control.md +22 -6
  113. package/skills/iyulab-components/references/usage.md +11 -0
  114. package/skills/iyulab-components/references/utilities/elements.md +1 -17
  115. package/skills/iyulab-components/references/utilities/locale.md +36 -0
  116. package/skills/iyulab-components/references/utilities/theme.md +12 -0
  117. package/skills/iyulab-components/references/utilities/toast.md +6 -0
  118. package/dist/components/UDataElement.d.ts +0 -44
  119. package/dist/components/UDataElement.js +0 -101
  120. package/dist/components/UDataElement.styles.d.ts +0 -1
  121. package/dist/components/UDataElement.styles.js +0 -95
  122. package/dist/core/locale.d.ts +0 -69
  123. package/dist/core/locale.js +0 -85
  124. package/dist/utilities/sanitizers.d.ts +0 -35
  125. package/dist/utilities/sanitizers.js +0 -75
  126. package/skills/iyulab-components/references/extensions/data.md +0 -60
  127. package/skills/iyulab-components/references/utilities/sanitizers.md +0 -32
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @iyulab/components 의 경량 로케일 유틸리티.
3
+ *
4
+ * 범위: 라이브러리가 스스로 생성하는 chrome 문자열(검증 메시지 등)만 대상.
5
+ * 일반 i18n 프레임워크가 아니다. 앱 콘텐츠 번역은 consumer 의 i18n 계층이 담당한다.
6
+ *
7
+ * en/ko/ja/zh-CN/es/fr 은 빌드 시점에 내장된다 (src/assets/locales/*.json).
8
+ * 그 외 언어는 register()로 테이블 단위 등록/오버라이드한다.
9
+ */
10
+ /** 라이브러리가 기본 제공하는 로케일. */
11
+ export type SupportedLocale = 'en' | 'ko' | 'ja' | 'zh-CN' | 'zh-TW' | 'es' | 'fr' | 'de' | 'pt-BR' | 'vi' | 'th' | 'id' | 'ru' | 'ar';
12
+ /** 내장 로케일은 자동완성되지만, 임의의 BCP47 태그도 그대로 받는다. */
13
+ export type LocaleTag = SupportedLocale | (string & {});
14
+ /** 라이브러리가 제공하는 chrome 문자열 키. 지금은 검증 메시지뿐이지만 이후 다른 UI 문구도 추가될 수 있다. */
15
+ export type LocaleMessageKey = 'valueMissing' | 'badInput' | 'typeMismatch' | 'patternMismatch' | 'rangeUnderflow' | 'rangeOverflow' | 'stepMismatch' | 'tooShort' | 'tooLong';
16
+ type LocaleTable = Record<LocaleMessageKey, string>;
17
+ /**
18
+ * 검증 메시지 로케일을 관리하는 정적 유틸리티입니다.
19
+ */
20
+ export declare class Locale {
21
+ /** 개별 인스턴스 생성을 방지합니다. */
22
+ private constructor();
23
+ /** 전역 활성 로케일을 지정합니다. */
24
+ static set(locale: LocaleTag): void;
25
+ /** 전역 활성 로케일을 반환합니다 (초기값은 브라우저 언어 자동 감지, 실패 시 'en'). */
26
+ static get(): LocaleTag;
27
+ /**
28
+ * 로케일 하나의 메시지 테이블(전체 또는 일부)을 등록합니다.
29
+ * 이미 존재하는 값(내장 포함) 위에 병합되므로, 일부 키만 넘겨도 나머지 키가 사라지지 않습니다.
30
+ */
31
+ static register(locale: LocaleTag, table: Partial<LocaleTable>): void;
32
+ /**
33
+ * 현재 활성 로케일 기준으로 메시지를 조회합니다.
34
+ * `params`가 있으면 템플릿의 `{name}` 자리를 치환합니다.
35
+ */
36
+ static getValue(key: LocaleMessageKey, params?: Record<string, string | number>): string;
37
+ }
38
+ export {};
@@ -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.3",
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
- }