@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
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.4.0] - 2026-07-06
4
+
5
+ ### Changed
6
+ - 폼 유효성 검증 아키텍처를 `UFormControlElement.validate()` 템플릿 메서드 + 컴포넌트별 `setValidity()` 구현 구조로 재정비하고, `commit(flags, message, anchor)` 헬퍼로 `setCustomValidity()` 커스텀 메시지 우선순위를 일관화. `validate(report)`로 `checkValidity`/`reportValidity`와 동일한 조용한 검증 모드도 지원.
7
+ - 로케일 시스템을 `src/core/locale.ts` 기반 레지스트리에서 `Locale` 유틸(`Locale.register()`, `Locale.set()`, `Locale.getValue()`)로 전환하고, en/ko/ja/zh-CN/zh-TW/es/fr/de/pt-BR/vi/th/id/ru/ar 14개 로케일 JSON을 빌드 시점 내장하도록 변경.
8
+ - 인터랙티브 컴포넌트의 색상 체계를 `--u-primary-color` 중심 토큰으로 전환해 hover/active/surface/outline 상태를 `color-mix()`로 파생하도록 개선. 이제 `--u-primary-color` 재정의만으로 전역 테마 컬러 커스터마이징 가능.
9
+ - 개발 스크립트를 `dev`에서 `start`로 정리하고 `test:watch` 스크립트를 제거.
10
+
11
+ ### Fixed
12
+ - 오버레이/컨테이너 계열 커스텀 이벤트(`show`/`hide`/`remove`/`expand`/`collapse`/`shift`)를 `bubbles:false`, `composed:false`로 조정해 중첩 컴포넌트에서 자식 이벤트를 조상 이벤트로 오인하던 문제를 해결.
13
+ - `UFloatingElement`가 `--anchor-width`/`--anchor-height`를 실제 픽셀 기준으로 노출하도록 개선하고, `USelect`/`UInput` 팝오버 폭 계산이 strategy(`fixed`)와 무관하게 일관되게 동작하도록 수정.
14
+ - `UOption.getText()`가 텍스트 노드만 추출하도록 보정하고 `getContent()`를 추가해 `USelect` 선택값 표시에서 리치 콘텐츠 처리를 개선.
15
+ - `UTabPanel`의 `change` 이벤트가 초기 마운트/직접 값 대입 시 오발생하지 않도록 사용자 조작(클릭/키보드)에서만 발생하게 수정.
16
+ - `Toast`에 전역 기본 옵션을 추가하고 hide 이벤트 처리에서 `target`을 검사하도록 바꿔 내부 엘리먼트 이벤트 오탐을 방지.
17
+
18
+ ### Removed
19
+ - **Breaking:** `UDataElement` 및 관련 스타일 파일(`UDataElement.styles.ts`) 제거.
20
+ - **Breaking:** `sanitizers` 유틸과 `buildElementHTML`(in `utilities/elements.ts`) 제거, 이에 따른 `src/index.ts` export 정리.
21
+ - 브라우저 테스트 `tests/browser/input-display-token.browser.test.ts` 제거.
22
+
3
23
  ## [1.3.4] - 2026-07-03
4
24
 
5
25
  ### Documentation
@@ -1,4 +1,4 @@
1
1
  //#region \0glob-assets_raw/dark.css.e8ac080d
2
- var dark_css_default = ":root[theme=\"dark\"] {\n color-scheme: dark;\n\n /* Neutral Colors */\n --u-neutral-0: #000000;\n --u-neutral-50: #0A0A0A;\n --u-neutral-100: #121212;\n --u-neutral-200: #1E1E1E;\n --u-neutral-300: #2A2A2A;\n --u-neutral-400: #3D3D3D;\n --u-neutral-500: #525252;\n --u-neutral-600: #6E6E6E;\n --u-neutral-700: #8A8A8A;\n --u-neutral-800: #B0B0B0;\n --u-neutral-900: #D4D4D4;\n --u-neutral-1000: #FFFFFF;\n\n /* Blue Colors */\n --u-blue-0: #0A1E3D;\n --u-blue-100: #1E3A5F;\n --u-blue-200: #2B4F7E;\n --u-blue-300: #3D6B9E;\n --u-blue-400: #5284BE;\n --u-blue-500: #6BA3E3;\n --u-blue-600: #87B8F5;\n --u-blue-700: #A5CDFF;\n --u-blue-800: #C2DEFF;\n --u-blue-900: #DDEEFF;\n --u-blue-1000: #F0F7FF;\n\n /* Green Colors */\n --u-green-0: #0D2818;\n --u-green-100: #1A3F2A;\n --u-green-200: #285639;\n --u-green-300: #3A7450;\n --u-green-400: #4E9268;\n --u-green-500: #66B584;\n --u-green-600: #81D19D;\n --u-green-700: #9FE5B5;\n --u-green-800: #BEF2CD;\n --u-green-900: #DDF9E5;\n --u-green-1000: #F0FDF5;\n\n /* Yellow Colors */\n --u-yellow-0: #2E2200;\n --u-yellow-100: #4D3A00;\n --u-yellow-200: #6B5200;\n --u-yellow-300: #8A6B00;\n --u-yellow-400: #B08900;\n --u-yellow-500: #D4A712;\n --u-yellow-600: #F5C842;\n --u-yellow-700: #FFE066;\n --u-yellow-800: #FFED99;\n --u-yellow-900: #FFF5CC;\n --u-yellow-1000: #FFFBE6;\n\n /* Red Colors */\n --u-red-0: #2E0A0A;\n --u-red-100: #4D1717;\n --u-red-200: #6B2424;\n --u-red-300: #8F3535;\n --u-red-400: #B24848;\n --u-red-500: #D66060;\n --u-red-600: #F57878;\n --u-red-700: #FF9494;\n --u-red-800: #FFB3B3;\n --u-red-900: #FFD2D2;\n --u-red-1000: #FFF0F0;\n\n /* Orange Colors */\n --u-orange-0: #2E1A00;\n --u-orange-100: #4D2E00;\n --u-orange-200: #6B4200;\n --u-orange-300: #8A5A00;\n --u-orange-400: #B07500;\n --u-orange-500: #D49212;\n --u-orange-600: #F5AE42;\n --u-orange-700: #FFC566;\n --u-orange-800: #FFD899;\n --u-orange-900: #FFEBCC;\n --u-orange-1000: #FFF5E6;\n\n /* Teal Colors */\n --u-teal-0: #002018;\n --u-teal-100: #00382B;\n --u-teal-200: #005040;\n --u-teal-300: #006B55;\n --u-teal-400: #00886C;\n --u-teal-500: #1AA88A;\n --u-teal-600: #42C4A5;\n --u-teal-700: #6EDABD;\n --u-teal-800: #9EEAD5;\n --u-teal-900: #CFF5EA;\n --u-teal-1000: #EDFCF7;\n\n /* Cyan Colors */\n --u-cyan-0: #002830;\n --u-cyan-100: #00404D;\n --u-cyan-200: #005A6B;\n --u-cyan-300: #00768A;\n --u-cyan-400: #0094B0;\n --u-cyan-500: #12B4D4;\n --u-cyan-600: #42CFF5;\n --u-cyan-700: #66DFFF;\n --u-cyan-800: #99EBFF;\n --u-cyan-900: #CCF5FF;\n --u-cyan-1000: #E6FAFF;\n\n /* Purple Colors */\n --u-purple-0: #1A0A2E;\n --u-purple-100: #2E174D;\n --u-purple-200: #42246B;\n --u-purple-300: #5A358F;\n --u-purple-400: #7548B2;\n --u-purple-500: #9260D6;\n --u-purple-600: #AE78F5;\n --u-purple-700: #C494FF;\n --u-purple-800: #D8B3FF;\n --u-purple-900: #ECD2FF;\n --u-purple-1000: #F7F0FF;\n\n /* Pink Colors */\n --u-pink-0: #2E0A1A;\n --u-pink-100: #4D172E;\n --u-pink-200: #6B2442;\n --u-pink-300: #8F355A;\n --u-pink-400: #B24875;\n --u-pink-500: #D66092;\n --u-pink-600: #F578AE;\n --u-pink-700: #FF94C4;\n --u-pink-800: #FFB3D8;\n --u-pink-900: #FFD2EB;\n --u-pink-1000: #FFF0F7;\n\n /* Text Colors */\n --u-txt-color: var(--u-neutral-900);\n --u-txt-color-inverse: var(--u-neutral-100);\n --u-txt-color-hover: var(--u-blue-600);\n --u-txt-color-active: var(--u-blue-600);\n --u-txt-color-disabled: var(--u-neutral-500);\n --u-txt-color-weak: var(--u-neutral-700);\n --u-txt-color-strong: var(--u-neutral-1000);\n\n --u-link-txt-color: var(--u-blue-700);\n --u-tooltip-txt-color: var(--u-neutral-100);\n\n /* Icon Colors */\n --u-icon-color: var(--u-neutral-800);\n --u-icon-color-inverse: var(--u-neutral-100);\n --u-icon-color-hover: var(--u-blue-600);\n --u-icon-color-active: var(--u-blue-600);\n --u-icon-color-disabled: var(--u-neutral-500);\n\n /* Border Colors */\n --u-border-color: var(--u-neutral-400);\n --u-border-color-weak: var(--u-neutral-300);\n --u-border-color-strong: var(--u-neutral-500);\n\n --u-input-border-color: var(--u-neutral-400);\n --u-input-border-color-hover: var(--u-neutral-500);\n --u-input-border-color-focus: var(--u-blue-600);\n --u-input-border-color-invalid: var(--u-red-600);\n\n /* Background Colors */\n --u-bg-color: var(--u-neutral-100);\n --u-bg-color-inverse: var(--u-neutral-0);\n --u-bg-color-hover: var(--u-neutral-300);\n --u-bg-color-active: var(--u-neutral-400);\n --u-bg-color-disabled: var(--u-neutral-100);\n \n --u-input-bg-color: var(--u-neutral-200);\n --u-panel-bg-color: var(--u-neutral-200);\n --u-overlay-bg-color: rgba(0, 0, 0, 0.7);\n --u-tooltip-bg-color: rgba(255, 255, 255, 0.85);\n\n /* Shadow Colors */\n --u-shadow-color-weaker: rgba(0, 0, 0, 0.15);\n --u-shadow-color-weak: rgba(0, 0, 0, 0.25);\n --u-shadow-color-normal: rgba(0, 0, 0, 0.35);\n --u-shadow-color-strong: rgba(0, 0, 0, 0.45);\n --u-shadow-color-stronger: rgba(0, 0, 0, 0.60);\n\n /* Scrollbar Colors */\n --u-scrollbar-color: var(--u-neutral-500);\n --u-scrollbar-color-hover: var(--u-neutral-600);\n --u-scrollbar-track-color: transparent;\n\n /* Font Styles */\n --u-font-base: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';\n --u-font-mono: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Monaco, 'Courier New', monospace;\n --u-font-serif: 'Georgia', 'Times New Roman', Times, serif;\n --u-font-display: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif;\n --u-font-modern: 'Inter', 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n --u-font-rounded: 'Nunito', 'Quicksand', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n}";
2
+ var dark_css_default = ":root[theme=\"dark\"] {\n color-scheme: dark;\n\n /* Neutral Colors */\n --u-neutral-0: #000000;\n --u-neutral-50: #0A0A0A;\n --u-neutral-100: #121212;\n --u-neutral-200: #1E1E1E;\n --u-neutral-300: #2A2A2A;\n --u-neutral-400: #3D3D3D;\n --u-neutral-500: #525252;\n --u-neutral-600: #6E6E6E;\n --u-neutral-700: #8A8A8A;\n --u-neutral-800: #B0B0B0;\n --u-neutral-900: #D4D4D4;\n --u-neutral-1000: #FFFFFF;\n\n /* Blue Colors */\n --u-blue-0: #030D1A;\n --u-blue-100: #061629;\n --u-blue-200: #0A223B;\n --u-blue-300: #103150;\n --u-blue-400: #174167;\n --u-blue-500: #205281;\n --u-blue-600: #2A659D;\n --u-blue-700: #3678B8;\n --u-blue-800: #478DCE;\n --u-blue-900: #5DA2DF;\n --u-blue-1000: #79BBEA;\n\n /* Green Colors */\n --u-green-0: #06140C;\n --u-green-100: #0A2114;\n --u-green-200: #10301D;\n --u-green-300: #164228;\n --u-green-400: #1F5535;\n --u-green-500: #2A6942;\n --u-green-600: #367E50;\n --u-green-700: #4A9563;\n --u-green-800: #63AB7A;\n --u-green-900: #80BE97;\n --u-green-1000: #9BCFB1;\n\n /* Yellow Colors */\n --u-yellow-0: #1C1300;\n --u-yellow-100: #2D1E00;\n --u-yellow-200: #402B00;\n --u-yellow-300: #553900;\n --u-yellow-400: #6B4900;\n --u-yellow-500: #825A00;\n --u-yellow-600: #9A6C00;\n --u-yellow-700: #B08012;\n --u-yellow-800: #C69635;\n --u-yellow-900: #D9AD5A;\n --u-yellow-1000: #E8C57F;\n\n /* Red Colors */\n --u-red-0: #1C0707;\n --u-red-100: #2C0B0B;\n --u-red-200: #3E1111;\n --u-red-300: #541818;\n --u-red-400: #6C2020;\n --u-red-500: #852A2A;\n --u-red-600: #A13535;\n --u-red-700: #B94949;\n --u-red-800: #CB6262;\n --u-red-900: #D98383;\n --u-red-1000: #E7A2A2;\n\n /* Orange Colors */\n --u-orange-0: #1D0E00;\n --u-orange-100: #2F1700;\n --u-orange-200: #421F00;\n --u-orange-300: #582A00;\n --u-orange-400: #703600;\n --u-orange-500: #8A4500;\n --u-orange-600: #A55600;\n --u-orange-700: #BD6A18;\n --u-orange-800: #D1823C;\n --u-orange-900: #E19D67;\n --u-orange-1000: #EDB992;\n\n /* Teal Colors */\n --u-teal-0: #041411;\n --u-teal-100: #07201B;\n --u-teal-200: #0B2E28;\n --u-teal-300: #10403A;\n --u-teal-400: #16544D;\n --u-teal-500: #1E6860;\n --u-teal-600: #297D74;\n --u-teal-700: #3A9389;\n --u-teal-800: #54A89F;\n --u-teal-900: #73BBB3;\n --u-teal-1000: #93CBC5;\n\n /* Cyan Colors */\n --u-cyan-0: #041318;\n --u-cyan-100: #071F29;\n --u-cyan-200: #0B2D3A;\n --u-cyan-300: #104050;\n --u-cyan-400: #165469;\n --u-cyan-500: #1E6A82;\n --u-cyan-600: #287F9C;\n --u-cyan-700: #3995B5;\n --u-cyan-800: #53AACC;\n --u-cyan-900: #73BEDD;\n --u-cyan-1000: #95CFE8;\n\n /* Purple Colors */\n --u-purple-0: #150A22;\n --u-purple-100: #220F36;\n --u-purple-200: #31164B;\n --u-purple-300: #432064;\n --u-purple-400: #572B80;\n --u-purple-500: #6C379C;\n --u-purple-600: #8245B7;\n --u-purple-700: #975BCB;\n --u-purple-800: #AB79D9;\n --u-purple-900: #BD99E2;\n --u-purple-1000: #CEB8EA;\n\n /* Pink Colors */\n --u-pink-0: #1F0A14;\n --u-pink-100: #310F20;\n --u-pink-200: #451532;\n --u-pink-300: #5C1D45;\n --u-pink-400: #74285A;\n --u-pink-500: #8F336F;\n --u-pink-600: #AB4187;\n --u-pink-700: #C0569D;\n --u-pink-800: #D174B3;\n --u-pink-900: #E095C7;\n --u-pink-1000: #EBB5D9;\n\n /* Text Colors */\n --u-txt-color: var(--u-neutral-900);\n --u-txt-color-inverse: var(--u-neutral-100);\n --u-txt-color-hover: var(--u-blue-600);\n --u-txt-color-active: var(--u-blue-600);\n --u-txt-color-disabled: var(--u-neutral-500);\n --u-txt-color-weak: var(--u-neutral-700);\n --u-txt-color-strong: var(--u-neutral-1000);\n\n --u-link-txt-color: var(--u-blue-700);\n --u-tooltip-txt-color: var(--u-neutral-100);\n\n /* Icon Colors */\n --u-icon-color: var(--u-neutral-800);\n --u-icon-color-inverse: var(--u-neutral-100);\n --u-icon-color-hover: var(--u-blue-600);\n --u-icon-color-active: var(--u-blue-600);\n --u-icon-color-disabled: var(--u-neutral-500);\n\n /* Border Colors */\n --u-border-color: var(--u-neutral-400);\n --u-border-color-weak: var(--u-neutral-300);\n --u-border-color-strong: var(--u-neutral-500);\n\n --u-input-border-color: var(--u-neutral-400);\n --u-input-border-color-hover: var(--u-neutral-500);\n --u-input-border-color-focus: var(--u-blue-600);\n --u-input-border-color-invalid: var(--u-red-600);\n\n /* Background Colors */\n --u-bg-color: var(--u-neutral-100);\n --u-bg-color-inverse: var(--u-neutral-0);\n --u-bg-color-hover: var(--u-neutral-300);\n --u-bg-color-active: var(--u-neutral-400);\n --u-bg-color-disabled: var(--u-neutral-100);\n \n --u-input-bg-color: var(--u-neutral-200);\n --u-panel-bg-color: var(--u-neutral-200);\n --u-overlay-bg-color: rgba(0, 0, 0, 0.7);\n --u-tooltip-bg-color: rgba(255, 255, 255, 0.85);\n\n /* Shadow Colors */\n --u-shadow-color-weaker: rgba(0, 0, 0, 0.15);\n --u-shadow-color-weak: rgba(0, 0, 0, 0.25);\n --u-shadow-color-normal: rgba(0, 0, 0, 0.35);\n --u-shadow-color-strong: rgba(0, 0, 0, 0.45);\n --u-shadow-color-stronger: rgba(0, 0, 0, 0.60);\n\n /* Scrollbar Colors */\n --u-scrollbar-color: var(--u-neutral-500);\n --u-scrollbar-color-hover: var(--u-neutral-600);\n --u-scrollbar-track-color: transparent;\n\n /* Font Styles */\n --u-font-base: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';\n --u-font-mono: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Monaco, 'Courier New', monospace;\n --u-font-serif: 'Georgia', 'Times New Roman', Times, serif;\n --u-font-display: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif;\n --u-font-modern: 'Inter', 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n --u-font-rounded: 'Nunito', 'Quicksand', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n}";
3
3
  //#endregion
4
4
  export { dark_css_default as default };
@@ -0,0 +1,23 @@
1
+ //#region src/assets/locales/ar.json
2
+ var valueMissing = "هذا الحقل مطلوب";
3
+ var badInput = "يرجى إدخال قيمة صالحة";
4
+ var typeMismatch = "يرجى إدخال قيمة بالتنسيق الصحيح";
5
+ var patternMismatch = "يرجى اتباع التنسيق المطلوب";
6
+ var rangeUnderflow = "يجب أن تكون القيمة {min} على الأقل";
7
+ var rangeOverflow = "يجب ألا تتجاوز القيمة {max}";
8
+ var stepMismatch = "يجب أن تكون القيمة من مضاعفات {step}";
9
+ var tooShort = "يجب أن تكون {min} على الأقل";
10
+ var tooLong = "يجب ألا تتجاوز {max}";
11
+ var ar_default = {
12
+ valueMissing,
13
+ badInput,
14
+ typeMismatch,
15
+ patternMismatch,
16
+ rangeUnderflow,
17
+ rangeOverflow,
18
+ stepMismatch,
19
+ tooShort,
20
+ tooLong
21
+ };
22
+ //#endregion
23
+ export { badInput, ar_default as default, patternMismatch, rangeOverflow, rangeUnderflow, stepMismatch, tooLong, tooShort, typeMismatch, valueMissing };
@@ -0,0 +1,23 @@
1
+ //#region src/assets/locales/de.json
2
+ var valueMissing = "Dieses Feld ist erforderlich";
3
+ var badInput = "Bitte geben Sie einen gültigen Wert ein";
4
+ var typeMismatch = "Bitte geben Sie einen gültigen Wert ein";
5
+ var patternMismatch = "Bitte halten Sie sich an das angeforderte Format";
6
+ var rangeUnderflow = "Der Wert muss mindestens {min} betragen";
7
+ var rangeOverflow = "Der Wert darf höchstens {max} betragen";
8
+ var stepMismatch = "Der Wert muss ein Vielfaches von {step} sein";
9
+ var tooShort = "Muss mindestens {min} betragen";
10
+ var tooLong = "Darf höchstens {max} betragen";
11
+ var de_default = {
12
+ valueMissing,
13
+ badInput,
14
+ typeMismatch,
15
+ patternMismatch,
16
+ rangeUnderflow,
17
+ rangeOverflow,
18
+ stepMismatch,
19
+ tooShort,
20
+ tooLong
21
+ };
22
+ //#endregion
23
+ export { badInput, de_default as default, patternMismatch, rangeOverflow, rangeUnderflow, stepMismatch, tooLong, tooShort, typeMismatch, valueMissing };
@@ -0,0 +1,23 @@
1
+ //#region src/assets/locales/en.json
2
+ var valueMissing = "This field is required";
3
+ var badInput = "Please enter a valid value";
4
+ var typeMismatch = "Please enter a valid value";
5
+ var patternMismatch = "Please match the requested format";
6
+ var rangeUnderflow = "Value must be at least {min}";
7
+ var rangeOverflow = "Value must be at most {max}";
8
+ var stepMismatch = "Value must be a multiple of {step}";
9
+ var tooShort = "Must be at least {min}";
10
+ var tooLong = "Must be at most {max}";
11
+ var en_default = {
12
+ valueMissing,
13
+ badInput,
14
+ typeMismatch,
15
+ patternMismatch,
16
+ rangeUnderflow,
17
+ rangeOverflow,
18
+ stepMismatch,
19
+ tooShort,
20
+ tooLong
21
+ };
22
+ //#endregion
23
+ export { badInput, en_default as default, patternMismatch, rangeOverflow, rangeUnderflow, stepMismatch, tooLong, tooShort, typeMismatch, valueMissing };
@@ -0,0 +1,23 @@
1
+ //#region src/assets/locales/es.json
2
+ var valueMissing = "Este campo es obligatorio";
3
+ var badInput = "Introduzca un valor válido";
4
+ var typeMismatch = "Introduzca un valor con el formato correcto";
5
+ var patternMismatch = "Ajuste el valor al formato solicitado";
6
+ var rangeUnderflow = "El valor debe ser como mínimo {min}";
7
+ var rangeOverflow = "El valor debe ser como máximo {max}";
8
+ var stepMismatch = "El valor debe ser múltiplo de {step}";
9
+ var tooShort = "Debe ser como mínimo {min}";
10
+ var tooLong = "Debe ser como máximo {max}";
11
+ var es_default = {
12
+ valueMissing,
13
+ badInput,
14
+ typeMismatch,
15
+ patternMismatch,
16
+ rangeUnderflow,
17
+ rangeOverflow,
18
+ stepMismatch,
19
+ tooShort,
20
+ tooLong
21
+ };
22
+ //#endregion
23
+ export { badInput, es_default as default, patternMismatch, rangeOverflow, rangeUnderflow, stepMismatch, tooLong, tooShort, typeMismatch, valueMissing };
@@ -0,0 +1,23 @@
1
+ //#region src/assets/locales/fr.json
2
+ var valueMissing = "Ce champ est obligatoire";
3
+ var badInput = "Veuillez saisir une valeur valide";
4
+ var typeMismatch = "Veuillez saisir une valeur au format correct";
5
+ var patternMismatch = "Veuillez respecter le format demandé";
6
+ var rangeUnderflow = "La valeur doit être supérieure ou égale à {min}";
7
+ var rangeOverflow = "La valeur doit être inférieure ou égale à {max}";
8
+ var stepMismatch = "La valeur doit être un multiple de {step}";
9
+ var tooShort = "Doit être au moins {min}";
10
+ var tooLong = "Doit être au plus {max}";
11
+ var fr_default = {
12
+ valueMissing,
13
+ badInput,
14
+ typeMismatch,
15
+ patternMismatch,
16
+ rangeUnderflow,
17
+ rangeOverflow,
18
+ stepMismatch,
19
+ tooShort,
20
+ tooLong
21
+ };
22
+ //#endregion
23
+ export { badInput, fr_default as default, patternMismatch, rangeOverflow, rangeUnderflow, stepMismatch, tooLong, tooShort, typeMismatch, valueMissing };
@@ -0,0 +1,23 @@
1
+ //#region src/assets/locales/id.json
2
+ var valueMissing = "Kolom ini wajib diisi";
3
+ var badInput = "Masukkan nilai yang valid";
4
+ var typeMismatch = "Masukkan nilai dengan format yang benar";
5
+ var patternMismatch = "Sesuaikan dengan format yang diminta";
6
+ var rangeUnderflow = "Nilai harus minimal {min}";
7
+ var rangeOverflow = "Nilai harus maksimal {max}";
8
+ var stepMismatch = "Nilai harus kelipatan dari {step}";
9
+ var tooShort = "Harus minimal {min}";
10
+ var tooLong = "Harus maksimal {max}";
11
+ var id_default = {
12
+ valueMissing,
13
+ badInput,
14
+ typeMismatch,
15
+ patternMismatch,
16
+ rangeUnderflow,
17
+ rangeOverflow,
18
+ stepMismatch,
19
+ tooShort,
20
+ tooLong
21
+ };
22
+ //#endregion
23
+ export { badInput, id_default as default, patternMismatch, rangeOverflow, rangeUnderflow, stepMismatch, tooLong, tooShort, typeMismatch, valueMissing };
@@ -0,0 +1,23 @@
1
+ //#region src/assets/locales/ja.json
2
+ var valueMissing = "この項目は必須です";
3
+ var badInput = "有効な値を入力してください";
4
+ var typeMismatch = "正しい形式の値を入力してください";
5
+ var patternMismatch = "指定された形式で入力してください";
6
+ var rangeUnderflow = "値は{min}以上である必要があります";
7
+ var rangeOverflow = "値は{max}以下である必要があります";
8
+ var stepMismatch = "値は{step}の倍数である必要があります";
9
+ var tooShort = "{min}以上である必要があります";
10
+ var tooLong = "{max}以下である必要があります";
11
+ var ja_default = {
12
+ valueMissing,
13
+ badInput,
14
+ typeMismatch,
15
+ patternMismatch,
16
+ rangeUnderflow,
17
+ rangeOverflow,
18
+ stepMismatch,
19
+ tooShort,
20
+ tooLong
21
+ };
22
+ //#endregion
23
+ export { badInput, ja_default as default, patternMismatch, rangeOverflow, rangeUnderflow, stepMismatch, tooLong, tooShort, typeMismatch, valueMissing };
@@ -0,0 +1,23 @@
1
+ //#region src/assets/locales/ko.json
2
+ var valueMissing = "필수 항목입니다";
3
+ var badInput = "올바른 값을 입력하세요";
4
+ var typeMismatch = "올바른 형식의 값을 입력하세요";
5
+ var patternMismatch = "요청된 형식에 맞게 입력하세요";
6
+ var rangeUnderflow = "값은 {min} 이상이어야 합니다";
7
+ var rangeOverflow = "값은 {max} 이하여야 합니다";
8
+ var stepMismatch = "값은 {step}의 배수여야 합니다";
9
+ var tooShort = "최소 {min} 이상이어야 합니다";
10
+ var tooLong = "최대 {max} 이하여야 합니다";
11
+ var ko_default = {
12
+ valueMissing,
13
+ badInput,
14
+ typeMismatch,
15
+ patternMismatch,
16
+ rangeUnderflow,
17
+ rangeOverflow,
18
+ stepMismatch,
19
+ tooShort,
20
+ tooLong
21
+ };
22
+ //#endregion
23
+ export { badInput, ko_default as default, patternMismatch, rangeOverflow, rangeUnderflow, stepMismatch, tooLong, tooShort, typeMismatch, valueMissing };
@@ -0,0 +1,23 @@
1
+ //#region src/assets/locales/pt-BR.json
2
+ var valueMissing = "Este campo é obrigatório";
3
+ var badInput = "Insira um valor válido";
4
+ var typeMismatch = "Insira um valor no formato correto";
5
+ var patternMismatch = "Siga o formato solicitado";
6
+ var rangeUnderflow = "O valor deve ser no mínimo {min}";
7
+ var rangeOverflow = "O valor deve ser no máximo {max}";
8
+ var stepMismatch = "O valor deve ser um múltiplo de {step}";
9
+ var tooShort = "Deve ser no mínimo {min}";
10
+ var tooLong = "Deve ser no máximo {max}";
11
+ var pt_BR_default = {
12
+ valueMissing,
13
+ badInput,
14
+ typeMismatch,
15
+ patternMismatch,
16
+ rangeUnderflow,
17
+ rangeOverflow,
18
+ stepMismatch,
19
+ tooShort,
20
+ tooLong
21
+ };
22
+ //#endregion
23
+ export { badInput, pt_BR_default as default, patternMismatch, rangeOverflow, rangeUnderflow, stepMismatch, tooLong, tooShort, typeMismatch, valueMissing };
@@ -0,0 +1,23 @@
1
+ //#region src/assets/locales/ru.json
2
+ var valueMissing = "Это поле обязательно для заполнения";
3
+ var badInput = "Введите допустимое значение";
4
+ var typeMismatch = "Введите значение в правильном формате";
5
+ var patternMismatch = "Введите значение в требуемом формате";
6
+ var rangeUnderflow = "Значение должно быть не менее {min}";
7
+ var rangeOverflow = "Значение должно быть не более {max}";
8
+ var stepMismatch = "Значение должно быть кратно {step}";
9
+ var tooShort = "Должно быть не менее {min}";
10
+ var tooLong = "Должно быть не более {max}";
11
+ var ru_default = {
12
+ valueMissing,
13
+ badInput,
14
+ typeMismatch,
15
+ patternMismatch,
16
+ rangeUnderflow,
17
+ rangeOverflow,
18
+ stepMismatch,
19
+ tooShort,
20
+ tooLong
21
+ };
22
+ //#endregion
23
+ export { badInput, ru_default as default, patternMismatch, rangeOverflow, rangeUnderflow, stepMismatch, tooLong, tooShort, typeMismatch, valueMissing };
@@ -0,0 +1,23 @@
1
+ //#region src/assets/locales/th.json
2
+ var valueMissing = "จำเป็นต้องกรอกข้อมูลนี้";
3
+ var badInput = "กรุณากรอกค่าที่ถูกต้อง";
4
+ var typeMismatch = "กรุณากรอกค่าให้ถูกรูปแบบ";
5
+ var patternMismatch = "กรุณากรอกให้ตรงตามรูปแบบที่กำหนด";
6
+ var rangeUnderflow = "ค่าต้องมากกว่าหรือเท่ากับ {min}";
7
+ var rangeOverflow = "ค่าต้องน้อยกว่าหรือเท่ากับ {max}";
8
+ var stepMismatch = "ค่าต้องเป็นจำนวนทวีคูณของ {step}";
9
+ var tooShort = "ต้องมีอย่างน้อย {min}";
10
+ var tooLong = "ต้องไม่เกิน {max}";
11
+ var th_default = {
12
+ valueMissing,
13
+ badInput,
14
+ typeMismatch,
15
+ patternMismatch,
16
+ rangeUnderflow,
17
+ rangeOverflow,
18
+ stepMismatch,
19
+ tooShort,
20
+ tooLong
21
+ };
22
+ //#endregion
23
+ export { badInput, th_default as default, patternMismatch, rangeOverflow, rangeUnderflow, stepMismatch, tooLong, tooShort, typeMismatch, valueMissing };
@@ -0,0 +1,23 @@
1
+ //#region src/assets/locales/vi.json
2
+ var valueMissing = "Trường này là bắt buộc";
3
+ var badInput = "Vui lòng nhập giá trị hợp lệ";
4
+ var typeMismatch = "Vui lòng nhập giá trị đúng định dạng";
5
+ var patternMismatch = "Vui lòng nhập đúng định dạng yêu cầu";
6
+ var rangeUnderflow = "Giá trị phải lớn hơn hoặc bằng {min}";
7
+ var rangeOverflow = "Giá trị phải nhỏ hơn hoặc bằng {max}";
8
+ var stepMismatch = "Giá trị phải là bội số của {step}";
9
+ var tooShort = "Phải lớn hơn hoặc bằng {min}";
10
+ var tooLong = "Phải nhỏ hơn hoặc bằng {max}";
11
+ var vi_default = {
12
+ valueMissing,
13
+ badInput,
14
+ typeMismatch,
15
+ patternMismatch,
16
+ rangeUnderflow,
17
+ rangeOverflow,
18
+ stepMismatch,
19
+ tooShort,
20
+ tooLong
21
+ };
22
+ //#endregion
23
+ export { badInput, vi_default as default, patternMismatch, rangeOverflow, rangeUnderflow, stepMismatch, tooLong, tooShort, typeMismatch, valueMissing };
@@ -0,0 +1,23 @@
1
+ //#region src/assets/locales/zh-CN.json
2
+ var valueMissing = "此项为必填项";
3
+ var badInput = "请输入有效的值";
4
+ var typeMismatch = "请输入正确格式的值";
5
+ var patternMismatch = "请按照要求的格式输入";
6
+ var rangeUnderflow = "值必须大于或等于{min}";
7
+ var rangeOverflow = "值必须小于或等于{max}";
8
+ var stepMismatch = "值必须是{step}的倍数";
9
+ var tooShort = "至少需要{min}";
10
+ var tooLong = "最多不能超过{max}";
11
+ var zh_CN_default = {
12
+ valueMissing,
13
+ badInput,
14
+ typeMismatch,
15
+ patternMismatch,
16
+ rangeUnderflow,
17
+ rangeOverflow,
18
+ stepMismatch,
19
+ tooShort,
20
+ tooLong
21
+ };
22
+ //#endregion
23
+ export { badInput, zh_CN_default as default, patternMismatch, rangeOverflow, rangeUnderflow, stepMismatch, tooLong, tooShort, typeMismatch, valueMissing };
@@ -0,0 +1,23 @@
1
+ //#region src/assets/locales/zh-TW.json
2
+ var valueMissing = "此欄位為必填";
3
+ var badInput = "請輸入有效的值";
4
+ var typeMismatch = "請輸入正確格式的值";
5
+ var patternMismatch = "請依照要求的格式輸入";
6
+ var rangeUnderflow = "值必須大於或等於{min}";
7
+ var rangeOverflow = "值必須小於或等於{max}";
8
+ var stepMismatch = "值必須是{step}的倍數";
9
+ var tooShort = "至少需要{min}";
10
+ var tooLong = "最多不能超過{max}";
11
+ var zh_TW_default = {
12
+ valueMissing,
13
+ badInput,
14
+ typeMismatch,
15
+ patternMismatch,
16
+ rangeUnderflow,
17
+ rangeOverflow,
18
+ stepMismatch,
19
+ tooShort,
20
+ tooLong
21
+ };
22
+ //#endregion
23
+ export { badInput, zh_TW_default as default, patternMismatch, rangeOverflow, rangeUnderflow, stepMismatch, tooLong, tooShort, typeMismatch, valueMissing };
@@ -1,8 +1,8 @@
1
1
  import { UElement } from "./UElement.js";
2
- import __decorateMetadata from "../_virtual/_@oxc-project_runtime@0.138.0/helpers/esm/decorateMetadata.js";
3
- import __decorate from "../_virtual/_@oxc-project_runtime@0.138.0/helpers/esm/decorate.js";
4
2
  import { getParentElement, querySelectorAllWithin } from "../utilities/elements.js";
5
3
  import { styles } from "./UFloatingElement.styles.js";
4
+ import __decorateMetadata from "../_virtual/_@oxc-project_runtime@0.138.0/helpers/esm/decorateMetadata.js";
5
+ import __decorate from "../_virtual/_@oxc-project_runtime@0.138.0/helpers/esm/decorate.js";
6
6
  import { property, state } from "lit/decorators.js";
7
7
  import { arrow, autoPlacement, autoUpdate, computePosition, flip, offset, shift } from "@floating-ui/dom";
8
8
  //#region src/components/UFloatingElement.ts
@@ -73,7 +73,10 @@ var UFloatingElement = class extends UElement {
73
73
  });
74
74
  this.targetEl = target;
75
75
  if (this.open) return true;
76
- if (this.fire("show")) {
76
+ if (this.fire("show", {
77
+ bubbles: false,
78
+ composed: false
79
+ })) {
77
80
  if (this.showDelay > 0) this.showTimer = window.setTimeout(() => {
78
81
  this.showTimer = void 0;
79
82
  this.open = true;
@@ -102,7 +105,10 @@ var UFloatingElement = class extends UElement {
102
105
  await this.updateComplete;
103
106
  this.targetEl = void 0;
104
107
  if (!this.open) return true;
105
- if (this.fire("hide")) {
108
+ if (this.fire("hide", {
109
+ bubbles: false,
110
+ composed: false
111
+ })) {
106
112
  if (this.hideDelay > 0) this.hideTimer = window.setTimeout(() => {
107
113
  this.hideTimer = void 0;
108
114
  this.open = false;
@@ -118,6 +124,9 @@ var UFloatingElement = class extends UElement {
118
124
  * @param target - 위치 계산에 사용할 타겟 엘리먼트입니다.
119
125
  */
120
126
  async reposition(target) {
127
+ const targetRect = target.getBoundingClientRect();
128
+ this.style.setProperty("--anchor-width", `${targetRect.width}px`);
129
+ this.style.setProperty("--anchor-height", `${targetRect.height}px`);
121
130
  const position = await computePosition(target, this, {
122
131
  strategy: this.strategy,
123
132
  placement: this.placement,
@@ -1,4 +1,4 @@
1
- import { CSSResultGroup } from 'lit';
1
+ import { CSSResultGroup, PropertyValues } from 'lit';
2
2
  import { UElement } from './UElement.js';
3
3
  /**
4
4
  * 폼 컨트롤 컴포넌트의 공통 기반 클래스입니다.
@@ -21,10 +21,6 @@ export declare abstract class UFormControlElement<T> extends UElement {
21
21
  label?: string;
22
22
  /** 보조 설명 텍스트 */
23
23
  description?: string;
24
- /** 커스텀 유효성 검증 메시지 */
25
- validationMessage?: string;
26
- /** chrome 문자열(검증 메시지 등)에 사용할 로케일 태그 (예: 'ko-KR'). 미지정 시 전역 기본/문서 언어를 따른다. */
27
- locale?: string;
28
24
  /** 폼 제출 시 사용되는 이름 */
29
25
  name?: string;
30
26
  /** 폼 제출 시 사용되는 값 */
@@ -43,14 +39,48 @@ export declare abstract class UFormControlElement<T> extends UElement {
43
39
  * ElementInternals를 지원하지 않는 브라우저에서는 undefined를 반환합니다.
44
40
  */
45
41
  get validity(): ValidityState | undefined;
42
+ /**
43
+ * 지금 `internals`에 설정된 유효성 메시지입니다. `setValidity()`가 계산한 값을
44
+ * 그대로 반영하는 읽기 전용 파생값이며, 별도로 저장하지 않는다.
45
+ * ElementInternals를 지원하지 않는 브라우저에서는 빈 문자열을 반환한다.
46
+ */
47
+ get validationMessage(): string;
48
+ /** `setCustomValidity()`로 주입된 커스텀 메시지. 비어있으면 커스텀 메시지가 없는 상태. */
49
+ private customMessage;
50
+ /**
51
+ * 네이티브 `HTMLInputElement.setCustomValidity()`와 동일한 API입니다.
52
+ * 상태(및 `internals`)만 갱신할 뿐 화면은 건드리지 않는다 — UI 반영은 항상 `validate()`의 몫이다.
53
+ * 빈 문자열을 넘기면 해제되어 원래 자동 계산된 메시지로 돌아간다.
54
+ */
55
+ setCustomValidity(message: string): void;
56
+ /**
57
+ * 각 컴포넌트의 `setValidity()`가 계산한 flags/message를 `internals.setValidity()`로
58
+ * 반영하는 공통 헬퍼입니다. `setCustomValidity()`로 커스텀 메시지가 주입돼 있으면
59
+ * 네이티브와 동일하게 그 메시지가 다른 모든 검증 결과보다 우선한다.
60
+ */
61
+ protected commit(flags: ValidityStateFlags, message: string, anchor?: HTMLElement): void;
46
62
  connectedCallback(): void;
63
+ protected updated(changedProperties: PropertyValues): void;
64
+ /**
65
+ * 어떤 속성이 바뀌었을 때 `setValidity()`를 다시 호출할지 결정합니다.
66
+ * 기본값은 `value`/`required`. `checked`처럼 다른 속성으로 상태를
67
+ * 표현하는 컴포넌트는 override합니다 (`super.shouldValidate(changed) || changed.has('checked')`).
68
+ */
69
+ protected shouldValidate(changed: PropertyValues): boolean;
70
+ /**
71
+ * 지금 상태를 검증해 `internals.setValidity(flags, message, anchor)`를 호출합니다.
72
+ * 각 컴포넌트가 자신의 검증 규칙과 메시지 조회(`Locale.getValue()`)를 직접 구현합니다.
73
+ */
74
+ protected abstract setValidity(): void;
47
75
  /**
48
- * 컴포넌트 자체 유효성을 검증하고 `invalid` 상태를 갱신합니다.
49
- * 각 컴포넌트가 자신의 검증 로직으로 구현합니다.
76
+ * 컴포넌트 자체 유효성을 검증합니다.
50
77
  *
78
+ * @param report `true`(기본값)면 `invalid` 상태(및 에러 메시지 표시)를 갱신한다.
79
+ * `false`면 화면에 아무 영향 없이 유효 여부만 조용히 확인한다 — 네이티브
80
+ * `checkValidity()`(조용히 확인) vs `reportValidity()`(UI 갱신)와 같은 관계.
51
81
  * @returns 유효하면 `true`, 아니면 `false`
52
82
  */
53
- abstract validate(): boolean;
83
+ validate(report?: boolean): boolean;
54
84
  /**
55
85
  * 폼이 리셋될 때 호출되는 메서드입니다.
56
86
  * 각 컴포넌트가 자신의 초기 상태로 리셋하는 로직을 구현합니다.
@@ -1,7 +1,7 @@
1
1
  import { UElement } from "./UElement.js";
2
- import { styles } from "./UFormControlElement.styles.js";
3
2
  import __decorateMetadata from "../_virtual/_@oxc-project_runtime@0.138.0/helpers/esm/decorateMetadata.js";
4
3
  import __decorate from "../_virtual/_@oxc-project_runtime@0.138.0/helpers/esm/decorate.js";
4
+ import { styles } from "./UFormControlElement.styles.js";
5
5
  import { property } from "lit/decorators.js";
6
6
  //#region src/components/UFormControlElement.ts
7
7
  /**
@@ -16,6 +16,7 @@ var UFormControlElement = class extends UElement {
16
16
  this.required = false;
17
17
  this.invalid = false;
18
18
  this.novalidate = false;
19
+ this.customMessage = "";
19
20
  }
20
21
  static {
21
22
  this.styles = [super.styles, styles];
@@ -23,24 +24,80 @@ var UFormControlElement = class extends UElement {
23
24
  static {
24
25
  this.formAssociated = true;
25
26
  }
26
- /**
27
+ /**
27
28
  * 폼과의 연동을 위해 `form` 속성을 제공합니다. ElementInternals를 지원하는 브라우저에서 폼 요소에 접근할 수 있습니다.
28
- * 지원하지 않는 브라우저에서는 null을 반환합니다.
29
+ * 지원하지 않는 브라우저에서는 null을 반환합니다.
29
30
  */
30
31
  get form() {
31
32
  return this.internals?.form ?? null;
32
33
  }
33
- /**
34
+ /**
34
35
  * 각 컴포넌트가 자신의 검증 로직으로 validity 상태를 갱신하면, 이 객체를 통해 유효성 상태를 확인할 수 있습니다.
35
36
  * ElementInternals를 지원하지 않는 브라우저에서는 undefined를 반환합니다.
36
37
  */
37
38
  get validity() {
38
39
  return this.internals?.validity;
39
40
  }
41
+ /**
42
+ * 지금 `internals`에 설정된 유효성 메시지입니다. `setValidity()`가 계산한 값을
43
+ * 그대로 반영하는 읽기 전용 파생값이며, 별도로 저장하지 않는다.
44
+ * ElementInternals를 지원하지 않는 브라우저에서는 빈 문자열을 반환한다.
45
+ */
46
+ get validationMessage() {
47
+ return this.internals?.validationMessage ?? "";
48
+ }
49
+ /**
50
+ * 네이티브 `HTMLInputElement.setCustomValidity()`와 동일한 API입니다.
51
+ * 상태(및 `internals`)만 갱신할 뿐 화면은 건드리지 않는다 — UI 반영은 항상 `validate()`의 몫이다.
52
+ * 빈 문자열을 넘기면 해제되어 원래 자동 계산된 메시지로 돌아간다.
53
+ */
54
+ setCustomValidity(message) {
55
+ this.customMessage = message;
56
+ this.setValidity();
57
+ }
58
+ /**
59
+ * 각 컴포넌트의 `setValidity()`가 계산한 flags/message를 `internals.setValidity()`로
60
+ * 반영하는 공통 헬퍼입니다. `setCustomValidity()`로 커스텀 메시지가 주입돼 있으면
61
+ * 네이티브와 동일하게 그 메시지가 다른 모든 검증 결과보다 우선한다.
62
+ */
63
+ commit(flags, message, anchor) {
64
+ if (this.customMessage) this.internals?.setValidity({ customError: true }, this.customMessage, anchor);
65
+ else this.internals?.setValidity(flags, message, anchor);
66
+ }
40
67
  connectedCallback() {
41
68
  super.connectedCallback();
42
69
  if ("attachInternals" in this) this.internals = this.attachInternals();
43
70
  }
71
+ updated(changedProperties) {
72
+ super.updated(changedProperties);
73
+ if (this.shouldValidate(changedProperties)) {
74
+ this.setValidity();
75
+ this.requestUpdate();
76
+ }
77
+ }
78
+ /**
79
+ * 어떤 속성이 바뀌었을 때 `setValidity()`를 다시 호출할지 결정합니다.
80
+ * 기본값은 `value`/`required`. `checked`처럼 다른 속성으로 상태를
81
+ * 표현하는 컴포넌트는 override합니다 (`super.shouldValidate(changed) || changed.has('checked')`).
82
+ */
83
+ shouldValidate(changed) {
84
+ return changed.has("value") || changed.has("required");
85
+ }
86
+ /**
87
+ * 컴포넌트 자체 유효성을 검증합니다.
88
+ *
89
+ * @param report `true`(기본값)면 `invalid` 상태(및 에러 메시지 표시)를 갱신한다.
90
+ * `false`면 화면에 아무 영향 없이 유효 여부만 조용히 확인한다 — 네이티브
91
+ * `checkValidity()`(조용히 확인) vs `reportValidity()`(UI 갱신)와 같은 관계.
92
+ * @returns 유효하면 `true`, 아니면 `false`
93
+ */
94
+ validate(report = true) {
95
+ this.setValidity();
96
+ this.requestUpdate();
97
+ const valid = this.internals ? this.internals.checkValidity() : true;
98
+ if (report) this.invalid = !valid;
99
+ return valid;
100
+ }
44
101
  };
45
102
  __decorate([property({
46
103
  type: Boolean,
@@ -61,8 +118,6 @@ __decorate([property({
61
118
  __decorate([property({ type: Boolean }), __decorateMetadata("design:type", Boolean)], UFormControlElement.prototype, "novalidate", void 0);
62
119
  __decorate([property({ type: String }), __decorateMetadata("design:type", String)], UFormControlElement.prototype, "label", void 0);
63
120
  __decorate([property({ type: String }), __decorateMetadata("design:type", String)], UFormControlElement.prototype, "description", void 0);
64
- __decorate([property({ type: String }), __decorateMetadata("design:type", String)], UFormControlElement.prototype, "validationMessage", void 0);
65
- __decorate([property({ type: String }), __decorateMetadata("design:type", String)], UFormControlElement.prototype, "locale", void 0);
66
121
  __decorate([property({ type: String }), __decorateMetadata("design:type", String)], UFormControlElement.prototype, "name", void 0);
67
122
  __decorate([property({ type: Object }), __decorateMetadata("design:type", Object)], UFormControlElement.prototype, "value", void 0);
68
123
  //#endregion
@@ -52,6 +52,10 @@ export declare abstract class UOverlayElement extends UElement {
52
52
  /**
53
53
  * 오버레이를 숨깁니다. `hide` 이벤트가 취소되면 닫히지 않습니다.
54
54
  * (이벤트 이름은 `hide`, prefix 없음 — `addEventListener('hide', ...)`로 수신)
55
+ *
56
+ * bubbles:false — 중첩된 다이얼로그/드로어/팝오버 조합에서 자식의 hide가
57
+ * 조상 오버레이까지 버블링되어 조상이 자신의 hide로 오인해 닫히는 사고를 방지한다.
58
+ * 이 이벤트는 항상 자기 자신(target)에 리스너를 붙이는 패턴으로만 소비된다.
55
59
  */
56
60
  hide(): boolean;
57
61
  /** closeOn 정책에 따라 닫기를 시도합니다. */