moru-krds-react 0.1.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 (247) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +61 -0
  3. package/dist/accordion/index.d.ts +63 -0
  4. package/dist/accordion/index.d.ts.map +1 -0
  5. package/dist/accordion/index.js +145 -0
  6. package/dist/accordion/index.js.map +1 -0
  7. package/dist/alert/index.d.ts +44 -0
  8. package/dist/alert/index.d.ts.map +1 -0
  9. package/dist/alert/index.js +66 -0
  10. package/dist/alert/index.js.map +1 -0
  11. package/dist/avatar/index.d.ts +102 -0
  12. package/dist/avatar/index.d.ts.map +1 -0
  13. package/dist/avatar/index.js +146 -0
  14. package/dist/avatar/index.js.map +1 -0
  15. package/dist/badge/index.d.ts +49 -0
  16. package/dist/badge/index.d.ts.map +1 -0
  17. package/dist/badge/index.js +41 -0
  18. package/dist/badge/index.js.map +1 -0
  19. package/dist/breadcrumb/index.d.ts +43 -0
  20. package/dist/breadcrumb/index.d.ts.map +1 -0
  21. package/dist/breadcrumb/index.js +43 -0
  22. package/dist/breadcrumb/index.js.map +1 -0
  23. package/dist/button/index.d.ts +78 -0
  24. package/dist/button/index.d.ts.map +1 -0
  25. package/dist/button/index.js +83 -0
  26. package/dist/button/index.js.map +1 -0
  27. package/dist/checkbox/index.d.ts +97 -0
  28. package/dist/checkbox/index.d.ts.map +1 -0
  29. package/dist/checkbox/index.js +110 -0
  30. package/dist/checkbox/index.js.map +1 -0
  31. package/dist/combobox/index.d.ts +135 -0
  32. package/dist/combobox/index.d.ts.map +1 -0
  33. package/dist/combobox/index.js +416 -0
  34. package/dist/combobox/index.js.map +1 -0
  35. package/dist/context-menu/index.d.ts +94 -0
  36. package/dist/context-menu/index.d.ts.map +1 -0
  37. package/dist/context-menu/index.js +399 -0
  38. package/dist/context-menu/index.js.map +1 -0
  39. package/dist/critical-alert/index.d.ts +39 -0
  40. package/dist/critical-alert/index.d.ts.map +1 -0
  41. package/dist/critical-alert/index.js +50 -0
  42. package/dist/critical-alert/index.js.map +1 -0
  43. package/dist/data-table/index.d.ts +94 -0
  44. package/dist/data-table/index.d.ts.map +1 -0
  45. package/dist/data-table/index.js +128 -0
  46. package/dist/data-table/index.js.map +1 -0
  47. package/dist/disclosure/index.d.ts +35 -0
  48. package/dist/disclosure/index.d.ts.map +1 -0
  49. package/dist/disclosure/index.js +54 -0
  50. package/dist/disclosure/index.js.map +1 -0
  51. package/dist/drawer/index.d.ts +106 -0
  52. package/dist/drawer/index.d.ts.map +1 -0
  53. package/dist/drawer/index.js +352 -0
  54. package/dist/drawer/index.js.map +1 -0
  55. package/dist/empty-state/index.d.ts +86 -0
  56. package/dist/empty-state/index.d.ts.map +1 -0
  57. package/dist/empty-state/index.js +138 -0
  58. package/dist/empty-state/index.js.map +1 -0
  59. package/dist/env.d.js +1 -0
  60. package/dist/env.d.js.map +1 -0
  61. package/dist/field/index.d.ts +149 -0
  62. package/dist/field/index.d.ts.map +1 -0
  63. package/dist/field/index.js +121 -0
  64. package/dist/field/index.js.map +1 -0
  65. package/dist/file-upload/index.d.ts +140 -0
  66. package/dist/file-upload/index.d.ts.map +1 -0
  67. package/dist/file-upload/index.js +249 -0
  68. package/dist/file-upload/index.js.map +1 -0
  69. package/dist/footer/index.d.ts +155 -0
  70. package/dist/footer/index.d.ts.map +1 -0
  71. package/dist/footer/index.js +186 -0
  72. package/dist/footer/index.js.map +1 -0
  73. package/dist/header/index.d.ts +170 -0
  74. package/dist/header/index.d.ts.map +1 -0
  75. package/dist/header/index.js +258 -0
  76. package/dist/header/index.js.map +1 -0
  77. package/dist/identifier/index.d.ts +38 -0
  78. package/dist/identifier/index.d.ts.map +1 -0
  79. package/dist/identifier/index.js +55 -0
  80. package/dist/identifier/index.js.map +1 -0
  81. package/dist/in-page-navigation/index.d.ts +71 -0
  82. package/dist/in-page-navigation/index.d.ts.map +1 -0
  83. package/dist/in-page-navigation/index.js +137 -0
  84. package/dist/in-page-navigation/index.js.map +1 -0
  85. package/dist/index.d.ts +57 -0
  86. package/dist/index.d.ts.map +1 -0
  87. package/dist/index.js +47 -0
  88. package/dist/index.js.map +1 -0
  89. package/dist/input-group/index.d.ts +66 -0
  90. package/dist/input-group/index.d.ts.map +1 -0
  91. package/dist/input-group/index.js +85 -0
  92. package/dist/input-group/index.js.map +1 -0
  93. package/dist/lib/krds.d.ts +45 -0
  94. package/dist/lib/krds.d.ts.map +1 -0
  95. package/dist/lib/krds.js +11 -0
  96. package/dist/lib/krds.js.map +1 -0
  97. package/dist/lib/link.d.ts +34 -0
  98. package/dist/lib/link.d.ts.map +1 -0
  99. package/dist/lib/link.js +8 -0
  100. package/dist/lib/link.js.map +1 -0
  101. package/dist/main-menu/index.d.ts +123 -0
  102. package/dist/main-menu/index.d.ts.map +1 -0
  103. package/dist/main-menu/index.js +613 -0
  104. package/dist/main-menu/index.js.map +1 -0
  105. package/dist/masthead/index.d.ts +25 -0
  106. package/dist/masthead/index.d.ts.map +1 -0
  107. package/dist/masthead/index.js +21 -0
  108. package/dist/masthead/index.js.map +1 -0
  109. package/dist/modal/index.d.ts +105 -0
  110. package/dist/modal/index.d.ts.map +1 -0
  111. package/dist/modal/index.js +285 -0
  112. package/dist/modal/index.js.map +1 -0
  113. package/dist/pagination/index.d.ts +58 -0
  114. package/dist/pagination/index.d.ts.map +1 -0
  115. package/dist/pagination/index.js +82 -0
  116. package/dist/pagination/index.js.map +1 -0
  117. package/dist/progress/index.d.ts +58 -0
  118. package/dist/progress/index.d.ts.map +1 -0
  119. package/dist/progress/index.js +125 -0
  120. package/dist/progress/index.js.map +1 -0
  121. package/dist/radio/index.d.ts +111 -0
  122. package/dist/radio/index.d.ts.map +1 -0
  123. package/dist/radio/index.js +136 -0
  124. package/dist/radio/index.js.map +1 -0
  125. package/dist/resize/index.d.ts +118 -0
  126. package/dist/resize/index.d.ts.map +1 -0
  127. package/dist/resize/index.js +342 -0
  128. package/dist/resize/index.js.map +1 -0
  129. package/dist/scroll-area/index.d.ts +40 -0
  130. package/dist/scroll-area/index.d.ts.map +1 -0
  131. package/dist/scroll-area/index.js +52 -0
  132. package/dist/scroll-area/index.js.map +1 -0
  133. package/dist/select/index.d.ts +67 -0
  134. package/dist/select/index.d.ts.map +1 -0
  135. package/dist/select/index.js +61 -0
  136. package/dist/select/index.js.map +1 -0
  137. package/dist/separator/index.d.ts +47 -0
  138. package/dist/separator/index.d.ts.map +1 -0
  139. package/dist/separator/index.js +61 -0
  140. package/dist/separator/index.js.map +1 -0
  141. package/dist/side-navigation/index.d.ts +78 -0
  142. package/dist/side-navigation/index.d.ts.map +1 -0
  143. package/dist/side-navigation/index.js +188 -0
  144. package/dist/side-navigation/index.js.map +1 -0
  145. package/dist/skeleton/index.d.ts +76 -0
  146. package/dist/skeleton/index.d.ts.map +1 -0
  147. package/dist/skeleton/index.js +78 -0
  148. package/dist/skeleton/index.js.map +1 -0
  149. package/dist/skip-link/index.d.ts +46 -0
  150. package/dist/skip-link/index.d.ts.map +1 -0
  151. package/dist/skip-link/index.js +37 -0
  152. package/dist/skip-link/index.js.map +1 -0
  153. package/dist/spinner/index.d.ts +58 -0
  154. package/dist/spinner/index.d.ts.map +1 -0
  155. package/dist/spinner/index.js +36 -0
  156. package/dist/spinner/index.js.map +1 -0
  157. package/dist/step-indicator/index.d.ts +41 -0
  158. package/dist/step-indicator/index.d.ts.map +1 -0
  159. package/dist/step-indicator/index.js +63 -0
  160. package/dist/step-indicator/index.js.map +1 -0
  161. package/dist/structured-list/index.d.ts +150 -0
  162. package/dist/structured-list/index.d.ts.map +1 -0
  163. package/dist/structured-list/index.js +194 -0
  164. package/dist/structured-list/index.js.map +1 -0
  165. package/dist/tab/index.d.ts +108 -0
  166. package/dist/tab/index.d.ts.map +1 -0
  167. package/dist/tab/index.js +198 -0
  168. package/dist/tab/index.js.map +1 -0
  169. package/dist/table/index.d.ts +75 -0
  170. package/dist/table/index.d.ts.map +1 -0
  171. package/dist/table/index.js +91 -0
  172. package/dist/table/index.js.map +1 -0
  173. package/dist/tag/index.d.ts +71 -0
  174. package/dist/tag/index.d.ts.map +1 -0
  175. package/dist/tag/index.js +45 -0
  176. package/dist/tag/index.js.map +1 -0
  177. package/dist/text-input/index.d.ts +69 -0
  178. package/dist/text-input/index.d.ts.map +1 -0
  179. package/dist/text-input/index.js +70 -0
  180. package/dist/text-input/index.js.map +1 -0
  181. package/dist/text-list/index.d.ts +71 -0
  182. package/dist/text-list/index.d.ts.map +1 -0
  183. package/dist/text-list/index.js +79 -0
  184. package/dist/text-list/index.js.map +1 -0
  185. package/dist/textarea/index.d.ts +29 -0
  186. package/dist/textarea/index.d.ts.map +1 -0
  187. package/dist/textarea/index.js +69 -0
  188. package/dist/textarea/index.js.map +1 -0
  189. package/dist/toast/index.d.ts +76 -0
  190. package/dist/toast/index.d.ts.map +1 -0
  191. package/dist/toast/index.js +183 -0
  192. package/dist/toast/index.js.map +1 -0
  193. package/dist/tooltip/index.d.ts +84 -0
  194. package/dist/tooltip/index.d.ts.map +1 -0
  195. package/dist/tooltip/index.js +329 -0
  196. package/dist/tooltip/index.js.map +1 -0
  197. package/package.json +57 -0
  198. package/src/accordion/index.tsx +251 -0
  199. package/src/alert/index.tsx +111 -0
  200. package/src/avatar/index.tsx +272 -0
  201. package/src/badge/index.tsx +91 -0
  202. package/src/breadcrumb/index.tsx +125 -0
  203. package/src/button/index.tsx +190 -0
  204. package/src/checkbox/index.tsx +247 -0
  205. package/src/combobox/index.tsx +700 -0
  206. package/src/context-menu/index.tsx +623 -0
  207. package/src/critical-alert/index.tsx +102 -0
  208. package/src/data-table/index.tsx +289 -0
  209. package/src/disclosure/index.tsx +87 -0
  210. package/src/drawer/index.tsx +516 -0
  211. package/src/empty-state/index.tsx +256 -0
  212. package/src/env.d.ts +10 -0
  213. package/src/field/index.tsx +307 -0
  214. package/src/file-upload/index.tsx +492 -0
  215. package/src/footer/index.tsx +393 -0
  216. package/src/header/index.tsx +498 -0
  217. package/src/identifier/index.tsx +96 -0
  218. package/src/in-page-navigation/index.tsx +258 -0
  219. package/src/index.ts +72 -0
  220. package/src/input-group/index.tsx +197 -0
  221. package/src/lib/krds.ts +75 -0
  222. package/src/lib/link.tsx +35 -0
  223. package/src/main-menu/index.tsx +912 -0
  224. package/src/masthead/index.tsx +50 -0
  225. package/src/modal/index.tsx +457 -0
  226. package/src/pagination/index.tsx +198 -0
  227. package/src/progress/index.tsx +198 -0
  228. package/src/radio/index.tsx +283 -0
  229. package/src/resize/index.tsx +541 -0
  230. package/src/scroll-area/index.tsx +96 -0
  231. package/src/select/index.tsx +136 -0
  232. package/src/separator/index.tsx +107 -0
  233. package/src/side-navigation/index.tsx +336 -0
  234. package/src/skeleton/index.tsx +172 -0
  235. package/src/skip-link/index.tsx +89 -0
  236. package/src/spinner/index.tsx +98 -0
  237. package/src/step-indicator/index.tsx +122 -0
  238. package/src/structured-list/index.tsx +395 -0
  239. package/src/tab/index.tsx +348 -0
  240. package/src/table/index.tsx +186 -0
  241. package/src/tag/index.tsx +127 -0
  242. package/src/text-input/index.tsx +156 -0
  243. package/src/text-list/index.tsx +177 -0
  244. package/src/textarea/index.tsx +113 -0
  245. package/src/toast/index.tsx +311 -0
  246. package/src/tooltip/index.tsx +496 -0
  247. package/styles/krds-tailwind.css +335 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/radio/index.tsx"],"sourcesContent":["import type { ChangeEvent, ComponentPropsWithRef, ReactNode } from 'react';\nimport { cx, type KrdsSize } from '../lib/krds';\n\n/**\n * ๋ผ๋””์˜ค ๋ฒ„ํŠผ โ€” KRDS `krds-form-check` ยท `krds-form-chip`.\n *\n * `name` ์„ ๊ณต์œ ํ•˜๋Š” ๊ฒƒ๋ผ๋ฆฌ ํ•œ ๋ฌถ์Œ์ด ๋˜๊ณ  ๋ฐฉํ–ฅํ‚ค ์ด๋™์€ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ•œ๋‹ค.\n * **`<label>` ์•ˆ์— `<input>` ์„ ๋„ฃ์œผ๋ฉด ๋™๊ทธ๋ผ๋ฏธ๊ฐ€ ์•„์˜ˆ ์•ˆ ๊ทธ๋ ค์ง„๋‹ค** โ€” ์ด ๋ถ€ํ’ˆ์ด ๊ทธ ๊ณจ๊ฒฉ์„ ๊ฐ•์ œํ•œ๋‹ค.\n * ๋ณดํ†ต์€ {@link RadioGroup} ์— `options` ๋ฅผ ๋„˜๊ฒจ ํ•œ ๋ฒˆ์— ๊ทธ๋ฆฐ๋‹ค(๊ทธ๋ž˜์•ผ `<fieldset>`/`<legend>` ๊ฐ€ ๋ถ™๋Š”๋‹ค).\n * ์—ฌ๋Ÿฌ ๊ฐ’์„ ๊ณ ๋ฅด๋Š” ์ž๋ฆฌ๋Š” `ui/checkbox` ๋‹ค.\n *\n * @example\n * <RadioGroup label=\"๊ณต๊ฐœ ๋ฒ”์œ„\" name=\"scope\" options={[\n * { value: 'all', label: '์ „์ฒด ๊ณต๊ฐœ' },\n * { value: 'org', label: '๊ธฐ๊ด€ ๋‚ด๋ถ€', description: '์†Œ์† ๊ธฐ๊ด€ ์Šน์ธ ๋’ค ์—ด๋ฆฝ๋‹ˆ๋‹ค.' },\n * ]} />\n * <RadioGroup label=\"๋™์˜\" name=\"agree\" chip equalWidth options={[\n * { value: 'y', label: '์˜ˆ' }, { value: 'n', label: '์•„๋‹ˆ์˜ค' },\n * ]} />\n *\n * ์ž์„ธํžˆ: docs/krds/09-๋ถ€ํ’ˆ-๋…ธํŠธ.md#๋ผ๋””์˜ค\n */\n\n/** ํ•ญ๋ชฉ ํฌ๊ธฐ. ํ‚ท์— ์žˆ๋Š” ๋‘˜๋ฟ์ด๋‹ค โ€” ๋™๊ทธ๋ผ๋ฏธ 20px / 24px, ๊ธ€์ž 17px / 19px. */\nexport type RadioSize = Extract<KrdsSize, 'medium' | 'large'>;\n\n/** ์นฉ ํฌ๊ธฐ. ๋†’์ด 40 / 48 / 56px โ€” ๋ฒ„ํŠผยท์ž…๋ ฅ์นธ๊ณผ ๊ฐ™์€ ๋ˆˆ๊ธˆ์ด๋ผ ํ•œ ์ค„์— ์„ž์–ด๋„ ์–ด๊ธ‹๋‚˜์ง€ ์•Š๋Š”๋‹ค. */\nexport type RadioChipSize = Extract<KrdsSize, 'small' | 'medium' | 'large'>;\n\n/** id ๋ฅผ `name`+`value` ๋กœ ๋งŒ๋“ ๋‹ค. `useId()` ๋ฅผ ์“ฐ๋ฉด ๋ถ€ํ’ˆ์ด ํด๋ผ์ด์–ธํŠธ๋กœ ๋‚ด๋ ค๊ฐ€๋Š”๋ฐ ๊ทธ๋Ÿด ์ด์œ ๊ฐ€ ์—†๋‹ค. */\nfunction radioId(name: string, value: string): string {\n return `${name}-${value}`.replace(/\\s+/g, '-');\n}\n\n/* โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */\n\nexport type RadioProps = Omit<\n ComponentPropsWithRef<'input'>,\n 'type' | 'size' | 'value' | 'className'\n> & {\n /** ๊ทธ๋ฃน ์ด๋ฆ„. ๊ฐ™์€ ๊ฐ’์„ ๊ฐ€์ง„ ๋ผ๋””์˜ค๋ผ๋ฆฌ ํ•œ ๋ฌถ์Œ์ด ๋˜๊ณ  ๋ฐฉํ–ฅํ‚ค๊ฐ€ ๊ทธ ์•ˆ์—์„œ ๋ˆ๋‹ค. */\n name: string;\n /** ๊ฐ’. ๊ฐ™์€ `name` ์•ˆ์—์„œ ์œ ์ผํ•ด์•ผ ํ•œ๋‹ค โ€” `id` ๋ฅผ ์ด ๊ฐ’์œผ๋กœ ๋งŒ๋“ ๋‹ค. */\n value: string;\n /** `<label>` ์— ๋“ค์–ด๊ฐˆ ๊ธ€. */\n label: ReactNode;\n /** ๋ถ€๊ฐ€ ์„ค๋ช…. ์„ธ๋กœ ๋ฐฐ์น˜์™€ ํ•จ๊ป˜ ์“ด๋‹ค. `aria-describedby` ๋กœ ์ด์–ด์ง„๋‹ค. */\n description?: ReactNode;\n /** ํฌ๊ธฐ. ๊ธฐ๋ณธ medium. */\n size?: RadioSize;\n /** ๊ฐ์‹ธ๊ฐœ `div.krds-form-check` ์— ๋ถ™๋Š”๋‹ค(์—ฌ๋ฐฑ ์กฐ์ ˆ์€ ์—ฌ๊ธฐ์„œ). */\n className?: string;\n /** `<input>` ์— ๋ถ™๋Š”๋‹ค. */\n inputClassName?: string;\n};\n\n/** ๋ผ๋””์˜ค ํ•œ ๊ฐœ. `id` ๋ฅผ ์ฃผ์ง€ ์•Š์œผ๋ฉด `name`-`value` ๋กœ ๋งŒ๋“ ๋‹ค. ๋ฌถ์Œ์€ {@link RadioGroup} ์ด๋‹ค. */\nexport function Radio({\n name,\n value,\n label,\n description,\n size = 'medium',\n className,\n inputClassName,\n id,\n 'aria-describedby': describedBy,\n ...rest\n}: RadioProps) {\n const inputId = id ?? radioId(name, value);\n const descId = description ? `${inputId}-desc` : undefined;\n\n return (\n <div className={cx('krds-form-check', size, className)}>\n <input\n type=\"radio\"\n id={inputId}\n name={name}\n value={value}\n className={inputClassName}\n aria-describedby={cx(describedBy, descId) || undefined}\n {...rest}\n />\n <label htmlFor={inputId}>{label}</label>\n {description ? (\n // ํ‚ท ๊ทœ์น™์ด `label + .krds-form-check-cnt` ๋ผ label ๋ฐ”๋กœ ๋‹ค์Œ ํ˜•์ œ์—ฌ์•ผ ์™ผ์ชฝ ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ๋งž๋Š”๋‹ค.\n <div className=\"krds-form-check-cnt\">\n <p className=\"krds-form-check-p\" id={descId}>\n {description}\n </p>\n </div>\n ) : null}\n </div>\n );\n}\n\n/* โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */\n\n/**\n * ์นฉ ํฌ์ปค์Šค ํ…Œ๋‘๋ฆฌ. ํ‚ท์€ JS ๊ฐ€ ๋ถ™์ด๋Š” `.focus` ํด๋ž˜์Šค๋ฅผ ์ „์ œํ•˜๋Š”๋ฐ ๊ทธ JS ๊ฐ€ ์—†์–ด\n * CSS ํ˜•์ œ ์„ ํƒ(`peer` / `peer-focus`)์œผ๋กœ ๊ฐ™์€ ๊ทธ๋ฆผ์„ ๋งŒ๋“ ๋‹ค. ๊ฐ’์€ ํ‚ท ํ† ํฐ ๊ทธ๋Œ€๋กœ๋‹ค.\n */\nconst CHIP_FOCUS_RING = 'peer-focus:[box-shadow:var(--krds-box-shadow-outline-inset)]';\n\nexport type RadioChipProps = Omit<\n ComponentPropsWithRef<'input'>,\n 'type' | 'size' | 'value' | 'className'\n> & {\n /** ๊ทธ๋ฃน ์ด๋ฆ„. */\n name: string;\n /** ๊ฐ’. ๊ฐ™์€ `name` ์•ˆ์—์„œ ์œ ์ผํ•ด์•ผ ํ•œ๋‹ค. */\n value: string;\n /** ์นฉ์— ๋ณด์ด๋Š” ๊ธ€. */\n label: ReactNode;\n /** ํฌ๊ธฐ. ๊ธฐ๋ณธ medium(48px). */\n size?: RadioChipSize;\n /** ๊ฐ์‹ธ๊ฐœ `div.krds-form-chip` ์— ๋ถ™๋Š”๋‹ค. */\n className?: string;\n /** `<input>` ์— ๋ถ™๋Š”๋‹ค. */\n inputClassName?: string;\n};\n\n/**\n * ์นฉ ๋ผ๋””์˜ค โ€” ํ…Œ๋‘๋ฆฌ ์•Œ์•ฝ์„ ๋ˆŒ๋Ÿฌ ๊ณ ๋ฅธ๋‹ค. ์˜ˆ/์•„๋‹ˆ์˜ค์ฒ˜๋Ÿผ ์„ ํƒ์ง€๊ฐ€ ์งง์„ ๋•Œ ์“ด๋‹ค.\n * ์ฒดํฌ ์•„์ด์ฝ˜์€ ํ‚ท์ด ์•Œ์•„์„œ ์ผœ๊ณ  ๋ˆ๋‹ค.\n */\nexport function RadioChip({\n name,\n value,\n label,\n size = 'medium',\n className,\n inputClassName,\n id,\n ...rest\n}: RadioChipProps) {\n const inputId = id ?? radioId(name, value);\n\n return (\n <div className={cx('krds-form-chip', size, className)}>\n <input\n type=\"radio\"\n // `radio` ๋Š” ํ‚ท ์ƒ˜ํ”Œ์ด ๋ถ™์ด๋Š” ํด๋ž˜์Šค๋‹ค(chip-wrap ์•ˆ์—์„œ ์„ ํƒ์ž๋กœ ์“ฐ์ธ๋‹ค).\n className={cx('radio peer', inputClassName)}\n id={inputId}\n name={name}\n value={value}\n {...rest}\n />\n <label className={cx('krds-form-chip-outline', CHIP_FOCUS_RING)} htmlFor={inputId}>\n {label}\n </label>\n </div>\n );\n}\n\n/* โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */\n\n/** `RadioGroup` ์ด ์ง์ ‘ ๊ทธ๋ฆด ํ•ญ๋ชฉ. */\nexport type RadioOption<T extends string = string> = {\n /** ๊ฐ’. */\n value: T;\n /** ํ™”๋ฉด์— ๋ณด์ด๋Š” ๊ธ€. */\n label: ReactNode;\n /** ๋ถ€๊ฐ€ ์„ค๋ช…. ํ•˜๋‚˜๋ผ๋„ ์žˆ์œผ๋ฉด ์„ธ๋กœ ๋ฐฐ์น˜๊ฐ€ ๋งž๋Š”๋‹ค. */\n description?: ReactNode;\n /** ๋น„ํ™œ์„ฑ. */\n disabled?: boolean;\n /** ๊ธฐ๋ณธ๊ฐ’์€ `name`-`value`. ํ•œ ํŽ˜์ด์ง€์— ๊ฐ™์€ `name` ์„ ๋‘ ๋ฒˆ ์“ธ ๋•Œ๋งŒ ์†์œผ๋กœ ์ค€๋‹ค. */\n id?: string;\n};\n\nexport type RadioGroupProps<T extends string = string> = Omit<\n ComponentPropsWithRef<'fieldset'>,\n 'onChange' | 'children'\n> & {\n /** ๋ฌถ์Œ ์ด๋ฆ„. `<legend>` ๋กœ ๋“ค์–ด๊ฐ„๋‹ค โ€” ํ‚ท์ด ํ™”๋ฉด์—์„œ ๊ฐ์ถ”์ง€๋งŒ ์Šคํฌ๋ฆฐ๋ฆฌ๋”๋Š” ์ฝ๋Š”๋‹ค. */\n label: ReactNode;\n /** ์†Œ์ œ๋ชฉ์„ ํ™”๋ฉด์—๋„ ๋ณด์ด๊ฒŒ ํ•œ๋‹ค. ์‚ฌ๋ณธ์ด๋ผ ๋‚ญ๋…์—์„œ๋Š” ๋น ์ง„๋‹ค. */\n labelVisible?: boolean;\n /** ๊ทธ๋ฃน ์ด๋ฆ„. ๋ฐฉํ–ฅํ‚ค ์ด๋™์ด ์ด ๊ฐ’์„ ๊ณต์œ ํ•˜๋Š” ๋ผ๋””์˜ค ์•ˆ์—์„œ ๋ˆ๋‹ค. */\n name: string;\n /** ํ•ญ๋ชฉ. ์ฃผ๋ฉด `RadioGroup` ์ด ์ง์ ‘ ๊ทธ๋ฆฐ๋‹ค. ์ƒ๋žตํ•˜๊ณ  `children` ์œผ๋กœ ์†์ˆ˜ ๋„ฃ์–ด๋„ ๋œ๋‹ค. */\n options?: readonly RadioOption<T>[];\n /** ํ†ต์ œ ์ปดํฌ๋„ŒํŠธ๋กœ ์“ธ ๋•Œ์˜ ํ˜„์žฌ ๊ฐ’. */\n value?: T;\n /** ๋น„ํ†ต์ œ๋กœ ์“ธ ๋•Œ์˜ ์ฒ˜์Œ ๊ฐ’. ์ •ํ™•ํ•œ ๊ฐ’์ด ์ค‘์š”ํ•˜๋ฉด **๊ธฐ๋ณธ ์„ ํƒ๊ฐ’์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค**(๊ทœ๊ฒฉ). */\n defaultValue?: T;\n /** ๊ฐ’์ด ๋ฐ”๋€” ๋•Œ. */\n onValueChange?: (value: T) => void;\n /** ํ•ญ๋ชฉ ํฌ๊ธฐ. ๊ธฐ๋ณธ medium. */\n size?: RadioSize;\n /** ์นฉ ํฌ๊ธฐ. ๊ธฐ๋ณธ medium. */\n chipSize?: RadioChipSize;\n /** ์นฉ ํ˜•ํƒœ๋กœ ๊ทธ๋ฆฐ๋‹ค. */\n chip?: boolean;\n /** ๋ฐฐ์น˜. ๊ธฐ๋ณธ์€ ์„ธ๋กœ๋‹ค(๊ทœ๊ฒฉ). ์นฉ์€ ์„ฑ์งˆ์ƒ ๊ฐ€๋กœ๊ฐ€ ๊ธฐ๋ณธ. */\n orientation?: 'vertical' | 'horizontal';\n /** ์นฉ์„ ๊ฐ™์€ ๋„ˆ๋น„๋กœ ๋Š˜๋ฆฐ๋‹ค(ํ‚ท `chip-wrap`). */\n equalWidth?: boolean;\n /** `div.krds-check-area` ์— ๋ถ™๋Š”๋‹ค. `className` ์€ ๋ฐ”๊นฅ `<fieldset>` ์— ๋ถ™๋Š”๋‹ค. */\n areaClassName?: string;\n children?: ReactNode;\n};\n\n/**\n * ๋ผ๋””์˜ค ๋ฌถ์Œ โ€” `fieldset > legend + div.krds-check-area`. ๊ทœ๊ฒฉ์ด ์š”๊ตฌํ•˜๋Š” ๊ณจ๊ฒฉ์ด๋‹ค.\n *\n * `disabled` ๋ฅผ ์ฃผ๋ฉด ์•ˆ์— ๋“  ๋ผ๋””์˜ค๊ฐ€ ์ „๋ถ€ ์ž ๊ธด๋‹ค(๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ณธ ๋™์ž‘).\n */\nexport function RadioGroup<T extends string = string>({\n label,\n labelVisible,\n name,\n options,\n value,\n defaultValue,\n onValueChange,\n size = 'medium',\n chipSize = 'medium',\n chip,\n orientation,\n equalWidth,\n className,\n areaClassName,\n children,\n ...rest\n}: RadioGroupProps<T>) {\n const vertical = (orientation ?? (chip ? 'horizontal' : 'vertical')) === 'vertical';\n const controlled = value !== undefined;\n\n const handleChange = (e: ChangeEvent<HTMLInputElement>) => {\n onValueChange?.(e.currentTarget.value as T);\n };\n\n return (\n <fieldset\n // ๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ณธ ํ…Œ๋‘๋ฆฌ๋ฅผ ์ง€์šฐ๊ณ , flex/grid ์•ˆ์—์„œ ์ค„์–ด๋“ค์ง€ ๋ชปํ•˜๋Š” ๊ธฐ๋ณธ๊ฐ’์„ ํ‘ผ๋‹ค.\n className={cx('border-0 min-w-0', className)}\n {...rest}\n >\n <legend>{label}</legend>\n {labelVisible ? (\n // `<legend>` ๊ฐ€ ์ด๋ฏธ ์ฝํžˆ๋ฏ€๋กœ ์‚ฌ๋ณธ์€ ๋‚ญ๋…์—์„œ ๋บ€๋‹ค.\n <p className=\"form-label mb-3\" aria-hidden=\"true\">\n {label}\n </p>\n ) : null}\n\n <div\n className={cx(\n 'krds-check-area',\n vertical && 'chk-column',\n equalWidth && 'chip-wrap',\n areaClassName,\n )}\n >\n {options?.map((o) => {\n const common = {\n name,\n value: o.value,\n label: o.label,\n id: o.id,\n disabled: o.disabled,\n onChange: handleChange,\n ...(controlled\n ? { checked: o.value === value }\n : defaultValue !== undefined\n ? { defaultChecked: o.value === defaultValue }\n : null),\n };\n // key ๋Š” spread ๋ฐ–์— ๋‘”๋‹ค โ€” props ๊ฐ์ฒด์— ์„ž์œผ๋ฉด React ๊ฐ€ ๊ฒฝ๊ณ ํ•œ๋‹ค.\n return chip ? (\n <RadioChip key={o.value} {...common} size={chipSize} />\n ) : (\n <Radio key={o.value} {...common} size={size} description={o.description} />\n );\n })}\n {children}\n </div>\n </fieldset>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,118 @@
1
+ import { type ComponentPropsWithRef } from 'react';
2
+ /**
3
+ * ํ™”๋ฉด ํฌ๊ธฐ ์กฐ์ • โ€” KRDS `krds-drop-wrap krds-resize`.
4
+ * ์„ ๋ช…ํ•œ ํ™”๋ฉด ๋ชจ๋“œ ์ „ํ™˜({@link ViewModeSwitch}) โ€” ๊ฐ™์€ ๋“œ๋กญ๋‹ค์šด ๊ป๋ฐ๊ธฐ๋ฅผ ์“ฐ๋Š” ์šฐ๋ฆฌ ๋ถ€ํ’ˆ์ด๋‹ค.
5
+ *
6
+ * ํ—ค๋” ์œ ํ‹ธ๋ฆฌํ‹ฐ ์ค„์— ๋†“๋Š”๋‹ค. ๋ฐฐ์œจ์€ ๋ฌธ์„œ ๋ฃจํŠธ ๊ธ€์ž ํฌ๊ธฐ๋กœ ๊ฑธ๋ฆฌ๋ฏ€๋กœ ํ™”๋ฉด ์ „์ฒด๊ฐ€ ๋”ฐ๋ผ์˜จ๋‹ค.
7
+ * ์ฒซ ํ™”๋ฉด์ด ๊ธฐ๋ณธ ๋ชจ๋“œ๋กœ ๋ฒˆ์ฉ์ด์ง€ ์•Š๊ฒŒ `<head>` ์— {@link ViewSettingsScript} ๋ฅผ ๋‘๊ณ  **nonce ๋ฅผ ๋„˜๊ธด๋‹ค**.
8
+ * `ViewModeSwitch` ๋Š” `<html data-krds-mode>` ๋ฅผ ๋ถ™์ด๋Š” **์œ ์ผํ•œ ๊ณณ**์ด๋‹ค โ€”
9
+ * ์ด๊ฒƒ ์—†์ด๋Š” ํ‚ท์˜ ๊ณ ๋Œ€๋น„ ๊ทœ์น™์ด ํ†ต์งธ๋กœ ์ฃฝ์€ ์ฝ”๋“œ๋กœ ๋‚จ๋Š”๋‹ค.
10
+ *
11
+ * @example
12
+ * // app/layout.tsx <head>
13
+ * <ViewSettingsScript nonce={nonce} />
14
+ * // ํ—ค๋” ์œ ํ‹ธ๋ฆฌํ‹ฐ ์ค„
15
+ * <HeaderUtility>
16
+ * <Resize />
17
+ * <ViewModeSwitch />
18
+ * </HeaderUtility>
19
+ *
20
+ * ์ž์„ธํžˆ: docs/krds/09-๋ถ€ํ’ˆ-๋…ธํŠธ.md#ํฌ๊ธฐ์กฐ์ ˆ
21
+ */
22
+ /** ํ‚ท์˜ 5๋‹จ. ํด๋ž˜์Šค ์ด๋ฆ„(`.item-link.sm` โ€ฆ)๊ณผ ๊ฐ’์ด ๊ฐ™์•„์•ผ ํ•œ๋‹ค. */
23
+ export type ResizeScale = 'sm' | 'md' | 'lg' | 'xlg' | 'xxlg';
24
+ /** 5๋‹จ์˜ ๋ ˆ์ด๋ธ”๊ณผ ๋ฐฐ์œจ โ€” ์ž‘๊ฒŒ 90% ยท ๋ณดํ†ต 100% ยท ์กฐ๊ธˆ ํฌ๊ฒŒ 110% ยท ํฌ๊ฒŒ 130% ยท ๊ฐ€์žฅ ํฌ๊ฒŒ 150%. */
25
+ export declare const RESIZE_SCALES: ReadonlyArray<{
26
+ value: ResizeScale;
27
+ label: string;
28
+ percent: number;
29
+ }>;
30
+ /**
31
+ * ๊ทธ ๋ฐฐ์œจ์—์„œ ๋ฌธ์„œ ๋ฃจํŠธ์— ๋„ฃ์„ ๊ธ€์ž ํฌ๊ธฐ. %(๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ณธ ๊ธ€์ž ํฌ๊ธฐ์˜ ๋น„์œจ)๋ผ
32
+ * ์‚ฌ์šฉ์ž์˜ ๋ธŒ๋ผ์šฐ์ € ๊ธ€๊ผด ์„ค์ •์„ ๋ฎ์ง€ ์•Š๋Š”๋‹ค.
33
+ *
34
+ * @example
35
+ * rootFontSize('lg') // '68.75%'
36
+ */
37
+ export declare function rootFontSize(scale: ResizeScale): string;
38
+ /**
39
+ * ๋ฐฐ์œจ์„ ๋ฌธ์„œ์— ๊ฑด๋‹ค โ€” `<html>` ์ธ๋ผ์ธ ๊ธ€์ž ํฌ๊ธฐ ยท `data-krds-scale` ํ‘œ์‹œ ยท
40
+ * ํ™•๋Œ€(100% ์ดˆ๊ณผ)์ผ ๋•Œ `krds-scaled-layout`(๋ชฉ์ฐจ์˜ ๊ณ ์ • ์œ„์น˜๋ฅผ ํ‘ผ๋‹ค).
41
+ */
42
+ export declare function applyScale(scale: ResizeScale): void;
43
+ /** ํ™”๋ฉด ๋ชจ๋“œ. `light` ๋Š” ์†์„ฑ์„ ๋–ผ๋Š” ๊ฒƒ์ด๊ณ , ๋‚˜๋จธ์ง€ ๋‘˜์€ `<html data-krds-mode>` ๊ฐ’์ด๋‹ค. */
44
+ export type ViewMode = 'light' | 'high-contrast' | 'theme';
45
+ /** ๋ชจ๋“œ ๋ ˆ์ด๋ธ”. ใ€Œ๊ณ ๋Œ€๋น„ใ€ ๋Œ€์‹  KRDS ์šฉ์–ด์ธ ใ€Œ์„ ๋ช…ํ•œ ํ™”๋ฉดใ€์„ ์“ด๋‹ค. */
46
+ export declare const VIEW_MODES: ReadonlyArray<{
47
+ value: ViewMode;
48
+ label: string;
49
+ }>;
50
+ /** ํ™”๋ฉด ๋ชจ๋“œ๋ฅผ `<html>` ์— ๊ฑด๋‹ค. ํ‚ท ์„ ํƒ์ž๊ฐ€ ํ›„์† ์„ ํƒ์ž๋ผ ๋ฐ˜๋“œ์‹œ ๋ฃจํŠธ์— ๋ถ™์–ด์•ผ ํ•œ๋‹ค. */
51
+ export declare function applyViewMode(mode: ViewMode): void;
52
+ /** ๋ฐฐ์œจ ์ €์žฅ ํ‚ค. */
53
+ export declare const SCALE_STORAGE_KEY = "krds.scale";
54
+ /** ํ™”๋ฉด ๋ชจ๋“œ ์ €์žฅ ํ‚ค. */
55
+ export declare const VIEW_MODE_STORAGE_KEY = "krds.view-mode";
56
+ /** ์ €์žฅ๋œ ๋ฐฐ์œจ. ์—†๊ฑฐ๋‚˜ ๋ชป ์ฝ์œผ๋ฉด null. */
57
+ export declare function readStoredScale(): ResizeScale | null;
58
+ /** ์ €์žฅ๋œ ํ™”๋ฉด ๋ชจ๋“œ. ์—†๊ฑฐ๋‚˜ ๋ชป ์ฝ์œผ๋ฉด null. */
59
+ export declare function readStoredViewMode(): ViewMode | null;
60
+ /**
61
+ * ์ฒซ ๊ทธ๋ฆผ ์ „์— ์ €์žฅ๋œ ๋ฐฐ์œจยทํ™”๋ฉด ๋ชจ๋“œ๋ฅผ ๊ฑฐ๋Š” ์ธ๋ผ์ธ ์Šคํฌ๋ฆฝํŠธ. ์—†์œผ๋ฉด ์ฒซ ํ™”๋ฉด์ด ํ•œ ๋ฒˆ ๋ฒˆ์ฉ์ธ๋‹ค.
62
+ * `<head>` ์•ˆ, ์Šคํƒ€์ผ์‹œํŠธ ๋’ค์— ๋†“๋Š”๋‹ค.
63
+ *
64
+ * **`nonce` ๋ฅผ ๋ฐ˜๋“œ์‹œ ๋„˜๊ฒจ๋ผ** โ€” CSP ๊ฐ€ nonce ์—†๋Š” ์ธ๋ผ์ธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋ง‰๋Š”๋‹ค.
65
+ *
66
+ * @example
67
+ * const nonce = await requestNonce();
68
+ * <ViewSettingsScript nonce={nonce ?? undefined} />
69
+ */
70
+ export declare function ViewSettingsScript({ nonce }: {
71
+ nonce?: string;
72
+ }): import("react").JSX.Element;
73
+ /** ๋“œ๋กญ๋‹ค์šด ์ •๋ ฌ. ์ƒ๋žตํ•˜๋ฉด ๊ฐ€์šด๋ฐ(ํ‚ท ๊ธฐ๋ณธ). */
74
+ export type DropAlign = 'left' | 'right';
75
+ export type ResizeProps = Omit<ComponentPropsWithRef<'div'>, 'children' | 'onSelect'> & {
76
+ /** ๋ฒ„ํŠผ ๊ธ€์ž. ๊ธฐ๋ณธ ใ€Œํ™”๋ฉด ํฌ๊ธฐใ€. */
77
+ label?: string;
78
+ /** ์ดˆ๊ธฐํ™” ๋ฒ„ํŠผ ๊ธ€์ž. ๊ธฐ๋ณธ ใ€Œ์ดˆ๊ธฐํ™”ใ€. */
79
+ resetLabel?: string;
80
+ /** ๋“œ๋กญ๋‹ค์šด ์ •๋ ฌ. */
81
+ align?: DropAlign;
82
+ /** ์ €์žฅ๊ฐ’์ด ์—†์„ ๋•Œ์˜ ๋ฐฐ์œจ. ๊ธฐ๋ณธ `md`(100%). */
83
+ defaultScale?: ResizeScale;
84
+ /** localStorage ๊ธฐ์–ต. ๊ธฐ๋ณธ ์ผฌ. */
85
+ persist?: boolean;
86
+ /** ๋ฐฐ์œจ์ด ๋ฐ”๋€” ๋•Œ. ์„œ๋ฒ„์— ๋‚จ๊ธฐ๊ณ  ์‹ถ์„ ๋•Œ ์“ด๋‹ค. */
87
+ onScaleChange?: (scale: ResizeScale) => void;
88
+ };
89
+ /**
90
+ * ํ™”๋ฉด ํฌ๊ธฐ ์กฐ์ • โ€” ํ—ค๋” ์œ ํ‹ธ๋ฆฌํ‹ฐ ์ค„์— ๋†“๋Š”๋‹ค. 5๋‹จ(90~150%)์—์„œ ๊ณ ๋ฅธ๋‹ค.
91
+ * ์ €์žฅ๊ฐ’์€ ๋ถ™์€ ๋’ค์— ์ฝ๋Š”๋‹ค โ€” ๊ทธ ํ•œ ํ”„๋ ˆ์ž„์˜ ๋ฒˆ์ฉ์ž„์€ {@link ViewSettingsScript} ๊ฐ€ ์—†์•ค๋‹ค.
92
+ */
93
+ export declare function Resize({ label, resetLabel, align, defaultScale, persist, onScaleChange, className, ...rest }: ResizeProps): import("react").JSX.Element;
94
+ export type ViewModeSwitchProps = Omit<ComponentPropsWithRef<'div'>, 'children' | 'onSelect'> & {
95
+ /** ๋ฒ„ํŠผ ๊ธ€์ž. ๊ธฐ๋ณธ ใ€Œํ™”๋ฉด ๋ชจ๋“œใ€. */
96
+ label?: string;
97
+ /** ๋“œ๋กญ๋‹ค์šด ์ •๋ ฌ. */
98
+ align?: DropAlign;
99
+ /** ์ €์žฅ๊ฐ’์ด ์—†์„ ๋•Œ์˜ ๋ชจ๋“œ. ๊ธฐ๋ณธ `light`. */
100
+ defaultMode?: ViewMode;
101
+ /** localStorage ๊ธฐ์–ต. ๊ธฐ๋ณธ ์ผฌ. */
102
+ persist?: boolean;
103
+ /**
104
+ * ใ€Œ๊ธฐ๊ธฐ ์„ค์ • ๋”ฐ๋ฆ„ใ€์„ ์˜ต์…˜์— ๋„ฃ๋Š”๋‹ค. **๊ธฐ๋ณธ ๋”** โ€” ๋ณด์ถฉ ์ธต์ด ๊ทธ ๋ชจ๋“œ๋ฅผ ์žฌ์ •์˜ํ•˜์ง€ ์•Š์•„
105
+ * ํ‚ท ๋ถ€ํ’ˆ๋งŒ ์–ด๋‘์›Œ์ง€๊ณ  ์œ ํ‹ธ๋ฆฌํ‹ฐ๋กœ ๊ทธ๋ฆฐ ๋ถ€๋ถ„์€ ๋ฐ๊ฒŒ ๋‚จ๋Š”๋‹ค.
106
+ */
107
+ systemOption?: boolean;
108
+ /** ๋ชจ๋“œ๊ฐ€ ๋ฐ”๋€” ๋•Œ. */
109
+ onModeChange?: (mode: ViewMode) => void;
110
+ };
111
+ /**
112
+ * ์„ ๋ช…ํ•œ ํ™”๋ฉด ๋ชจ๋“œ ์ „ํ™˜ โ€” ํ‚ท์— ์ด๋ฆ„์ด ์—†๋Š” ์šฐ๋ฆฌ ๋ถ€ํ’ˆ์ด๋‹ค. ๊ป๋ฐ๊ธฐ์™€ ์•„์ด์ฝ˜์€ ํ‚ท ๊ฒƒ์„ ์“ด๋‹ค.
113
+ *
114
+ * **`<html data-krds-mode>` ๋ฅผ ๋ถ™์ด๋Š” ์œ ์ผํ•œ ๊ณณ์ด๋‹ค** โ€” ์ด๊ฒƒ ์—†์ด๋Š” ํ‚ท์˜ ๊ณ ๋Œ€๋น„ ๊ทœ์น™์ด
115
+ * ํ†ต์งธ๋กœ ์ฃฝ์€ ์ฝ”๋“œ๋กœ ๋‚จ๋Š”๋‹ค.
116
+ */
117
+ export declare function ViewModeSwitch({ label, align, defaultMode, persist, systemOption, onModeChange, className, ...rest }: ViewModeSwitchProps): import("react").JSX.Element;
118
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resize/index.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,342 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import {
4
+ useCallback,
5
+ useEffect,
6
+ useId,
7
+ useRef,
8
+ useState
9
+ } from "react";
10
+ import { cx } from "../lib/krds.js";
11
+ const RESIZE_SCALES = [
12
+ { value: "sm", label: "\uC791\uAC8C", percent: 90 },
13
+ { value: "md", label: "\uBCF4\uD1B5", percent: 100 },
14
+ { value: "lg", label: "\uC870\uAE08 \uD06C\uAC8C", percent: 110 },
15
+ { value: "xlg", label: "\uD06C\uAC8C", percent: 130 },
16
+ { value: "xxlg", label: "\uAC00\uC7A5 \uD06C\uAC8C", percent: 150 }
17
+ ];
18
+ const ROOT_FONT_BASE_PERCENT = 62.5;
19
+ const DEFAULT_SCALE = "md";
20
+ function scaleInfo(scale) {
21
+ return RESIZE_SCALES.find((s) => s.value === scale) ?? RESIZE_SCALES[1];
22
+ }
23
+ function rootFontSize(scale) {
24
+ return `${ROOT_FONT_BASE_PERCENT * scaleInfo(scale).percent / 100}%`;
25
+ }
26
+ function applyScale(scale) {
27
+ const root = document.documentElement;
28
+ root.style.fontSize = rootFontSize(scale);
29
+ root.dataset.krdsScale = scale;
30
+ document.body?.classList.toggle("krds-scaled-layout", scaleInfo(scale).percent > 100);
31
+ }
32
+ const VIEW_MODES = [
33
+ { value: "light", label: "\uAE30\uBCF8 \uD654\uBA74" },
34
+ { value: "high-contrast", label: "\uC120\uBA85\uD55C \uD654\uBA74" },
35
+ { value: "theme", label: "\uAE30\uAE30 \uC124\uC815 \uB530\uB984" }
36
+ ];
37
+ function applyViewMode(mode) {
38
+ const root = document.documentElement;
39
+ if (mode === "light") delete root.dataset.krdsMode;
40
+ else root.dataset.krdsMode = mode;
41
+ }
42
+ const SCALE_STORAGE_KEY = "krds.scale";
43
+ const VIEW_MODE_STORAGE_KEY = "krds.view-mode";
44
+ function readStored(key, allowed) {
45
+ try {
46
+ const v = window.localStorage.getItem(key);
47
+ return v && allowed.includes(v) ? v : null;
48
+ } catch {
49
+ return null;
50
+ }
51
+ }
52
+ function writeStored(key, value) {
53
+ try {
54
+ window.localStorage.setItem(key, value);
55
+ } catch {
56
+ }
57
+ }
58
+ function readStoredScale() {
59
+ return readStored(
60
+ SCALE_STORAGE_KEY,
61
+ RESIZE_SCALES.map((s) => s.value)
62
+ );
63
+ }
64
+ function readStoredViewMode() {
65
+ return readStored(
66
+ VIEW_MODE_STORAGE_KEY,
67
+ VIEW_MODES.map((m) => m.value)
68
+ );
69
+ }
70
+ const BOOT_SCRIPT = (() => {
71
+ const map = {};
72
+ for (const s of RESIZE_SCALES) map[s.value] = rootFontSize(s.value);
73
+ return `(function(){try{var d=document.documentElement,m=${JSON.stringify(map)},s=localStorage.getItem(${JSON.stringify(SCALE_STORAGE_KEY)});if(s&&m[s]){d.style.fontSize=m[s];d.dataset.krdsScale=s;}var v=localStorage.getItem(${JSON.stringify(VIEW_MODE_STORAGE_KEY)});if(v==='high-contrast'||v==='theme'){d.dataset.krdsMode=v;}}catch(e){}})();`;
74
+ })();
75
+ function ViewSettingsScript({ nonce }) {
76
+ return /* @__PURE__ */ jsx("script", { nonce, dangerouslySetInnerHTML: { __html: BOOT_SCRIPT } });
77
+ }
78
+ function DropdownShell({
79
+ wrapClass,
80
+ triggerLabel,
81
+ leadingIcon,
82
+ options,
83
+ value,
84
+ onSelect,
85
+ align,
86
+ footer,
87
+ className,
88
+ dataAdjust,
89
+ wrapProps
90
+ }) {
91
+ const [open, setOpen] = useState(false);
92
+ const wrapRef = useRef(null);
93
+ const triggerRef = useRef(null);
94
+ const menuRef = useRef(null);
95
+ const menuId = useId();
96
+ const close = useCallback((refocus = false) => {
97
+ setOpen(false);
98
+ if (refocus) triggerRef.current?.focus();
99
+ }, []);
100
+ useEffect(() => {
101
+ if (!open) return;
102
+ const onPointerDown = (e) => {
103
+ if (!wrapRef.current?.contains(e.target)) setOpen(false);
104
+ };
105
+ document.addEventListener("pointerdown", onPointerDown);
106
+ return () => document.removeEventListener("pointerdown", onPointerDown);
107
+ }, [open]);
108
+ const focusItem = (index) => {
109
+ const items = menuRef.current?.querySelectorAll(".item-link");
110
+ if (!items?.length) return;
111
+ const i = (index + items.length) % items.length;
112
+ items[i]?.focus();
113
+ };
114
+ const onTriggerKeyDown = (e) => {
115
+ if (e.key !== "ArrowDown" && e.key !== "ArrowUp") return;
116
+ e.preventDefault();
117
+ if (open) {
118
+ focusItem(e.key === "ArrowDown" ? 0 : options.length - 1);
119
+ return;
120
+ }
121
+ const at = options.findIndex((o) => o.value === value);
122
+ const next = e.key === "ArrowDown" ? at + 1 : at - 1;
123
+ if (next >= 0 && next < options.length) onSelect(options[next].value);
124
+ };
125
+ const onMenuKeyDown = (e) => {
126
+ const items = Array.from(
127
+ menuRef.current?.querySelectorAll(".item-link") ?? []
128
+ );
129
+ const at = items.indexOf(document.activeElement);
130
+ if (at < 0) return;
131
+ if (e.key === "ArrowDown") {
132
+ e.preventDefault();
133
+ focusItem(at + 1);
134
+ } else if (e.key === "ArrowUp") {
135
+ e.preventDefault();
136
+ focusItem(at - 1);
137
+ } else if (e.key === "Home") {
138
+ e.preventDefault();
139
+ focusItem(0);
140
+ } else if (e.key === "End") {
141
+ e.preventDefault();
142
+ focusItem(items.length - 1);
143
+ }
144
+ };
145
+ const onWrapKeyDown = (e) => {
146
+ if (e.key === "Escape" && open) {
147
+ e.stopPropagation();
148
+ close(true);
149
+ }
150
+ };
151
+ const onBlurCapture = (e) => {
152
+ const next = e.relatedTarget;
153
+ if (next && !e.currentTarget.contains(next)) setOpen(false);
154
+ };
155
+ const current = options.find((o) => o.value === value);
156
+ return /* @__PURE__ */ jsxs(
157
+ "div",
158
+ {
159
+ ...wrapProps,
160
+ ref: wrapRef,
161
+ className: cx("krds-drop-wrap", wrapClass, align && `drop-${align}`, className),
162
+ "data-adjust": dataAdjust,
163
+ onKeyDown: onWrapKeyDown,
164
+ onBlurCapture,
165
+ children: [
166
+ /* @__PURE__ */ jsxs(
167
+ "button",
168
+ {
169
+ ref: triggerRef,
170
+ type: "button",
171
+ className: "krds-btn small text drop-btn",
172
+ "aria-expanded": open,
173
+ "aria-controls": menuId,
174
+ onClick: () => setOpen((v) => !v),
175
+ onKeyDown: onTriggerKeyDown,
176
+ children: [
177
+ leadingIcon && /* @__PURE__ */ jsx("i", { className: `svg-icon ico-${leadingIcon}`, "aria-hidden": "true" }),
178
+ triggerLabel,
179
+ /* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
180
+ "\uD604\uC7AC ",
181
+ current?.label ?? ""
182
+ ] }),
183
+ /* @__PURE__ */ jsx("i", { className: "svg-icon ico-toggle", "aria-hidden": "true" })
184
+ ]
185
+ }
186
+ ),
187
+ /* @__PURE__ */ jsx(
188
+ "div",
189
+ {
190
+ ref: menuRef,
191
+ id: menuId,
192
+ className: "drop-menu",
193
+ style: open ? { display: "block" } : void 0,
194
+ onKeyDown: onMenuKeyDown,
195
+ children: /* @__PURE__ */ jsxs("div", { className: "drop-in", children: [
196
+ /* @__PURE__ */ jsx("ul", { className: "drop-list", children: options.map((option) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
197
+ "button",
198
+ {
199
+ type: "button",
200
+ className: cx(
201
+ "item-link",
202
+ option.itemClass,
203
+ option.value === value && "active"
204
+ ),
205
+ "data-adjust-scale": option.data,
206
+ "aria-current": option.value === value ? "true" : void 0,
207
+ onClick: () => {
208
+ onSelect(option.value);
209
+ close(true);
210
+ },
211
+ children: option.label
212
+ }
213
+ ) }, option.value)) }),
214
+ footer && /* @__PURE__ */ jsx("div", { className: "drop-bottom", onClick: () => close(true), children: footer })
215
+ ] })
216
+ }
217
+ )
218
+ ]
219
+ }
220
+ );
221
+ }
222
+ function Resize({
223
+ label = "\uD654\uBA74 \uD06C\uAE30",
224
+ resetLabel = "\uCD08\uAE30\uD654",
225
+ align,
226
+ defaultScale = DEFAULT_SCALE,
227
+ persist = true,
228
+ onScaleChange,
229
+ className,
230
+ ...rest
231
+ }) {
232
+ const [scale, setScale] = useState(defaultScale);
233
+ useEffect(() => {
234
+ const initial = persist && readStoredScale() || defaultScale;
235
+ setScale(initial);
236
+ applyScale(initial);
237
+ }, [persist, defaultScale]);
238
+ const select = useCallback(
239
+ (next) => {
240
+ setScale(next);
241
+ applyScale(next);
242
+ if (persist) writeStored(SCALE_STORAGE_KEY, next);
243
+ onScaleChange?.(next);
244
+ },
245
+ [persist, onScaleChange]
246
+ );
247
+ return /* @__PURE__ */ jsx(
248
+ DropdownShell,
249
+ {
250
+ wrapClass: "krds-resize",
251
+ dataAdjust: "scale",
252
+ triggerLabel: label,
253
+ options: RESIZE_SCALES.map((s) => ({
254
+ value: s.value,
255
+ label: s.label,
256
+ // ํ‚ท์ด ์ด ํด๋ž˜์Šค๋กœ ๋ชฉ๋ก ์•ž ๊ธ€์ž ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์•„์ด์ฝ˜ ํฌ๊ธฐ(2.2~3.0rem)๋ฅผ ๊ทธ๋ฆฐ๋‹ค.
257
+ itemClass: s.value,
258
+ data: s.value
259
+ })),
260
+ value: scale,
261
+ onSelect: select,
262
+ align,
263
+ footer: (
264
+ // ํ‚ท ์ƒ˜ํ”Œ ๊ทธ๋Œ€๋กœ `krds-btn medium text` + ico-reset. ์•„์ด์ฝ˜์ด ๊ธ€์ž ์•ž์— ์˜จ๋‹ค.
265
+ // ๋ชฉ๋ก์„ ๋‹ซ๋Š” ์ผ์€ ๊ป๋ฐ๊ธฐ(`.drop-bottom` ์˜ ํด๋ฆญ)๊ฐ€ ๋งก๋Š”๋‹ค.
266
+ /* @__PURE__ */ jsxs(
267
+ "button",
268
+ {
269
+ type: "button",
270
+ className: "krds-btn medium text",
271
+ "data-adjust-scale": DEFAULT_SCALE,
272
+ onClick: () => select(DEFAULT_SCALE),
273
+ children: [
274
+ /* @__PURE__ */ jsx("i", { className: "svg-icon ico-reset", "aria-hidden": "true" }),
275
+ " ",
276
+ resetLabel
277
+ ]
278
+ }
279
+ )
280
+ ),
281
+ className,
282
+ wrapProps: rest
283
+ }
284
+ );
285
+ }
286
+ function ViewModeSwitch({
287
+ label = "\uD654\uBA74 \uBAA8\uB4DC",
288
+ align,
289
+ defaultMode = "light",
290
+ persist = true,
291
+ systemOption = false,
292
+ onModeChange,
293
+ className,
294
+ ...rest
295
+ }) {
296
+ const [mode, setMode] = useState(defaultMode);
297
+ useEffect(() => {
298
+ const saved = persist && readStoredViewMode() || defaultMode;
299
+ const initial = saved === "theme" && !systemOption ? "light" : saved;
300
+ setMode(initial);
301
+ applyViewMode(initial);
302
+ }, [persist, defaultMode, systemOption]);
303
+ const select = useCallback(
304
+ (next) => {
305
+ setMode(next);
306
+ applyViewMode(next);
307
+ if (persist) writeStored(VIEW_MODE_STORAGE_KEY, next);
308
+ onModeChange?.(next);
309
+ },
310
+ [persist, onModeChange]
311
+ );
312
+ const options = VIEW_MODES.filter((m) => systemOption || m.value !== "theme");
313
+ return /* @__PURE__ */ jsx(
314
+ DropdownShell,
315
+ {
316
+ wrapClass: void 0,
317
+ triggerLabel: label,
318
+ leadingIcon: "view-mode",
319
+ options: options.map((m) => ({ value: m.value, label: m.label })),
320
+ value: mode,
321
+ onSelect: select,
322
+ align,
323
+ className,
324
+ wrapProps: rest
325
+ }
326
+ );
327
+ }
328
+ export {
329
+ RESIZE_SCALES,
330
+ Resize,
331
+ SCALE_STORAGE_KEY,
332
+ VIEW_MODES,
333
+ VIEW_MODE_STORAGE_KEY,
334
+ ViewModeSwitch,
335
+ ViewSettingsScript,
336
+ applyScale,
337
+ applyViewMode,
338
+ readStoredScale,
339
+ readStoredViewMode,
340
+ rootFontSize
341
+ };
342
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/resize/index.tsx"],"sourcesContent":["'use client';\n\nimport {\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n type ComponentPropsWithRef,\n type FocusEvent as ReactFocusEvent,\n type KeyboardEvent as ReactKeyboardEvent,\n type ReactNode,\n} from 'react';\nimport { cx } from '../lib/krds';\n\n/**\n * ํ™”๋ฉด ํฌ๊ธฐ ์กฐ์ • โ€” KRDS `krds-drop-wrap krds-resize`.\n * ์„ ๋ช…ํ•œ ํ™”๋ฉด ๋ชจ๋“œ ์ „ํ™˜({@link ViewModeSwitch}) โ€” ๊ฐ™์€ ๋“œ๋กญ๋‹ค์šด ๊ป๋ฐ๊ธฐ๋ฅผ ์“ฐ๋Š” ์šฐ๋ฆฌ ๋ถ€ํ’ˆ์ด๋‹ค.\n *\n * ํ—ค๋” ์œ ํ‹ธ๋ฆฌํ‹ฐ ์ค„์— ๋†“๋Š”๋‹ค. ๋ฐฐ์œจ์€ ๋ฌธ์„œ ๋ฃจํŠธ ๊ธ€์ž ํฌ๊ธฐ๋กœ ๊ฑธ๋ฆฌ๋ฏ€๋กœ ํ™”๋ฉด ์ „์ฒด๊ฐ€ ๋”ฐ๋ผ์˜จ๋‹ค.\n * ์ฒซ ํ™”๋ฉด์ด ๊ธฐ๋ณธ ๋ชจ๋“œ๋กœ ๋ฒˆ์ฉ์ด์ง€ ์•Š๊ฒŒ `<head>` ์— {@link ViewSettingsScript} ๋ฅผ ๋‘๊ณ  **nonce ๋ฅผ ๋„˜๊ธด๋‹ค**.\n * `ViewModeSwitch` ๋Š” `<html data-krds-mode>` ๋ฅผ ๋ถ™์ด๋Š” **์œ ์ผํ•œ ๊ณณ**์ด๋‹ค โ€”\n * ์ด๊ฒƒ ์—†์ด๋Š” ํ‚ท์˜ ๊ณ ๋Œ€๋น„ ๊ทœ์น™์ด ํ†ต์งธ๋กœ ์ฃฝ์€ ์ฝ”๋“œ๋กœ ๋‚จ๋Š”๋‹ค.\n *\n * @example\n * // app/layout.tsx <head>\n * <ViewSettingsScript nonce={nonce} />\n * // ํ—ค๋” ์œ ํ‹ธ๋ฆฌํ‹ฐ ์ค„\n * <HeaderUtility>\n * <Resize />\n * <ViewModeSwitch />\n * </HeaderUtility>\n *\n * ์ž์„ธํžˆ: docs/krds/09-๋ถ€ํ’ˆ-๋…ธํŠธ.md#ํฌ๊ธฐ์กฐ์ ˆ\n */\n\n/* โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * 1. ๋ฐฐ์œจ\n * โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */\n\n/** ํ‚ท์˜ 5๋‹จ. ํด๋ž˜์Šค ์ด๋ฆ„(`.item-link.sm` โ€ฆ)๊ณผ ๊ฐ’์ด ๊ฐ™์•„์•ผ ํ•œ๋‹ค. */\nexport type ResizeScale = 'sm' | 'md' | 'lg' | 'xlg' | 'xxlg';\n\n/** 5๋‹จ์˜ ๋ ˆ์ด๋ธ”๊ณผ ๋ฐฐ์œจ โ€” ์ž‘๊ฒŒ 90% ยท ๋ณดํ†ต 100% ยท ์กฐ๊ธˆ ํฌ๊ฒŒ 110% ยท ํฌ๊ฒŒ 130% ยท ๊ฐ€์žฅ ํฌ๊ฒŒ 150%. */\nexport const RESIZE_SCALES: ReadonlyArray<{\n value: ResizeScale;\n label: string;\n percent: number;\n}> = [\n { value: 'sm', label: '์ž‘๊ฒŒ', percent: 90 },\n { value: 'md', label: '๋ณดํ†ต', percent: 100 },\n { value: 'lg', label: '์กฐ๊ธˆ ํฌ๊ฒŒ', percent: 110 },\n { value: 'xlg', label: 'ํฌ๊ฒŒ', percent: 130 },\n { value: 'xxlg', label: '๊ฐ€์žฅ ํฌ๊ฒŒ', percent: 150 },\n];\n\n/** ํ‚ท ๊ธฐ๋ณธ ๋ฃจํŠธ ๊ธ€์ž ํฌ๊ธฐ. */\nconst ROOT_FONT_BASE_PERCENT = 62.5;\n\n/** ๊ธฐ๋ณธ ๋ฐฐ์œจ(ํ‚ท์˜ `.active` ๊ฐ€ ๋ถ™์–ด ์žˆ๋Š” ๋‹จ). */\nconst DEFAULT_SCALE: ResizeScale = 'md';\n\nfunction scaleInfo(scale: ResizeScale) {\n return RESIZE_SCALES.find((s) => s.value === scale) ?? RESIZE_SCALES[1];\n}\n\n/**\n * ๊ทธ ๋ฐฐ์œจ์—์„œ ๋ฌธ์„œ ๋ฃจํŠธ์— ๋„ฃ์„ ๊ธ€์ž ํฌ๊ธฐ. %(๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ณธ ๊ธ€์ž ํฌ๊ธฐ์˜ ๋น„์œจ)๋ผ\n * ์‚ฌ์šฉ์ž์˜ ๋ธŒ๋ผ์šฐ์ € ๊ธ€๊ผด ์„ค์ •์„ ๋ฎ์ง€ ์•Š๋Š”๋‹ค.\n *\n * @example\n * rootFontSize('lg') // '68.75%'\n */\nexport function rootFontSize(scale: ResizeScale): string {\n return `${(ROOT_FONT_BASE_PERCENT * scaleInfo(scale).percent) / 100}%`;\n}\n\n/**\n * ๋ฐฐ์œจ์„ ๋ฌธ์„œ์— ๊ฑด๋‹ค โ€” `<html>` ์ธ๋ผ์ธ ๊ธ€์ž ํฌ๊ธฐ ยท `data-krds-scale` ํ‘œ์‹œ ยท\n * ํ™•๋Œ€(100% ์ดˆ๊ณผ)์ผ ๋•Œ `krds-scaled-layout`(๋ชฉ์ฐจ์˜ ๊ณ ์ • ์œ„์น˜๋ฅผ ํ‘ผ๋‹ค).\n */\nexport function applyScale(scale: ResizeScale): void {\n const root = document.documentElement;\n root.style.fontSize = rootFontSize(scale);\n root.dataset.krdsScale = scale;\n document.body?.classList.toggle('krds-scaled-layout', scaleInfo(scale).percent > 100);\n}\n\n/* โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * 2. ์„ ๋ช…ํ•œ ํ™”๋ฉด ๋ชจ๋“œ\n * โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */\n\n/** ํ™”๋ฉด ๋ชจ๋“œ. `light` ๋Š” ์†์„ฑ์„ ๋–ผ๋Š” ๊ฒƒ์ด๊ณ , ๋‚˜๋จธ์ง€ ๋‘˜์€ `<html data-krds-mode>` ๊ฐ’์ด๋‹ค. */\nexport type ViewMode = 'light' | 'high-contrast' | 'theme';\n\n/** ๋ชจ๋“œ ๋ ˆ์ด๋ธ”. ใ€Œ๊ณ ๋Œ€๋น„ใ€ ๋Œ€์‹  KRDS ์šฉ์–ด์ธ ใ€Œ์„ ๋ช…ํ•œ ํ™”๋ฉดใ€์„ ์“ด๋‹ค. */\nexport const VIEW_MODES: ReadonlyArray<{ value: ViewMode; label: string }> = [\n { value: 'light', label: '๊ธฐ๋ณธ ํ™”๋ฉด' },\n { value: 'high-contrast', label: '์„ ๋ช…ํ•œ ํ™”๋ฉด' },\n { value: 'theme', label: '๊ธฐ๊ธฐ ์„ค์ • ๋”ฐ๋ฆ„' },\n];\n\n/** ํ™”๋ฉด ๋ชจ๋“œ๋ฅผ `<html>` ์— ๊ฑด๋‹ค. ํ‚ท ์„ ํƒ์ž๊ฐ€ ํ›„์† ์„ ํƒ์ž๋ผ ๋ฐ˜๋“œ์‹œ ๋ฃจํŠธ์— ๋ถ™์–ด์•ผ ํ•œ๋‹ค. */\nexport function applyViewMode(mode: ViewMode): void {\n const root = document.documentElement;\n if (mode === 'light') delete root.dataset.krdsMode;\n else root.dataset.krdsMode = mode;\n}\n\n/* โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * 3. ์ €์žฅ โ€” ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ง‰์•„๋„ ํ™”๋ฉด์€ ๋– ์•ผ ํ•œ๋‹ค\n * โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */\n\n/** ๋ฐฐ์œจ ์ €์žฅ ํ‚ค. */\nexport const SCALE_STORAGE_KEY = 'krds.scale';\n/** ํ™”๋ฉด ๋ชจ๋“œ ์ €์žฅ ํ‚ค. */\nexport const VIEW_MODE_STORAGE_KEY = 'krds.view-mode';\n\n/** ์‚ฌ์ƒํ™œ ๋ณดํ˜ธ ๋ชจ๋“œยท์ฟ ํ‚ค ์ฐจ๋‹จ์—์„œ๋Š” ์ ‘๊ทผ๋งŒ ํ•ด๋„ ์˜ˆ์™ธ๊ฐ€ ๋‚œ๋‹ค โ€” try/catch ๋กœ ๊ฐ์‹ผ๋‹ค. */\nfunction readStored<T extends string>(key: string, allowed: ReadonlyArray<T>): T | null {\n try {\n const v = window.localStorage.getItem(key);\n return v && (allowed as ReadonlyArray<string>).includes(v) ? (v as T) : null;\n } catch {\n return null;\n }\n}\n\nfunction writeStored(key: string, value: string): void {\n try {\n window.localStorage.setItem(key, value);\n } catch {\n /* ์ €์žฅ์ด ๋ง‰ํžŒ ๋ธŒ๋ผ์šฐ์ € โ€” ์ด๋ฒˆ ๋ฐฉ๋ฌธ์—๋งŒ ์ ์šฉ๋œ๋‹ค */\n }\n}\n\n/** ์ €์žฅ๋œ ๋ฐฐ์œจ. ์—†๊ฑฐ๋‚˜ ๋ชป ์ฝ์œผ๋ฉด null. */\nexport function readStoredScale(): ResizeScale | null {\n return readStored(\n SCALE_STORAGE_KEY,\n RESIZE_SCALES.map((s) => s.value),\n );\n}\n\n/** ์ €์žฅ๋œ ํ™”๋ฉด ๋ชจ๋“œ. ์—†๊ฑฐ๋‚˜ ๋ชป ์ฝ์œผ๋ฉด null. */\nexport function readStoredViewMode(): ViewMode | null {\n return readStored(\n VIEW_MODE_STORAGE_KEY,\n VIEW_MODES.map((m) => m.value),\n );\n}\n\n/** ์ฒซ ๊ทธ๋ฆผ ์ „์— ์ €์žฅ๊ฐ’์„ ๊ฑฐ๋Š” ์ธ๋ผ์ธ ์Šคํฌ๋ฆฝํŠธ ๋ณธ๋ฌธ. `RESIZE_SCALES` ์—์„œ ๋งŒ๋“ค์–ด ๋‚ธ๋‹ค. */\nconst BOOT_SCRIPT = ((): string => {\n const map: Record<string, string> = {};\n for (const s of RESIZE_SCALES) map[s.value] = rootFontSize(s.value);\n return (\n '(function(){try{var d=document.documentElement,' +\n `m=${JSON.stringify(map)},` +\n `s=localStorage.getItem(${JSON.stringify(SCALE_STORAGE_KEY)});` +\n 'if(s&&m[s]){d.style.fontSize=m[s];d.dataset.krdsScale=s;}' +\n `var v=localStorage.getItem(${JSON.stringify(VIEW_MODE_STORAGE_KEY)});` +\n \"if(v==='high-contrast'||v==='theme'){d.dataset.krdsMode=v;}\" +\n '}catch(e){}})();'\n );\n})();\n\n/**\n * ์ฒซ ๊ทธ๋ฆผ ์ „์— ์ €์žฅ๋œ ๋ฐฐ์œจยทํ™”๋ฉด ๋ชจ๋“œ๋ฅผ ๊ฑฐ๋Š” ์ธ๋ผ์ธ ์Šคํฌ๋ฆฝํŠธ. ์—†์œผ๋ฉด ์ฒซ ํ™”๋ฉด์ด ํ•œ ๋ฒˆ ๋ฒˆ์ฉ์ธ๋‹ค.\n * `<head>` ์•ˆ, ์Šคํƒ€์ผ์‹œํŠธ ๋’ค์— ๋†“๋Š”๋‹ค.\n *\n * **`nonce` ๋ฅผ ๋ฐ˜๋“œ์‹œ ๋„˜๊ฒจ๋ผ** โ€” CSP ๊ฐ€ nonce ์—†๋Š” ์ธ๋ผ์ธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋ง‰๋Š”๋‹ค.\n *\n * @example\n * const nonce = await requestNonce();\n * <ViewSettingsScript nonce={nonce ?? undefined} />\n */\nexport function ViewSettingsScript({ nonce }: { nonce?: string }) {\n return <script nonce={nonce} dangerouslySetInnerHTML={{ __html: BOOT_SCRIPT }} />;\n}\n\n/* โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * 4. ๋“œ๋กญ๋‹ค์šด ๊ป๋ฐ๊ธฐ โ€” ๋‘ ๋ถ€ํ’ˆ์ด ํ•จ๊ป˜ ์“ด๋‹ค\n * โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */\n\n/** ๋“œ๋กญ๋‹ค์šด ์ •๋ ฌ. ์ƒ๋žตํ•˜๋ฉด ๊ฐ€์šด๋ฐ(ํ‚ท ๊ธฐ๋ณธ). */\nexport type DropAlign = 'left' | 'right';\n\ntype DropOption<T extends string> = {\n value: T;\n label: string;\n /** ํ•ญ๋ชฉ์— ๋ง๋ถ™์ผ ํ‚ท ํด๋ž˜์Šค. ํ™”๋ฉด ํฌ๊ธฐ ์กฐ์ •์˜ `sm`~`xxlg` ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์•„์ด์ฝ˜์ด ์—ฌ๊ธฐ๋กœ ์˜จ๋‹ค. */\n itemClass?: string;\n /** ํ•ญ๋ชฉ์— ๋ถ™์ผ `data-adjust-scale` ๊ฐ’(ํ‚ท ์ƒ˜ํ”Œ์˜ ์†์žก์ด). */\n data?: string;\n};\n\ntype DropdownShellProps<T extends string> = {\n /** ๊ป๋ฐ๊ธฐ ์ข…๋ฅ˜ ํด๋ž˜์Šค. `krds-resize` ์ฒ˜๋Ÿผ ํ‚ท์— ์‹ค์žฌํ•˜๋Š” ๊ฒƒ๋งŒ ๋„ฃ๋Š”๋‹ค. */\n wrapClass?: string;\n /** ๋ฒ„ํŠผ ๊ธ€์ž(๊ตฌ์กฐ โ‘ ). */\n triggerLabel: string;\n /** ๋ฒ„ํŠผ ์•ž ์•„์ด์ฝ˜ ์ด๋ฆ„(`ico-` ๋บ€ ๊ฒƒ). ์—†์œผ๋ฉด ๊ธ€์ž๋งŒ. */\n leadingIcon?: string;\n options: ReadonlyArray<DropOption<T>>;\n value: T;\n onSelect: (value: T) => void;\n align?: DropAlign;\n /**\n * `.drop-bottom` ์ž๋ฆฌ. ์—ฌ๊ธฐ์„œ ์ผ์–ด๋‚œ ํด๋ฆญ์€ **๋ชฉ๋ก์„ ๋‹ซ๊ณ  ๋ฒ„ํŠผ์œผ๋กœ ์ดˆ์ ์„ ๋Œ๋ฆฐ๋‹ค**\n * โ€” ์ดˆ๊ธฐํ™”์ฒ˜๋Ÿผ ๊ฐ’์„ ๋ฐ”๊พธ๋Š” ๋™์ž‘์ด ๋“ค์–ด์˜ค๋Š” ์ž๋ฆฌ๋ผ ์˜ต์…˜์„ ๊ณ ๋ฅธ ๊ฒƒ๊ณผ ๊ฐ™์ด ๋‹ค๋ฃฌ๋‹ค.\n */\n footer?: ReactNode;\n className?: string;\n /** ๊ฐ์‹ธ๊ฐœ์— ๋ถ™์ผ `data-adjust` ๊ฐ’(ํ‚ท ์ƒ˜ํ”Œ์˜ ์†์žก์ด). */\n dataAdjust?: string;\n wrapProps: Omit<ComponentPropsWithRef<'div'>, 'children'>;\n};\n\n/**\n * ๋“œ๋กญ๋‹ค์šด ๊ป๋ฐ๊ธฐ. ์ƒํ˜ธ์ž‘์šฉ์€ 10_02 ์›๋ฌธ ๊ทธ๋Œ€๋กœ โ€” Esc ๋Š” ์ ‘๊ณ  ๋ฒ„ํŠผ์œผ๋กœ ์ดˆ์  ๋ณต๊ท€,\n * ์ ‘ํžŒ ์ƒํƒœ์˜ โ†‘โ†“ ๋Š” **์„ ํƒ๊ฐ’ ์ž์ฒด๋ฅผ** ์˜ฎ๊ธฐ๊ณ , ๋ชฉ๋ก ์•ˆ์—์„œ๋Š” ์ดˆ์ ๋งŒ ์˜ฎ๊ธด๋‹ค.\n * `role=\"menu\"` ๋ฅผ ์“ฐ์ง€ ์•Š๋Š”๋‹ค โ€” ๊ฐ€์ด๋“œ๊ฐ€ Tab ์œผ๋กœ ํ•ญ๋ชฉ์— ๋‹ฟ์„ ๊ฒƒ์„ ์š”๊ตฌํ•œ๋‹ค.\n */\nfunction DropdownShell<T extends string>({\n wrapClass,\n triggerLabel,\n leadingIcon,\n options,\n value,\n onSelect,\n align,\n footer,\n className,\n dataAdjust,\n wrapProps,\n}: DropdownShellProps<T>) {\n const [open, setOpen] = useState(false);\n const wrapRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n const menuId = useId();\n\n const close = useCallback((refocus = false) => {\n setOpen(false);\n if (refocus) triggerRef.current?.focus();\n }, []);\n\n // ๋ฐ”๊นฅ์„ ๋ˆ„๋ฅด๋ฉด ์ ‘๋Š”๋‹ค(๊ฐ€์ด๋“œ๋ผ์ธ: ใ€Œ๋ ˆ์ด๋ธ”, ์ปจํ…Œ์ด๋„ˆ, ์˜ต์…˜ ๋ชฉ๋ก์ด ์•„๋‹Œ ์˜์—ญ์„ Click ํ•˜๋ฉด ์ถ•์†Œใ€).\n useEffect(() => {\n if (!open) return;\n const onPointerDown = (e: PointerEvent) => {\n if (!wrapRef.current?.contains(e.target as Node)) setOpen(false);\n };\n document.addEventListener('pointerdown', onPointerDown);\n return () => document.removeEventListener('pointerdown', onPointerDown);\n }, [open]);\n\n /** ๋ชฉ๋ก ์•ˆ n ๋ฒˆ์งธ ํ•ญ๋ชฉ์œผ๋กœ ์ดˆ์ ์„ ์˜ฎ๊ธด๋‹ค. */\n const focusItem = (index: number) => {\n const items = menuRef.current?.querySelectorAll<HTMLButtonElement>('.item-link');\n if (!items?.length) return;\n const i = (index + items.length) % items.length;\n items[i]?.focus();\n };\n\n const onTriggerKeyDown = (e: ReactKeyboardEvent<HTMLButtonElement>) => {\n if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp') return;\n e.preventDefault();\n if (open) {\n // ํŽผ์ณ์ ธ ์žˆ์œผ๋ฉด ๋ชฉ๋ก์œผ๋กœ ๋“ค์–ด๊ฐ„๋‹ค.\n focusItem(e.key === 'ArrowDown' ? 0 : options.length - 1);\n return;\n }\n // ์ ‘ํ˜€ ์žˆ์œผ๋ฉด **์„ ํƒ๊ฐ’ ์ž์ฒด๊ฐ€** ์ด์ „/๋‹ค์Œ์œผ๋กœ ๋ฐ”๋€๋‹ค(๊ฐ€์ด๋“œ๋ผ์ธ ์›๋ฌธ).\n const at = options.findIndex((o) => o.value === value);\n const next = e.key === 'ArrowDown' ? at + 1 : at - 1;\n if (next >= 0 && next < options.length) onSelect(options[next].value);\n };\n\n const onMenuKeyDown = (e: ReactKeyboardEvent<HTMLDivElement>) => {\n const items = Array.from(\n menuRef.current?.querySelectorAll<HTMLButtonElement>('.item-link') ?? [],\n );\n const at = items.indexOf(document.activeElement as HTMLButtonElement);\n if (at < 0) return;\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n focusItem(at + 1);\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n focusItem(at - 1);\n } else if (e.key === 'Home') {\n e.preventDefault();\n focusItem(0);\n } else if (e.key === 'End') {\n e.preventDefault();\n focusItem(items.length - 1);\n }\n };\n\n // Esc ๋Š” ๊ฐ์‹ธ๊ฐœ์—์„œ ํ•œ ๋ฒˆ์— ๋ฐ›๋Š”๋‹ค โ€” ๋ฒ„ํŠผ์— ์žˆ๋“  ํ•ญ๋ชฉ์— ์žˆ๋“  ์ ‘๊ณ  ๋ฒ„ํŠผ์œผ๋กœ ๋Œ์•„๊ฐ„๋‹ค.\n const onWrapKeyDown = (e: ReactKeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Escape' && open) {\n e.stopPropagation();\n close(true);\n }\n };\n\n // Tab ์œผ๋กœ ๊ป๋ฐ๊ธฐ ๋ฐ–์œผ๋กœ ๋‚˜๊ฐ€๋ฉด ์ ‘๋Š”๋‹ค. relatedTarget ์ด ์—†์œผ๋ฉด(๋ธŒ๋ผ์šฐ์ € UI ๋กœ ์ด๋™ ๋“ฑ) ๊ทธ๋Œ€๋กœ ๋‘”๋‹ค.\n const onBlurCapture = (e: ReactFocusEvent<HTMLDivElement>) => {\n const next = e.relatedTarget as Node | null;\n if (next && !e.currentTarget.contains(next)) setOpen(false);\n };\n\n const current = options.find((o) => o.value === value);\n\n return (\n <div\n // ๋ฐ–์—์„œ ์˜จ props ๋ฅผ ๋จผ์ € ํŽธ๋‹ค โ€” ์•„๋ž˜ ๋„ท์€ ๋ถ€ํ’ˆ์ด ๋„๋Š” ๋ฐ ๊ผญ ํ•„์š”ํ•œ ๋ฐฐ์„ ์ด๋ผ ๋ฎ์ด๋ฉด ์•ˆ ๋œ๋‹ค.\n {...wrapProps}\n ref={wrapRef}\n className={cx('krds-drop-wrap', wrapClass, align && `drop-${align}`, className)}\n data-adjust={dataAdjust}\n onKeyDown={onWrapKeyDown}\n onBlurCapture={onBlurCapture}\n >\n {/* ํ‚ท์€ ์•ž๋’ค๋กœ ์•„์ด์ฝ˜ ๋‘˜์„ ๋‘๋Š”๋ฐ `Button` ์€ ํ•˜๋‚˜๋งŒ ๋ฐ›์•„ ์—ฌ๊ธฐ์„œ๋Š” ๋งˆํฌ์—…์„ ๊ทธ๋Œ€๋กœ ์“ด๋‹ค. */}\n <button\n ref={triggerRef}\n type=\"button\"\n className=\"krds-btn small text drop-btn\"\n aria-expanded={open}\n aria-controls={menuId}\n onClick={() => setOpen((v) => !v)}\n onKeyDown={onTriggerKeyDown}\n >\n {leadingIcon && <i className={`svg-icon ico-${leadingIcon}`} aria-hidden=\"true\" />}\n {triggerLabel}\n {/* ๊ตฌ์กฐ โ‘ข ใ€Œ์„ ํƒ๊ฐ’ใ€ โ€” ํ‚ท ์ƒ˜ํ”Œ์€ ๋ชฉ๋ก์˜ .active ๋กœ๋งŒ ๋ณด์—ฌ ์ค€๋‹ค. ์Šคํฌ๋ฆฐ๋ฆฌ๋”์—๋„ ์•Œ๋ฆฐ๋‹ค. */}\n <span className=\"sr-only\">ํ˜„์žฌ {current?.label ?? ''}</span>\n <i className=\"svg-icon ico-toggle\" aria-hidden=\"true\" />\n </button>\n\n {/* ํ‚ท์— ์—ฌ๋Š” ํด๋ž˜์Šค๊ฐ€ ์—†์–ด ์ธ๋ผ์ธ display ๋กœ ์—ฐ๋‹ค. ์ ‘ํžŒ ๋™์•ˆ์€ ์Šคํฌ๋ฆฐ๋ฆฌ๋”๋„ ์ฝ์ง€ ์•Š๋Š”๋‹ค. */}\n <div\n ref={menuRef}\n id={menuId}\n className=\"drop-menu\"\n style={open ? { display: 'block' } : undefined}\n onKeyDown={onMenuKeyDown}\n >\n <div className=\"drop-in\">\n <ul className=\"drop-list\">\n {options.map((option) => (\n <li key={option.value}>\n <button\n type=\"button\"\n className={cx(\n 'item-link',\n option.itemClass,\n option.value === value && 'active',\n )}\n data-adjust-scale={option.data}\n // ๊ณ ๋ฅธ ๊ฐ’ ํ‘œ์‹œ. ๋ชฉ๋ก์ด role=listbox ๊ฐ€ ์•„๋‹ˆ๋ฏ€๋กœ aria-selected ๊ฐ€ ์•„๋‹ˆ๋ผ aria-current ๋‹ค.\n aria-current={option.value === value ? 'true' : undefined}\n onClick={() => {\n onSelect(option.value);\n close(true);\n }}\n >\n {option.label}\n </button>\n </li>\n ))}\n </ul>\n {footer && (\n <div className=\"drop-bottom\" onClick={() => close(true)}>\n {footer}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n\n/* โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n * 5. ๋ถ€ํ’ˆ\n * โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */\n\nexport type ResizeProps = Omit<ComponentPropsWithRef<'div'>, 'children' | 'onSelect'> & {\n /** ๋ฒ„ํŠผ ๊ธ€์ž. ๊ธฐ๋ณธ ใ€Œํ™”๋ฉด ํฌ๊ธฐใ€. */\n label?: string;\n /** ์ดˆ๊ธฐํ™” ๋ฒ„ํŠผ ๊ธ€์ž. ๊ธฐ๋ณธ ใ€Œ์ดˆ๊ธฐํ™”ใ€. */\n resetLabel?: string;\n /** ๋“œ๋กญ๋‹ค์šด ์ •๋ ฌ. */\n align?: DropAlign;\n /** ์ €์žฅ๊ฐ’์ด ์—†์„ ๋•Œ์˜ ๋ฐฐ์œจ. ๊ธฐ๋ณธ `md`(100%). */\n defaultScale?: ResizeScale;\n /** localStorage ๊ธฐ์–ต. ๊ธฐ๋ณธ ์ผฌ. */\n persist?: boolean;\n /** ๋ฐฐ์œจ์ด ๋ฐ”๋€” ๋•Œ. ์„œ๋ฒ„์— ๋‚จ๊ธฐ๊ณ  ์‹ถ์„ ๋•Œ ์“ด๋‹ค. */\n onScaleChange?: (scale: ResizeScale) => void;\n};\n\n/**\n * ํ™”๋ฉด ํฌ๊ธฐ ์กฐ์ • โ€” ํ—ค๋” ์œ ํ‹ธ๋ฆฌํ‹ฐ ์ค„์— ๋†“๋Š”๋‹ค. 5๋‹จ(90~150%)์—์„œ ๊ณ ๋ฅธ๋‹ค.\n * ์ €์žฅ๊ฐ’์€ ๋ถ™์€ ๋’ค์— ์ฝ๋Š”๋‹ค โ€” ๊ทธ ํ•œ ํ”„๋ ˆ์ž„์˜ ๋ฒˆ์ฉ์ž„์€ {@link ViewSettingsScript} ๊ฐ€ ์—†์•ค๋‹ค.\n */\nexport function Resize({\n label = 'ํ™”๋ฉด ํฌ๊ธฐ',\n resetLabel = '์ดˆ๊ธฐํ™”',\n align,\n defaultScale = DEFAULT_SCALE,\n persist = true,\n onScaleChange,\n className,\n ...rest\n}: ResizeProps) {\n const [scale, setScale] = useState<ResizeScale>(defaultScale);\n\n useEffect(() => {\n const initial = (persist && readStoredScale()) || defaultScale;\n setScale(initial);\n applyScale(initial);\n }, [persist, defaultScale]);\n\n const select = useCallback(\n (next: ResizeScale) => {\n setScale(next);\n applyScale(next);\n if (persist) writeStored(SCALE_STORAGE_KEY, next);\n onScaleChange?.(next);\n },\n [persist, onScaleChange],\n );\n\n return (\n <DropdownShell\n wrapClass=\"krds-resize\"\n dataAdjust=\"scale\"\n triggerLabel={label}\n options={RESIZE_SCALES.map((s) => ({\n value: s.value,\n label: s.label,\n // ํ‚ท์ด ์ด ํด๋ž˜์Šค๋กœ ๋ชฉ๋ก ์•ž ๊ธ€์ž ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์•„์ด์ฝ˜ ํฌ๊ธฐ(2.2~3.0rem)๋ฅผ ๊ทธ๋ฆฐ๋‹ค.\n itemClass: s.value,\n data: s.value,\n }))}\n value={scale}\n onSelect={select}\n align={align}\n footer={\n // ํ‚ท ์ƒ˜ํ”Œ ๊ทธ๋Œ€๋กœ `krds-btn medium text` + ico-reset. ์•„์ด์ฝ˜์ด ๊ธ€์ž ์•ž์— ์˜จ๋‹ค.\n // ๋ชฉ๋ก์„ ๋‹ซ๋Š” ์ผ์€ ๊ป๋ฐ๊ธฐ(`.drop-bottom` ์˜ ํด๋ฆญ)๊ฐ€ ๋งก๋Š”๋‹ค.\n <button\n type=\"button\"\n className=\"krds-btn medium text\"\n data-adjust-scale={DEFAULT_SCALE}\n onClick={() => select(DEFAULT_SCALE)}\n >\n <i className=\"svg-icon ico-reset\" aria-hidden=\"true\" /> {resetLabel}\n </button>\n }\n className={className}\n wrapProps={rest}\n />\n );\n}\n\nexport type ViewModeSwitchProps = Omit<ComponentPropsWithRef<'div'>, 'children' | 'onSelect'> & {\n /** ๋ฒ„ํŠผ ๊ธ€์ž. ๊ธฐ๋ณธ ใ€Œํ™”๋ฉด ๋ชจ๋“œใ€. */\n label?: string;\n /** ๋“œ๋กญ๋‹ค์šด ์ •๋ ฌ. */\n align?: DropAlign;\n /** ์ €์žฅ๊ฐ’์ด ์—†์„ ๋•Œ์˜ ๋ชจ๋“œ. ๊ธฐ๋ณธ `light`. */\n defaultMode?: ViewMode;\n /** localStorage ๊ธฐ์–ต. ๊ธฐ๋ณธ ์ผฌ. */\n persist?: boolean;\n /**\n * ใ€Œ๊ธฐ๊ธฐ ์„ค์ • ๋”ฐ๋ฆ„ใ€์„ ์˜ต์…˜์— ๋„ฃ๋Š”๋‹ค. **๊ธฐ๋ณธ ๋”** โ€” ๋ณด์ถฉ ์ธต์ด ๊ทธ ๋ชจ๋“œ๋ฅผ ์žฌ์ •์˜ํ•˜์ง€ ์•Š์•„\n * ํ‚ท ๋ถ€ํ’ˆ๋งŒ ์–ด๋‘์›Œ์ง€๊ณ  ์œ ํ‹ธ๋ฆฌํ‹ฐ๋กœ ๊ทธ๋ฆฐ ๋ถ€๋ถ„์€ ๋ฐ๊ฒŒ ๋‚จ๋Š”๋‹ค.\n */\n systemOption?: boolean;\n /** ๋ชจ๋“œ๊ฐ€ ๋ฐ”๋€” ๋•Œ. */\n onModeChange?: (mode: ViewMode) => void;\n};\n\n/**\n * ์„ ๋ช…ํ•œ ํ™”๋ฉด ๋ชจ๋“œ ์ „ํ™˜ โ€” ํ‚ท์— ์ด๋ฆ„์ด ์—†๋Š” ์šฐ๋ฆฌ ๋ถ€ํ’ˆ์ด๋‹ค. ๊ป๋ฐ๊ธฐ์™€ ์•„์ด์ฝ˜์€ ํ‚ท ๊ฒƒ์„ ์“ด๋‹ค.\n *\n * **`<html data-krds-mode>` ๋ฅผ ๋ถ™์ด๋Š” ์œ ์ผํ•œ ๊ณณ์ด๋‹ค** โ€” ์ด๊ฒƒ ์—†์ด๋Š” ํ‚ท์˜ ๊ณ ๋Œ€๋น„ ๊ทœ์น™์ด\n * ํ†ต์งธ๋กœ ์ฃฝ์€ ์ฝ”๋“œ๋กœ ๋‚จ๋Š”๋‹ค.\n */\nexport function ViewModeSwitch({\n label = 'ํ™”๋ฉด ๋ชจ๋“œ',\n align,\n defaultMode = 'light',\n persist = true,\n systemOption = false,\n onModeChange,\n className,\n ...rest\n}: ViewModeSwitchProps) {\n const [mode, setMode] = useState<ViewMode>(defaultMode);\n\n useEffect(() => {\n const saved = (persist && readStoredViewMode()) || defaultMode;\n // ๋ชฉ๋ก์—์„œ ๋บ€ ๊ฐ’์ด ์ €์žฅ๋ผ ์žˆ์œผ๋ฉด ๊ธฐ๋ณธ ํ™”๋ฉด์œผ๋กœ ๋˜๋Œ๋ฆฐ๋‹ค โ€” ๊ณ ๋ฅผ ์ˆ˜๋„ ๋Œ ์ˆ˜๋„ ์—†๋Š” ์ƒํƒœ๋ฅผ ๋ง‰๋Š”๋‹ค.\n const initial: ViewMode = saved === 'theme' && !systemOption ? 'light' : saved;\n setMode(initial);\n applyViewMode(initial);\n }, [persist, defaultMode, systemOption]);\n\n const select = useCallback(\n (next: ViewMode) => {\n setMode(next);\n applyViewMode(next);\n if (persist) writeStored(VIEW_MODE_STORAGE_KEY, next);\n onModeChange?.(next);\n },\n [persist, onModeChange],\n );\n\n const options = VIEW_MODES.filter((m) => systemOption || m.value !== 'theme');\n\n return (\n <DropdownShell\n wrapClass={undefined}\n triggerLabel={label}\n leadingIcon=\"view-mode\"\n options={options.map((m) => ({ value: m.value, label: m.label }))}\n value={mode}\n onSelect={select}\n align={align}\n className={className}\n wrapProps={rest}\n />\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,40 @@
1
+ import type { ComponentPropsWithRef, ReactNode } from 'react';
2
+ /**
3
+ * ์Šคํฌ๋กค ์˜์—ญ โ€” KRDS ์— ์—†๋‹ค. ํ‚ท ์Šคํฌ๋กค ๋ง‰๋Œ€ ๋ชจ์–‘์„ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋กœ ์˜ฎ๊ธด ๋ณด์ถฉ ๋ถ€ํ’ˆ์ด๋‹ค.
4
+ *
5
+ * ๋„˜์น˜๋Š” ๋‚ด์šฉ์„ ๊ฐ€๋‘ฌ ๊ตด๋ฆฐ๋‹ค. **์ดˆ์ ์„ ๋ฐ›์•„ ํ‚ค๋ณด๋“œ๋กœ๋„ ๊ตด๋Ÿฌ๊ฐ„๋‹ค** โ€” ๊ทธ๊ฒƒ์ด ์ด ๋ถ€ํ’ˆ์˜ ์กด์žฌ ์ด์œ ๋‹ค.
6
+ * `role="region"` ์ด๋ผ ์ด๋ฆ„(`label` ๋˜๋Š” `labelledBy`)์ด ํ•„์ˆ˜์ด๊ณ , ๋žœ๋“œ๋งˆํฌ๊ฐ€ ๋ชฉ๋ก์— ์Œ“์ด๋ฏ€๋กœ
7
+ * ์ด๋ฆ„์„ ๋ถ™์ผ ๋งŒํผ ๋œป์ด ์žˆ๋Š” ์นธ์—๋งŒ ์“ด๋‹ค. ๋‹จ์ˆœํžˆ ๋„˜์น˜๋Š” ํ‘œ๋Š” `ui/table` ์˜ ๊ฐ์‹ธ๊ฐœ๋‹ค.
8
+ * **๋†’์ด(ํญ)๋ฅผ ์ œํ•œํ•˜์ง€ ์•Š์œผ๋ฉด ์•„๋ฌด๊ฒƒ๋„ ์Šคํฌ๋กค๋˜์ง€ ์•Š๋Š”๋‹ค** โ€” `className="max-h-80"` ์ฒ˜๋Ÿผ ์ค€๋‹ค.
9
+ *
10
+ * @example
11
+ * <ScrollArea label="์•ฝ๊ด€ ์ „๋ฌธ" className="max-h-80 rounded-lg border border-solid border-line p-4">
12
+ * {terms}
13
+ * </ScrollArea>
14
+ *
15
+ * ์ž์„ธํžˆ: docs/krds/09-๋ถ€ํ’ˆ-๋…ธํŠธ.md#์Šคํฌ๋กค์˜์—ญ
16
+ */
17
+ /** ๊ตด๋ฆด ๋ฐฉํ–ฅ. ๊ธฐ๋ณธ์€ ์„ธ๋กœ. */
18
+ export type ScrollAreaAxis = 'vertical' | 'horizontal' | 'both';
19
+ type BaseProps = {
20
+ /** ๊ตด๋ฆด ๋ฐฉํ–ฅ. ๊ธฐ๋ณธ ์„ธ๋กœ. */
21
+ axis?: ScrollAreaAxis;
22
+ /** ๋์— ๋‹ฟ์•˜์„ ๋•Œ ๋ฐ”๊นฅ๊นŒ์ง€ ๋”ฐ๋ผ ๊ตด๋Ÿฌ๊ฐ€๋Š” ๊ฒƒ์„ ๋ง‰๋Š”๋‹ค. ๋ชจ๋‹ฌยท์„œ๋ž์ฒ˜๋Ÿผ ๊ฒน์ณ ๋œจ๋Š” ์นธ์— ์ผ ๋‹ค. */
23
+ containScroll?: boolean;
24
+ /** ์นธ์— ๋ถ™์ผ ํด๋ž˜์Šค. **์—ฌ๊ธฐ์„œ ๋†’์ด(ํญ)๋ฅผ ์ œํ•œํ•ด์•ผ ์Šคํฌ๋กค์ด ์ƒ๊ธด๋‹ค.** */
25
+ className?: string;
26
+ /** ๊ตด๋ฆด ๋‚ด์šฉ. */
27
+ children?: ReactNode;
28
+ };
29
+ /** ์ด๋ฆ„์€ ๋ฐ˜๋“œ์‹œ ํ•˜๋‚˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค โ€” ๋‘˜ ๋‹ค ์ฃผ์ง€๋„ ๋‘˜ ๋‹ค ๋นผ์ง€๋„ ๋ชปํ•˜๊ฒŒ ํƒ€์ž…์œผ๋กœ ๋ง‰๋Š”๋‹ค. */
30
+ type NameProps = {
31
+ label: string;
32
+ labelledBy?: never;
33
+ } | {
34
+ label?: never;
35
+ labelledBy: string;
36
+ };
37
+ export type ScrollAreaProps = Omit<ComponentPropsWithRef<'div'>, 'aria-label' | 'aria-labelledby' | 'children'> & BaseProps & NameProps;
38
+ export declare function ScrollArea(props: ScrollAreaProps): import("react").JSX.Element;
39
+ export {};
40
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scroll-area/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAG9D;;;;;;;;;;;;;;GAcG;AAEH,qBAAqB;AACrB,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC;AAEhE,KAAK,SAAS,GAAG;IACf,oBAAoB;IACpB,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,yDAAyD;IACzD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa;IACb,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB,CAAC;AAEF,wDAAwD;AACxD,KAAK,SAAS,GACV;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,KAAK,CAAA;CAAE,GACrC;IAAE,KAAK,CAAC,EAAE,KAAK,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1C,MAAM,MAAM,eAAe,GAAG,IAAI,CAChC,qBAAqB,CAAC,KAAK,CAAC,EAC5B,YAAY,GAAG,iBAAiB,GAAG,UAAU,CAC9C,GACC,SAAS,GACT,SAAS,CAAC;AAmBZ,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,+BAiChD"}
@@ -0,0 +1,52 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { cx } from "../lib/krds.js";
3
+ const OVERFLOW = {
4
+ vertical: "overflow-y-auto overflow-x-hidden",
5
+ horizontal: "overflow-x-auto overflow-y-hidden",
6
+ both: "overflow-auto"
7
+ };
8
+ const SCROLLBAR = cx(
9
+ // ํ‘œ์ค€ ์†์„ฑ โ€” ํŒŒ์ด์–ดํญ์Šค์™€ ํฌ๋กฌ 121+ ๊ฐ€ ๋ณธ๋‹ค.
10
+ "[scrollbar-width:thin]",
11
+ "[scrollbar-color:var(--color-line)_var(--color-surface-subtler)]",
12
+ // ์›นํ‚ท ์˜์‚ฌ์š”์†Œ โ€” ํ‚ท๊ณผ ๊ฐ™์€ 8px ๋ง‰๋Œ€.
13
+ "[&::-webkit-scrollbar]:h-2 [&::-webkit-scrollbar]:w-2",
14
+ "[&::-webkit-scrollbar-track]:bg-surface-subtler",
15
+ "[&::-webkit-scrollbar-thumb]:rounded-lg [&::-webkit-scrollbar-thumb]:bg-line"
16
+ );
17
+ function ScrollArea(props) {
18
+ const {
19
+ axis = "vertical",
20
+ containScroll,
21
+ label,
22
+ labelledBy,
23
+ className,
24
+ children,
25
+ // ๊ธฐ๋ณธ 0. ์Šคํฌ๋กค ์นธ์€ ์ดˆ์ ์„ ๋ฐ›์•„์•ผ โ†‘โ†“ยทPageUp/PageDownยทSpace ๋กœ ๊ตด๋Ÿฌ๊ฐ„๋‹ค(๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ฒ˜๋ฆฌํ•œ๋‹ค).
26
+ tabIndex = 0,
27
+ ...rest
28
+ } = props;
29
+ return /* @__PURE__ */ jsx(
30
+ "div",
31
+ {
32
+ role: "region",
33
+ "aria-label": label,
34
+ "aria-labelledby": labelledBy,
35
+ tabIndex,
36
+ className: cx(
37
+ OVERFLOW[axis],
38
+ // flex/grid ์ž์‹์ผ ๋•Œ ๋‚ด์šฉ๋งŒํผ ๋Š˜์–ด๋‚˜ ์Šคํฌ๋กค์ด ์•ˆ ์ƒ๊ธฐ๋Š” ๊ฒƒ์„ ๋ง‰๋Š”๋‹ค.
39
+ "min-h-0 min-w-0",
40
+ containScroll && "overscroll-contain",
41
+ SCROLLBAR,
42
+ className
43
+ ),
44
+ ...rest,
45
+ children
46
+ }
47
+ );
48
+ }
49
+ export {
50
+ ScrollArea
51
+ };
52
+ //# sourceMappingURL=index.js.map