@k8ordo/ui 1.0.0 → 2.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 (651) hide show
  1. package/README.md +206 -171
  2. package/dist/_virtual/_rolldown/runtime.mjs +13 -0
  3. package/dist/components/_internal/focus-ring.css +37 -0
  4. package/dist/components/_internal/focus-ring.module.mjs +9 -0
  5. package/dist/components/_internal/form-value.d.mts +33 -0
  6. package/dist/components/_internal/form-value.mjs +91 -0
  7. package/dist/components/_internal/high-contrast.css +18 -0
  8. package/dist/components/_internal/high-contrast.module.mjs +5 -0
  9. package/dist/components/_internal/ignore-changes.d.mts +20 -0
  10. package/dist/components/_internal/ignore-changes.mjs +37 -0
  11. package/dist/components/_internal/nav-link.css +78 -0
  12. package/dist/components/_internal/nav-link.d.mts +5 -0
  13. package/dist/components/_internal/nav-link.mjs +8 -0
  14. package/dist/components/_internal/nav-link.module.mjs +14 -0
  15. package/dist/components/_internal/sr-only.css +17 -0
  16. package/dist/components/_internal/sr-only.module.mjs +5 -0
  17. package/dist/components/_internal/status-tone.css +37 -0
  18. package/dist/components/_internal/status-tone.d.mts +20 -0
  19. package/dist/components/_internal/status-tone.mjs +22 -0
  20. package/dist/components/_internal/status-tone.module.mjs +14 -0
  21. package/dist/components/ai/_internal/attachment-preview.css +75 -0
  22. package/dist/components/ai/_internal/attachment-preview.d.mts +14 -0
  23. package/dist/components/ai/_internal/attachment-preview.mjs +50 -0
  24. package/dist/components/ai/_internal/attachment-preview.module.mjs +14 -0
  25. package/dist/components/ai/_internal/collapsible.css +62 -0
  26. package/dist/components/ai/_internal/collapsible.d.mts +4 -3
  27. package/dist/components/ai/_internal/collapsible.mjs +42 -33
  28. package/dist/components/ai/_internal/collapsible.module.mjs +12 -0
  29. package/dist/components/ai/_internal/icons.d.mts +7 -0
  30. package/dist/components/ai/_internal/icons.mjs +14 -0
  31. package/dist/components/ai/_internal/streaming-cursor.css +28 -0
  32. package/dist/components/ai/_internal/streaming-cursor.d.mts +2 -3
  33. package/dist/components/ai/_internal/streaming-cursor.mjs +2 -1
  34. package/dist/components/ai/_internal/streaming-cursor.module.mjs +8 -0
  35. package/dist/components/ai/attachment/attachment.css +17 -0
  36. package/dist/components/ai/attachment/attachment.d.mts +14 -0
  37. package/dist/components/ai/attachment/attachment.mjs +25 -0
  38. package/dist/components/ai/attachment/attachment.module.mjs +8 -0
  39. package/dist/components/ai/attachment/index.d.mts +13 -0
  40. package/dist/components/ai/attachment/index.mjs +8 -0
  41. package/dist/components/ai/conversation/conversation.css +71 -0
  42. package/dist/components/ai/conversation/conversation.d.mts +8 -11
  43. package/dist/components/ai/conversation/conversation.mjs +39 -40
  44. package/dist/components/ai/conversation/conversation.module.mjs +11 -0
  45. package/dist/components/ai/conversation/index.d.mts +15 -2
  46. package/dist/components/ai/conversation/index.mjs +8 -1
  47. package/dist/components/ai/index.d.mts +8 -10
  48. package/dist/components/ai/index.mjs +7 -5
  49. package/dist/components/ai/message/index.d.mts +39 -2
  50. package/dist/components/ai/message/index.mjs +12 -1
  51. package/dist/components/ai/message/message.css +71 -0
  52. package/dist/components/ai/message/message.d.mts +33 -5
  53. package/dist/components/ai/message/message.mjs +98 -12
  54. package/dist/components/ai/message/message.module.mjs +18 -0
  55. package/dist/components/ai/prompt-input/index.d.mts +31 -2
  56. package/dist/components/ai/prompt-input/index.mjs +10 -1
  57. package/dist/components/ai/prompt-input/prompt-input.css +101 -0
  58. package/dist/components/ai/prompt-input/prompt-input.d.mts +15 -8
  59. package/dist/components/ai/prompt-input/prompt-input.mjs +152 -42
  60. package/dist/components/ai/prompt-input/prompt-input.module.mjs +15 -0
  61. package/dist/components/ai/reasoning/reasoning.css +16 -0
  62. package/dist/components/ai/reasoning/reasoning.d.mts +2 -3
  63. package/dist/components/ai/reasoning/reasoning.mjs +5 -5
  64. package/dist/components/ai/reasoning/reasoning.module.mjs +8 -0
  65. package/dist/components/ai/response/response.css +453 -0
  66. package/dist/components/ai/response/response.d.mts +4 -6
  67. package/dist/components/ai/response/response.mjs +20 -15
  68. package/dist/components/ai/response/response.module.mjs +8 -0
  69. package/dist/components/ai/source/index.d.mts +12 -0
  70. package/dist/components/ai/source/index.mjs +8 -0
  71. package/dist/components/ai/source/source.css +54 -0
  72. package/dist/components/ai/source/source.d.mts +13 -0
  73. package/dist/components/ai/source/source.mjs +51 -0
  74. package/dist/components/ai/source/source.module.mjs +12 -0
  75. package/dist/components/ai/suggestion/index.d.mts +13 -2
  76. package/dist/components/ai/suggestion/index.mjs +7 -1
  77. package/dist/components/ai/suggestion/suggestion.css +32 -0
  78. package/dist/components/ai/suggestion/suggestion.d.mts +3 -6
  79. package/dist/components/ai/suggestion/suggestion.mjs +8 -11
  80. package/dist/components/ai/suggestion/suggestion.module.mjs +8 -0
  81. package/dist/components/ai/tool-invocation/approval-bar.css +26 -0
  82. package/dist/components/ai/tool-invocation/approval-bar.d.mts +11 -0
  83. package/dist/components/ai/tool-invocation/approval-bar.mjs +59 -0
  84. package/dist/components/ai/tool-invocation/approval-bar.module.mjs +9 -0
  85. package/dist/components/ai/tool-invocation/tool-invocation.css +55 -0
  86. package/dist/components/ai/tool-invocation/tool-invocation.d.mts +5 -5
  87. package/dist/components/ai/tool-invocation/tool-invocation.mjs +39 -18
  88. package/dist/components/ai/tool-invocation/tool-invocation.module.mjs +15 -0
  89. package/dist/components/ai/types.d.mts +21 -4
  90. package/dist/components/buttons/button/button.css +158 -0
  91. package/dist/components/buttons/button/button.d.mts +32 -9
  92. package/dist/components/buttons/button/button.mjs +46 -36
  93. package/dist/components/buttons/button/button.module.mjs +23 -0
  94. package/dist/components/buttons/button/index.d.mts +2 -2
  95. package/dist/components/buttons/copy-button/copy-button.css +15 -0
  96. package/dist/components/buttons/copy-button/copy-button.d.mts +10 -0
  97. package/dist/components/buttons/copy-button/copy-button.mjs +70 -0
  98. package/dist/components/buttons/copy-button/copy-button.module.mjs +8 -0
  99. package/dist/components/buttons/copy-button/index.d.mts +2 -0
  100. package/dist/components/buttons/copy-button/index.mjs +2 -0
  101. package/dist/components/buttons/icon-button/icon-button.css +81 -0
  102. package/dist/components/buttons/icon-button/icon-button.d.mts +39 -12
  103. package/dist/components/buttons/icon-button/icon-button.mjs +71 -58
  104. package/dist/components/buttons/icon-button/icon-button.module.mjs +15 -0
  105. package/dist/components/buttons/icon-button/index.d.mts +2 -2
  106. package/dist/components/buttons/toolbar/index.d.mts +14 -0
  107. package/dist/components/buttons/toolbar/index.mjs +9 -0
  108. package/dist/components/buttons/toolbar/toolbar.css +30 -0
  109. package/dist/components/buttons/toolbar/toolbar.d.mts +18 -0
  110. package/dist/components/buttons/toolbar/toolbar.mjs +111 -0
  111. package/dist/components/buttons/toolbar/toolbar.module.mjs +9 -0
  112. package/dist/components/data-display/accordion/accordion-button.css +48 -0
  113. package/dist/components/data-display/accordion/accordion-button.d.mts +2 -3
  114. package/dist/components/data-display/accordion/accordion-button.mjs +5 -4
  115. package/dist/components/data-display/accordion/accordion-button.module.mjs +9 -0
  116. package/dist/components/data-display/accordion/accordion-item.css +11 -0
  117. package/dist/components/data-display/accordion/accordion-item.d.mts +2 -3
  118. package/dist/components/data-display/accordion/accordion-item.mjs +2 -1
  119. package/dist/components/data-display/accordion/accordion-item.module.mjs +5 -0
  120. package/dist/components/data-display/accordion/accordion-panel.css +9 -0
  121. package/dist/components/data-display/accordion/accordion-panel.d.mts +2 -3
  122. package/dist/components/data-display/accordion/accordion-panel.mjs +2 -2
  123. package/dist/components/data-display/accordion/accordion-panel.module.mjs +5 -0
  124. package/dist/components/data-display/accordion/accordion.css +19 -0
  125. package/dist/components/data-display/accordion/accordion.d.mts +2 -3
  126. package/dist/components/data-display/accordion/accordion.mjs +2 -1
  127. package/dist/components/data-display/accordion/accordion.module.mjs +5 -0
  128. package/dist/components/data-display/accordion/context.d.mts +3 -3
  129. package/dist/components/data-display/accordion/index.d.mts +2 -3
  130. package/dist/components/data-display/avatar/avatar.css +95 -0
  131. package/dist/components/data-display/avatar/avatar.d.mts +2 -3
  132. package/dist/components/data-display/avatar/avatar.mjs +22 -6
  133. package/dist/components/data-display/avatar/avatar.module.mjs +18 -0
  134. package/dist/components/data-display/badge/badge.css +160 -0
  135. package/dist/components/data-display/badge/badge.d.mts +2 -3
  136. package/dist/components/data-display/badge/badge.mjs +30 -5
  137. package/dist/components/data-display/badge/badge.module.mjs +21 -0
  138. package/dist/components/data-display/card/card.css +44 -0
  139. package/dist/components/data-display/card/card.d.mts +2 -3
  140. package/dist/components/data-display/card/card.mjs +12 -2
  141. package/dist/components/data-display/card/card.module.mjs +12 -0
  142. package/dist/components/data-display/carousel/carousel.css +83 -0
  143. package/dist/components/data-display/carousel/carousel.d.mts +11 -0
  144. package/dist/components/data-display/carousel/carousel.mjs +186 -0
  145. package/dist/components/data-display/carousel/carousel.module.mjs +18 -0
  146. package/dist/components/data-display/carousel/index.d.mts +11 -0
  147. package/dist/components/data-display/carousel/index.mjs +8 -0
  148. package/dist/components/data-display/code/code.css +37 -0
  149. package/dist/components/data-display/code/code.d.mts +2 -3
  150. package/dist/components/data-display/code/code.mjs +7 -6
  151. package/dist/components/data-display/code/code.module.mjs +9 -0
  152. package/dist/components/data-display/code/find-all-colors.d.mts +2 -3
  153. package/dist/components/data-display/code/find-all-colors.mjs +0 -161
  154. package/dist/components/data-display/code-block/code-block.css +161 -0
  155. package/dist/components/data-display/code-block/code-block.d.mts +12 -0
  156. package/dist/components/data-display/code-block/code-block.mjs +44 -0
  157. package/dist/components/data-display/code-block/code-block.module.mjs +11 -0
  158. package/dist/components/data-display/code-block/highlight.d.mts +9 -0
  159. package/dist/components/data-display/code-block/highlight.mjs +54 -0
  160. package/dist/components/data-display/code-block/index.d.mts +2 -0
  161. package/dist/components/data-display/code-block/index.mjs +2 -0
  162. package/dist/components/data-display/data-table/data-table.css +74 -0
  163. package/dist/components/data-display/data-table/data-table.d.mts +31 -0
  164. package/dist/components/data-display/data-table/data-table.mjs +155 -0
  165. package/dist/components/data-display/data-table/data-table.module.mjs +14 -0
  166. package/dist/components/data-display/data-table/index.d.mts +2 -0
  167. package/dist/components/data-display/data-table/index.mjs +2 -0
  168. package/dist/components/data-display/heading/heading.css +99 -0
  169. package/dist/components/data-display/heading/heading.d.mts +2 -3
  170. package/dist/components/data-display/heading/heading.mjs +15 -14
  171. package/dist/components/data-display/heading/heading.module.mjs +20 -0
  172. package/dist/components/data-display/kbd/index.d.mts +2 -0
  173. package/dist/components/data-display/kbd/index.mjs +2 -0
  174. package/dist/components/data-display/kbd/kbd.css +21 -0
  175. package/dist/components/data-display/kbd/kbd.d.mts +8 -0
  176. package/dist/components/data-display/kbd/kbd.mjs +17 -0
  177. package/dist/components/data-display/kbd/kbd.module.mjs +5 -0
  178. package/dist/components/data-display/prose/index.d.mts +2 -0
  179. package/dist/components/data-display/prose/index.mjs +2 -0
  180. package/dist/components/data-display/prose/prose.css +253 -0
  181. package/dist/components/data-display/prose/prose.d.mts +5 -0
  182. package/dist/components/data-display/prose/prose.mjs +10 -0
  183. package/dist/components/data-display/prose/prose.module.mjs +5 -0
  184. package/dist/components/data-display/table/table.css +107 -0
  185. package/dist/components/data-display/table/table.d.mts +10 -9
  186. package/dist/components/data-display/table/table.mjs +26 -15
  187. package/dist/components/data-display/table/table.module.mjs +22 -0
  188. package/dist/components/data-display/tree/index.d.mts +2 -0
  189. package/dist/components/data-display/tree/index.mjs +2 -0
  190. package/dist/components/data-display/tree/tree.css +84 -0
  191. package/dist/components/data-display/tree/tree.d.mts +20 -0
  192. package/dist/components/data-display/tree/tree.mjs +151 -0
  193. package/dist/components/data-display/tree/tree.module.mjs +15 -0
  194. package/dist/components/feedback/alert/alert.css +42 -0
  195. package/dist/components/feedback/alert/alert.d.mts +3 -4
  196. package/dist/components/feedback/alert/alert.mjs +20 -23
  197. package/dist/components/feedback/alert/alert.module.mjs +14 -0
  198. package/dist/components/feedback/callout/callout.css +38 -0
  199. package/dist/components/feedback/callout/callout.d.mts +10 -0
  200. package/dist/components/feedback/callout/callout.mjs +38 -0
  201. package/dist/components/feedback/callout/callout.module.mjs +11 -0
  202. package/dist/components/feedback/callout/index.d.mts +2 -0
  203. package/dist/components/feedback/callout/index.mjs +2 -0
  204. package/dist/components/feedback/empty-state/empty-state.css +36 -0
  205. package/dist/components/feedback/empty-state/empty-state.d.mts +10 -0
  206. package/dist/components/feedback/empty-state/empty-state.mjs +27 -0
  207. package/dist/components/feedback/empty-state/empty-state.module.mjs +11 -0
  208. package/dist/components/feedback/empty-state/index.d.mts +2 -0
  209. package/dist/components/feedback/empty-state/index.mjs +2 -0
  210. package/dist/components/feedback/progress/progress.css +78 -0
  211. package/dist/components/feedback/progress/progress.d.mts +5 -5
  212. package/dist/components/feedback/progress/progress.mjs +17 -3
  213. package/dist/components/feedback/progress/progress.module.mjs +12 -0
  214. package/dist/components/feedback/skeleton/skeleton.css +64 -0
  215. package/dist/components/feedback/skeleton/skeleton.d.mts +2 -3
  216. package/dist/components/feedback/skeleton/skeleton.mjs +19 -2
  217. package/dist/components/feedback/skeleton/skeleton.module.mjs +17 -0
  218. package/dist/components/feedback/spinner/spinner.css +40 -0
  219. package/dist/components/feedback/spinner/spinner.d.mts +2 -3
  220. package/dist/components/feedback/spinner/spinner.mjs +13 -7
  221. package/dist/components/feedback/spinner/spinner.module.mjs +12 -0
  222. package/dist/components/feedback/toast/context.d.mts +8 -9
  223. package/dist/components/feedback/toast/provider.css +69 -0
  224. package/dist/components/feedback/toast/provider.d.mts +2 -3
  225. package/dist/components/feedback/toast/provider.mjs +17 -13
  226. package/dist/components/feedback/toast/provider.module.mjs +12 -0
  227. package/dist/components/feedback/toast/toast.d.mts +2 -3
  228. package/dist/components/form/autocomplete/autocomplete.css +154 -0
  229. package/dist/components/form/autocomplete/autocomplete.d.mts +2 -3
  230. package/dist/components/form/autocomplete/autocomplete.mjs +70 -46
  231. package/dist/components/form/autocomplete/autocomplete.module.mjs +21 -0
  232. package/dist/components/form/calendar/calendar.css +98 -0
  233. package/dist/components/form/calendar/calendar.d.mts +14 -0
  234. package/dist/components/form/calendar/calendar.mjs +182 -0
  235. package/dist/components/form/calendar/calendar.module.mjs +18 -0
  236. package/dist/components/form/calendar/index.d.mts +2 -0
  237. package/dist/components/form/calendar/index.mjs +2 -0
  238. package/dist/components/form/checkbox/checkbox.css +90 -0
  239. package/dist/components/form/checkbox/checkbox.d.mts +5 -3
  240. package/dist/components/form/checkbox/checkbox.mjs +30 -27
  241. package/dist/components/form/checkbox/checkbox.module.mjs +13 -0
  242. package/dist/components/form/checkbox-card/checkbox-card.css +138 -0
  243. package/dist/components/form/checkbox-card/checkbox-card.d.mts +3 -4
  244. package/dist/components/form/checkbox-card/checkbox-card.mjs +17 -23
  245. package/dist/components/form/checkbox-card/checkbox-card.module.mjs +17 -0
  246. package/dist/components/form/checkbox-group/checkbox-group.css +15 -0
  247. package/dist/components/form/checkbox-group/checkbox-group.d.mts +7 -5
  248. package/dist/components/form/checkbox-group/checkbox-group.mjs +12 -16
  249. package/dist/components/form/checkbox-group/checkbox-group.module.mjs +8 -0
  250. package/dist/components/form/checkbox-group/index.d.mts +5 -3
  251. package/dist/components/form/color-picker/color-picker.css +172 -0
  252. package/dist/components/form/color-picker/color-picker.d.mts +28 -0
  253. package/dist/components/form/color-picker/color-picker.mjs +239 -0
  254. package/dist/components/form/color-picker/color-picker.module.mjs +20 -0
  255. package/dist/components/form/color-picker/index.d.mts +2 -0
  256. package/dist/components/form/color-picker/index.mjs +2 -0
  257. package/dist/components/form/combobox/combobox.css +143 -0
  258. package/dist/components/form/combobox/combobox.d.mts +32 -0
  259. package/dist/components/form/combobox/combobox.mjs +278 -0
  260. package/dist/components/form/combobox/combobox.module.mjs +19 -0
  261. package/dist/components/form/combobox/index.d.mts +2 -0
  262. package/dist/components/form/combobox/index.mjs +2 -0
  263. package/dist/components/form/date-field/date-field.css +31 -0
  264. package/dist/components/form/date-field/date-field.d.mts +8 -0
  265. package/dist/components/form/date-field/date-field.mjs +20 -0
  266. package/dist/components/form/date-field/date-field.module.mjs +5 -0
  267. package/dist/components/form/date-field/index.d.mts +2 -0
  268. package/dist/components/form/date-field/index.mjs +2 -0
  269. package/dist/components/form/date-picker/date-picker.css +90 -0
  270. package/dist/components/form/date-picker/date-picker.d.mts +12 -0
  271. package/dist/components/form/date-picker/date-picker.mjs +77 -0
  272. package/dist/components/form/date-picker/date-picker.module.mjs +14 -0
  273. package/dist/components/form/date-picker/index.d.mts +2 -0
  274. package/dist/components/form/date-picker/index.mjs +2 -0
  275. package/dist/components/form/file-field/file-field.css +88 -0
  276. package/dist/components/form/file-field/file-field.d.mts +18 -19
  277. package/dist/components/form/file-field/file-field.mjs +130 -42
  278. package/dist/components/form/file-field/file-field.module.mjs +17 -0
  279. package/dist/components/form/file-field/index.d.mts +20 -2
  280. package/dist/components/form/file-field/index.mjs +9 -1
  281. package/dist/components/form/form/form.css +11 -0
  282. package/dist/components/form/form/form.d.mts +4 -4
  283. package/dist/components/form/form/form.mjs +2 -1
  284. package/dist/components/form/form/form.module.mjs +5 -0
  285. package/dist/components/form/form-control/form-control.css +43 -0
  286. package/dist/components/form/form-control/form-control.d.mts +2 -3
  287. package/dist/components/form/form-control/form-control.mjs +11 -10
  288. package/dist/components/form/form-control/form-control.module.mjs +12 -0
  289. package/dist/components/form/number-field/cast.d.mts +2 -3
  290. package/dist/components/form/number-field/cast.mjs +3 -22
  291. package/dist/components/form/number-field/number-field.css +122 -0
  292. package/dist/components/form/number-field/number-field.d.mts +10 -10
  293. package/dist/components/form/number-field/number-field.mjs +126 -54
  294. package/dist/components/form/number-field/number-field.module.mjs +10 -0
  295. package/dist/components/form/password-input/password-input.css +88 -0
  296. package/dist/components/form/password-input/password-input.d.mts +2 -3
  297. package/dist/components/form/password-input/password-input.mjs +15 -12
  298. package/dist/components/form/password-input/password-input.module.mjs +12 -0
  299. package/dist/components/form/radio/radio.css +89 -0
  300. package/dist/components/form/radio/radio.d.mts +4 -3
  301. package/dist/components/form/radio/radio.mjs +16 -19
  302. package/dist/components/form/radio/radio.module.mjs +16 -0
  303. package/dist/components/form/radio-card/radio-card.css +147 -0
  304. package/dist/components/form/radio-card/radio-card.d.mts +4 -4
  305. package/dist/components/form/radio-card/radio-card.mjs +17 -23
  306. package/dist/components/form/radio-card/radio-card.module.mjs +19 -0
  307. package/dist/components/form/range-slider/index.d.mts +2 -0
  308. package/dist/components/form/range-slider/index.mjs +2 -0
  309. package/dist/components/form/range-slider/range-slider.css +67 -0
  310. package/dist/components/form/range-slider/range-slider.d.mts +30 -0
  311. package/dist/components/form/range-slider/range-slider.mjs +135 -0
  312. package/dist/components/form/range-slider/range-slider.module.mjs +14 -0
  313. package/dist/components/form/select/select.css +74 -0
  314. package/dist/components/form/select/select.d.mts +2 -3
  315. package/dist/components/form/select/select.mjs +25 -8
  316. package/dist/components/form/select/select.module.mjs +12 -0
  317. package/dist/components/form/slider/range-input-class.css +97 -0
  318. package/dist/components/form/slider/range-input-class.d.mts +7 -0
  319. package/dist/components/form/slider/range-input-class.mjs +10 -0
  320. package/dist/components/form/slider/range-input-class.module.mjs +8 -0
  321. package/dist/components/form/slider/slider.css +55 -0
  322. package/dist/components/form/slider/slider.d.mts +6 -7
  323. package/dist/components/form/slider/slider.mjs +44 -11
  324. package/dist/components/form/slider/slider.module.mjs +12 -0
  325. package/dist/components/form/switch/switch.css +103 -0
  326. package/dist/components/form/switch/switch.d.mts +2 -3
  327. package/dist/components/form/switch/switch.mjs +14 -17
  328. package/dist/components/form/switch/switch.module.mjs +16 -0
  329. package/dist/components/form/text-field/text-field.css +41 -0
  330. package/dist/components/form/text-field/text-field.d.mts +4 -5
  331. package/dist/components/form/text-field/text-field.mjs +2 -3
  332. package/dist/components/form/text-field/text-field.module.mjs +5 -0
  333. package/dist/components/form/textarea/textarea.css +50 -0
  334. package/dist/components/form/textarea/textarea.d.mts +3 -3
  335. package/dist/components/form/textarea/textarea.mjs +6 -20
  336. package/dist/components/form/textarea/textarea.module.mjs +9 -0
  337. package/dist/components/icons/base.css +40 -0
  338. package/dist/components/icons/base.d.mts +4 -5
  339. package/dist/components/icons/base.mjs +10 -10
  340. package/dist/components/icons/base.module.mjs +13 -0
  341. package/dist/components/icons/browsers.d.mts +5 -6
  342. package/dist/components/icons/color-scale.d.mts +2 -3
  343. package/dist/components/icons/github-mark.d.mts +2 -3
  344. package/dist/components/icons/logo.css +17 -0
  345. package/dist/components/icons/logo.d.mts +3 -4
  346. package/dist/components/icons/logo.mjs +4 -3
  347. package/dist/components/icons/logo.module.mjs +9 -0
  348. package/dist/components/icons/lucide-deep.d.mts +3 -1
  349. package/dist/components/icons/lucide-imports.d.mts +3 -1
  350. package/dist/components/icons/lucide-imports.mjs +3 -1
  351. package/dist/components/icons/lucide.d.mts +60 -61
  352. package/dist/components/icons/qiita.d.mts +2 -3
  353. package/dist/components/icons/twitter.css +9 -0
  354. package/dist/components/icons/twitter.d.mts +2 -3
  355. package/dist/components/icons/twitter.mjs +2 -1
  356. package/dist/components/icons/twitter.module.mjs +5 -0
  357. package/dist/components/icons/vertical-writing.d.mts +2 -3
  358. package/dist/components/index.d.mts +62 -29
  359. package/dist/components/index.mjs +36 -14
  360. package/dist/components/layout/_shared/gap.css +25 -0
  361. package/dist/components/layout/_shared/gap.d.mts +8 -9
  362. package/dist/components/layout/_shared/gap.mjs +6 -5
  363. package/dist/components/layout/_shared/gap.module.mjs +11 -0
  364. package/dist/components/layout/_shared/padding.css +25 -0
  365. package/dist/components/layout/_shared/padding.d.mts +8 -9
  366. package/dist/components/layout/_shared/padding.mjs +6 -5
  367. package/dist/components/layout/_shared/padding.module.mjs +11 -0
  368. package/dist/components/layout/grid/grid.css +93 -0
  369. package/dist/components/layout/grid/grid.d.mts +5 -6
  370. package/dist/components/layout/grid/grid.mjs +21 -20
  371. package/dist/components/layout/grid/grid.module.mjs +25 -0
  372. package/dist/components/layout/resizable-panels/index.d.mts +18 -0
  373. package/dist/components/layout/resizable-panels/index.mjs +9 -0
  374. package/dist/components/layout/resizable-panels/resizable-panels.css +77 -0
  375. package/dist/components/layout/resizable-panels/resizable-panels.d.mts +21 -0
  376. package/dist/components/layout/resizable-panels/resizable-panels.mjs +164 -0
  377. package/dist/components/layout/resizable-panels/resizable-panels.module.mjs +16 -0
  378. package/dist/components/layout/separator/separator.css +37 -0
  379. package/dist/components/layout/separator/separator.d.mts +2 -3
  380. package/dist/components/layout/separator/separator.mjs +12 -9
  381. package/dist/components/layout/separator/separator.module.mjs +12 -0
  382. package/dist/components/layout/stack/stack.css +49 -0
  383. package/dist/components/layout/stack/stack.d.mts +3 -4
  384. package/dist/components/layout/stack/stack.mjs +11 -10
  385. package/dist/components/layout/stack/stack.module.mjs +17 -0
  386. package/dist/components/navigation/anchor/anchor.css +29 -0
  387. package/dist/components/navigation/anchor/anchor.d.mts +2 -3
  388. package/dist/components/navigation/anchor/anchor.mjs +5 -2
  389. package/dist/components/navigation/anchor/anchor.module.mjs +8 -0
  390. package/dist/components/navigation/breadcrumb/breadcrumb.css +72 -0
  391. package/dist/components/navigation/breadcrumb/breadcrumb.d.mts +5 -6
  392. package/dist/components/navigation/breadcrumb/breadcrumb.mjs +15 -9
  393. package/dist/components/navigation/breadcrumb/breadcrumb.module.mjs +14 -0
  394. package/dist/components/navigation/breadcrumb/index.d.mts +2 -3
  395. package/dist/components/navigation/pagination/pagination.css +36 -0
  396. package/dist/components/navigation/pagination/pagination.d.mts +2 -3
  397. package/dist/components/navigation/pagination/pagination.mjs +9 -8
  398. package/dist/components/navigation/pagination/pagination.module.mjs +11 -0
  399. package/dist/components/navigation/side-nav/index.d.mts +16 -0
  400. package/dist/components/navigation/side-nav/index.mjs +10 -0
  401. package/dist/components/navigation/side-nav/side-nav.css +73 -0
  402. package/dist/components/navigation/side-nav/side-nav.d.mts +31 -0
  403. package/dist/components/navigation/side-nav/side-nav.mjs +62 -0
  404. package/dist/components/navigation/side-nav/side-nav.module.mjs +11 -0
  405. package/dist/components/navigation/stepper/index.d.mts +2 -0
  406. package/dist/components/navigation/stepper/index.mjs +2 -0
  407. package/dist/components/navigation/stepper/stepper.css +151 -0
  408. package/dist/components/navigation/stepper/stepper.d.mts +19 -0
  409. package/dist/components/navigation/stepper/stepper.mjs +87 -0
  410. package/dist/components/navigation/stepper/stepper.module.mjs +29 -0
  411. package/dist/components/navigation/table-of-contents/index.d.mts +2 -0
  412. package/dist/components/navigation/table-of-contents/index.mjs +2 -0
  413. package/dist/components/navigation/table-of-contents/table-of-contents.css +17 -0
  414. package/dist/components/navigation/table-of-contents/table-of-contents.d.mts +12 -0
  415. package/dist/components/navigation/table-of-contents/table-of-contents.mjs +94 -0
  416. package/dist/components/navigation/table-of-contents/table-of-contents.module.mjs +8 -0
  417. package/dist/components/navigation/tabs/index.d.mts +19 -2
  418. package/dist/components/navigation/tabs/index.mjs +9 -1
  419. package/dist/components/navigation/tabs/tabs.css +70 -0
  420. package/dist/components/navigation/tabs/tabs.d.mts +16 -19
  421. package/dist/components/navigation/tabs/tabs.mjs +52 -49
  422. package/dist/components/navigation/tabs/tabs.module.mjs +12 -0
  423. package/dist/components/observers/fragment-instance.d.mts +1 -0
  424. package/dist/components/observers/in-view/in-view.d.mts +11 -0
  425. package/dist/components/observers/in-view/in-view.mjs +60 -0
  426. package/dist/components/observers/in-view/index.d.mts +2 -0
  427. package/dist/components/observers/in-view/index.mjs +2 -0
  428. package/dist/components/observers/resize/index.d.mts +2 -0
  429. package/dist/components/observers/resize/index.mjs +2 -0
  430. package/dist/components/observers/resize/resize.d.mts +7 -0
  431. package/dist/components/observers/resize/resize.mjs +25 -0
  432. package/dist/components/overlays/_internal/modal-dialog-context.d.mts +4 -5
  433. package/dist/components/overlays/_internal/use-can-hover.d.mts +2 -3
  434. package/dist/components/overlays/_internal/use-hover-intent.d.mts +3 -4
  435. package/dist/components/overlays/_internal/use-list-navigation.d.mts +17 -11
  436. package/dist/components/overlays/_internal/use-list-navigation.mjs +42 -26
  437. package/dist/components/overlays/command-palette/command-palette.css +91 -0
  438. package/dist/components/overlays/command-palette/command-palette.d.mts +24 -0
  439. package/dist/components/overlays/command-palette/command-palette.mjs +139 -0
  440. package/dist/components/overlays/command-palette/command-palette.module.mjs +14 -0
  441. package/dist/components/overlays/command-palette/index.d.mts +2 -0
  442. package/dist/components/overlays/command-palette/index.mjs +2 -0
  443. package/dist/components/overlays/context-menu/context-menu.d.mts +13 -0
  444. package/dist/components/overlays/context-menu/context-menu.mjs +79 -0
  445. package/dist/components/overlays/context-menu/index.d.mts +21 -0
  446. package/dist/components/overlays/context-menu/index.mjs +13 -0
  447. package/dist/components/overlays/dialog/dialog.css +31 -0
  448. package/dist/components/overlays/dialog/dialog.d.mts +12 -17
  449. package/dist/components/overlays/dialog/dialog.mjs +11 -13
  450. package/dist/components/overlays/dialog/dialog.module.mjs +10 -0
  451. package/dist/components/overlays/dialog/index.d.mts +17 -2
  452. package/dist/components/overlays/dialog/index.mjs +8 -1
  453. package/dist/components/overlays/drawer/drawer.css +48 -0
  454. package/dist/components/overlays/drawer/drawer.d.mts +2 -3
  455. package/dist/components/overlays/drawer/drawer.mjs +11 -10
  456. package/dist/components/overlays/drawer/drawer.module.mjs +13 -0
  457. package/dist/components/overlays/dropdown-menu/dropdown-menu.d.mts +19 -26
  458. package/dist/components/overlays/dropdown-menu/dropdown-menu.mjs +12 -20
  459. package/dist/components/overlays/dropdown-menu/hooks.d.mts +7 -7
  460. package/dist/components/overlays/dropdown-menu/hooks.mjs +3 -3
  461. package/dist/components/overlays/dropdown-menu/index.d.mts +30 -2
  462. package/dist/components/overlays/dropdown-menu/index.mjs +12 -1
  463. package/dist/components/overlays/dropdown-menu/shared.css +51 -0
  464. package/dist/components/overlays/dropdown-menu/shared.d.mts +3 -6
  465. package/dist/components/overlays/dropdown-menu/shared.mjs +4 -6
  466. package/dist/components/overlays/dropdown-menu/shared.module.mjs +8 -0
  467. package/dist/components/overlays/dropdown-menu/sub-menu.css +28 -0
  468. package/dist/components/overlays/dropdown-menu/sub-menu.d.mts +3 -6
  469. package/dist/components/overlays/dropdown-menu/sub-menu.mjs +16 -16
  470. package/dist/components/overlays/dropdown-menu/sub-menu.module.mjs +9 -0
  471. package/dist/components/overlays/dropdown-menu/use-safe-triangle.d.mts +2 -3
  472. package/dist/components/overlays/list-box/hooks.d.mts +6 -5
  473. package/dist/components/overlays/list-box/hooks.mjs +5 -4
  474. package/dist/components/overlays/list-box/index.d.mts +27 -2
  475. package/dist/components/overlays/list-box/index.mjs +9 -1
  476. package/dist/components/overlays/list-box/list-box.css +74 -0
  477. package/dist/components/overlays/list-box/list-box.d.mts +20 -23
  478. package/dist/components/overlays/list-box/list-box.mjs +17 -21
  479. package/dist/components/overlays/list-box/list-box.module.mjs +10 -0
  480. package/dist/components/overlays/modal/modal.css +119 -0
  481. package/dist/components/overlays/modal/modal.d.mts +2 -3
  482. package/dist/components/overlays/modal/modal.mjs +14 -11
  483. package/dist/components/overlays/modal/modal.module.mjs +11 -0
  484. package/dist/components/overlays/popover/anchor-positioning.d.mts +4 -5
  485. package/dist/components/overlays/popover/escape-stack.d.mts +2 -3
  486. package/dist/components/overlays/popover/hooks.d.mts +7 -8
  487. package/dist/components/overlays/popover/index.d.mts +25 -2
  488. package/dist/components/overlays/popover/index.mjs +8 -1
  489. package/dist/components/overlays/popover/popover.css +51 -0
  490. package/dist/components/overlays/popover/popover.d.mts +18 -20
  491. package/dist/components/overlays/popover/popover.mjs +13 -12
  492. package/dist/components/overlays/popover/popover.module.mjs +11 -0
  493. package/dist/components/overlays/tooltip/bridge.css +68 -0
  494. package/dist/components/overlays/tooltip/bridge.d.mts +2 -3
  495. package/dist/components/overlays/tooltip/bridge.mjs +7 -21
  496. package/dist/components/overlays/tooltip/bridge.module.mjs +11 -0
  497. package/dist/components/overlays/tooltip/index.d.mts +22 -2
  498. package/dist/components/overlays/tooltip/index.mjs +8 -1
  499. package/dist/components/overlays/tooltip/tooltip.css +15 -0
  500. package/dist/components/overlays/tooltip/tooltip.d.mts +19 -24
  501. package/dist/components/overlays/tooltip/tooltip.mjs +5 -9
  502. package/dist/components/overlays/tooltip/tooltip.module.mjs +5 -0
  503. package/dist/components/providers/index.d.mts +1 -2
  504. package/dist/components/providers/portal-root.d.mts +9 -7
  505. package/dist/components/providers/portal-root.mjs +7 -7
  506. package/dist/components/providers/ui-provider.d.mts +2 -6
  507. package/dist/components/providers/ui-provider.mjs +1 -5
  508. package/dist/helpers/chain.d.mts +2 -3
  509. package/dist/helpers/chain.mjs +0 -23
  510. package/dist/helpers/create-safe-context.d.mts +2 -3
  511. package/dist/helpers/create-safe-context.mjs +0 -17
  512. package/dist/helpers/index.d.mts +1 -2
  513. package/dist/helpers/index.mjs +2 -3
  514. package/dist/helpers/merge-props.d.mts +2 -3
  515. package/dist/helpers/merge-props.mjs +2 -37
  516. package/dist/helpers/merge-refs.d.mts +2 -3
  517. package/dist/helpers/merge-refs.mjs +0 -32
  518. package/dist/hooks/click-away/index.d.mts +2 -3
  519. package/dist/hooks/controllable-state/index.d.mts +2 -3
  520. package/dist/hooks/controllable-state/index.mjs +9 -11
  521. package/dist/hooks/index.d.mts +2 -23
  522. package/dist/hooks/index.mjs +2 -22
  523. package/dist/hooks/writing-mode/index.d.mts +15 -5
  524. package/dist/hooks/writing-mode/index.mjs +21 -14
  525. package/dist/i18n/current.d.mts +23 -0
  526. package/dist/i18n/current.mjs +43 -0
  527. package/dist/i18n/en.d.mts +2 -3
  528. package/dist/i18n/en.mjs +46 -0
  529. package/dist/i18n/index.d.mts +3 -2
  530. package/dist/i18n/index.mjs +4 -3
  531. package/dist/i18n/ja.d.mts +2 -3
  532. package/dist/i18n/ja.mjs +46 -0
  533. package/dist/i18n/messages.d.mts +81 -3
  534. package/dist/i18n/usage.d.mts +8 -0
  535. package/dist/i18n/usage.mjs +131 -0
  536. package/dist/index.d.mts +40 -47
  537. package/dist/index.mjs +36 -42
  538. package/dist/integrations/_shared/openui-defs.d.mts +3 -4
  539. package/dist/integrations/_shared/openui-defs.mjs +123 -54
  540. package/dist/integrations/_shared/renderers.css +50 -0
  541. package/dist/integrations/_shared/renderers.d.mts +71 -52
  542. package/dist/integrations/_shared/renderers.mjs +292 -34
  543. package/dist/integrations/_shared/renderers.module.mjs +14 -0
  544. package/dist/integrations/_shared/schemas.d.mts +388 -104
  545. package/dist/integrations/_shared/schemas.mjs +165 -27
  546. package/dist/integrations/ai-sdk/index.d.mts +2 -2
  547. package/dist/integrations/ai-sdk/map-parts.d.mts +25 -7
  548. package/dist/integrations/ai-sdk/map-parts.mjs +28 -3
  549. package/dist/integrations/json-render/catalog.d.mts +336 -18
  550. package/dist/integrations/json-render/catalog.mjs +120 -57
  551. package/dist/integrations/json-render/registry.d.mts +3 -4
  552. package/dist/integrations/json-render/registry.mjs +38 -4
  553. package/dist/integrations/openui/form-views.d.mts +23 -18
  554. package/dist/integrations/openui/form-views.mjs +27 -3
  555. package/dist/integrations/openui/library.d.mts +59 -7
  556. package/dist/integrations/openui/library.mjs +18 -3
  557. package/dist/integrations/openui/prompt.d.mts +2 -3
  558. package/dist/internal/accepts-file.d.mts +8 -0
  559. package/dist/internal/accepts-file.mjs +19 -0
  560. package/dist/internal/carries-files.d.mts +3 -0
  561. package/dist/internal/carries-files.mjs +4 -0
  562. package/dist/internal/clamp.d.mts +2 -3
  563. package/dist/internal/clamp.mjs +0 -11
  564. package/dist/internal/commit-input-value.d.mts +10 -0
  565. package/dist/internal/commit-input-value.mjs +15 -0
  566. package/dist/internal/dropped-files.d.mts +3 -0
  567. package/dist/internal/dropped-files.mjs +8 -0
  568. package/dist/{hooks/focus-trap/index.d.mts → internal/focus-trap.d.mts} +6 -7
  569. package/dist/{hooks/focus-trap/index.mjs → internal/focus-trap.mjs} +5 -5
  570. package/dist/internal/hex-color.d.mts +22 -0
  571. package/dist/internal/hex-color.mjs +53 -0
  572. package/dist/internal/iso-date.d.mts +39 -0
  573. package/dist/internal/iso-date.mjs +98 -0
  574. package/dist/internal/to-precision.d.mts +2 -3
  575. package/dist/internal/to-precision.mjs +0 -8
  576. package/dist/styles/index.css +513 -2534
  577. package/dist/styles/tailwind.css +217 -17
  578. package/dist/styles/tokens.d.mts +1 -2
  579. package/dist/styles/tokens.mjs +1 -2
  580. package/dist/types/variables.d.mts +7 -9
  581. package/docs/GUIDE.md +340 -158
  582. package/docs/llms.txt +18 -10
  583. package/docs/props.generated.json +2157 -292
  584. package/docs/references/ai-chat.md +396 -113
  585. package/docs/references/color.md +258 -113
  586. package/docs/references/components.md +1891 -461
  587. package/docs/references/generative-ui.md +163 -34
  588. package/docs/references/interaction-design.md +103 -73
  589. package/docs/references/spatial-design.md +112 -90
  590. package/docs/references/types.md +101 -0
  591. package/docs/references/typography.md +182 -73
  592. package/package.json +71 -70
  593. package/dist/components/_internal/focus-ring.d.mts +0 -8
  594. package/dist/components/_internal/focus-ring.mjs +0 -8
  595. package/dist/components/layout/scroll-linked/index.d.mts +0 -2
  596. package/dist/components/layout/scroll-linked/index.mjs +0 -2
  597. package/dist/components/layout/scroll-linked/scroll-linked.d.mts +0 -14
  598. package/dist/components/layout/scroll-linked/scroll-linked.mjs +0 -59
  599. package/dist/helpers/cn.d.mts +0 -5
  600. package/dist/helpers/cn.mjs +0 -27
  601. package/dist/hooks/breakpoint/index.d.mts +0 -5
  602. package/dist/hooks/breakpoint/index.mjs +0 -24
  603. package/dist/hooks/client/index.d.mts +0 -4
  604. package/dist/hooks/client/index.mjs +0 -6
  605. package/dist/hooks/clipboard/index.d.mts +0 -7
  606. package/dist/hooks/clipboard/index.mjs +0 -15
  607. package/dist/hooks/debounced-transition/index.d.mts +0 -5
  608. package/dist/hooks/debounced-transition/index.mjs +0 -49
  609. package/dist/hooks/deferred-debounce/index.d.mts +0 -4
  610. package/dist/hooks/deferred-debounce/index.mjs +0 -9
  611. package/dist/hooks/disclosure/index.d.mts +0 -10
  612. package/dist/hooks/disclosure/index.mjs +0 -20
  613. package/dist/hooks/hash/index.d.mts +0 -4
  614. package/dist/hooks/hash/index.mjs +0 -25
  615. package/dist/hooks/hover/index.d.mts +0 -12
  616. package/dist/hooks/hover/index.mjs +0 -19
  617. package/dist/hooks/intersection-observer/index.d.mts +0 -3
  618. package/dist/hooks/intersection-observer/index.mjs +0 -3
  619. package/dist/hooks/intersection-observer/use-in-view.d.mts +0 -11
  620. package/dist/hooks/intersection-observer/use-in-view.mjs +0 -18
  621. package/dist/hooks/intersection-observer/use-intersection-observer.d.mts +0 -11
  622. package/dist/hooks/intersection-observer/use-intersection-observer.mjs +0 -33
  623. package/dist/hooks/interval/index.d.mts +0 -4
  624. package/dist/hooks/interval/index.mjs +0 -19
  625. package/dist/hooks/local-storage/index.d.mts +0 -4
  626. package/dist/hooks/local-storage/index.mjs +0 -46
  627. package/dist/hooks/resize/index.d.mts +0 -8
  628. package/dist/hooks/resize/index.mjs +0 -24
  629. package/dist/hooks/scroll-direction/index.d.mts +0 -13
  630. package/dist/hooks/scroll-direction/index.mjs +0 -67
  631. package/dist/hooks/scroll-lock/index.d.mts +0 -9
  632. package/dist/hooks/scroll-lock/index.mjs +0 -59
  633. package/dist/hooks/session-storage/index.d.mts +0 -4
  634. package/dist/hooks/session-storage/index.mjs +0 -46
  635. package/dist/hooks/step/index.d.mts +0 -15
  636. package/dist/hooks/step/index.mjs +0 -39
  637. package/dist/hooks/timeout/index.d.mts +0 -4
  638. package/dist/hooks/timeout/index.mjs +0 -19
  639. package/dist/hooks/window-resize/index.d.mts +0 -11
  640. package/dist/hooks/window-resize/index.mjs +0 -21
  641. package/dist/hooks/window-size/index.d.mts +0 -8
  642. package/dist/hooks/window-size/index.mjs +0 -31
  643. package/dist/i18n/context.d.mts +0 -9
  644. package/dist/i18n/context.mjs +0 -19
  645. package/dist/styles/base.css +0 -315
  646. package/dist/styles/tokens.css +0 -380
  647. package/dist/styles/tokens.generated.d.mts +0 -840
  648. package/dist/styles/tokens.generated.mjs +0 -813
  649. package/dist/styles/utilities.css +0 -62
  650. package/docs/references/helpers.md +0 -120
  651. package/docs/references/hooks.md +0 -314
@@ -1,20 +1,77 @@
1
- # k8ordo UI コンポーネント一覧
1
+ # @k8ordo/ui component catalog
2
2
 
3
- ## インポート方法
3
+ ## Importing
4
4
 
5
5
  ```tsx
6
- // スタイルシート(必須)。Tailwind CSS 4 のプロジェクトは
7
- // 代わりに '@k8ordo/ui/tailwind.css' を import する
6
+ // The stylesheet (required). In a Tailwind CSS 4 project, a CSS file
7
+ // imports 'tailwindcss' and then '@k8ordo/ui/tailwind.css' instead
8
8
  import '@k8ordo/ui/styles.css';
9
-
10
- // プロバイダー(アプリルートで1回)
9
+ // The provider (once, at the app root)
11
10
  import { UIProvider } from '@k8ordo/ui';
12
-
13
- // コンポーネント(すべてルートからインポート)
11
+ // Components (all from the root entry)
14
12
  import { Button, Card, TextField } from '@k8ordo/ui';
13
+ // Except CodeBlock, which highlights on the server and has its own entry
14
+ import { CodeBlock } from '@k8ordo/ui/code-block';
15
15
  ```
16
16
 
17
- ## ボタン・リンク
17
+ Every component can be rendered from a Server Component, compound ones
18
+ included: `Dialog.Root`, `Tabs.Root`, `Popover.Trigger`, and the rest are
19
+ composed outside the client modules, so the parts resolve on the server. Only
20
+ the interactive parts carry `'use client'`.
21
+
22
+ ## Render props
23
+
24
+ Two different contracts are spelled `render*`, and mixing them up is the usual
25
+ source of surprise.
26
+
27
+ **Replacing the element** — `renderItem` on `Button` and `IconButton`,
28
+ `renderAnchor` on `Anchor`, `Breadcrumb.Link`, and `SideNav.Link`. The component computes
29
+ everything and hands back the exact props it would have put on its own element,
30
+ so substituting an `<a>`, a framework `<Link>`, or your own button loses
31
+ nothing. For `Button` and `IconButton` that is the resolved `className`, the
32
+ composed `children` (icons and the pending spinner included), the click handler,
33
+ the disabled and pending state, the `ref`, and every `aria-*` / `data-*` /
34
+ native attribute the caller passed in. Spread the bag onto whatever you render.
35
+
36
+ - Handlers and the `ref` are typed for `HTMLElement` rather than for the
37
+ element the component would have rendered, so the bag spreads onto any tag.
38
+ - `disabled` and `type` are the only members that exist on `<button>` alone.
39
+ Destructure them away when you render something else — `aria-disabled` in the
40
+ same bag carries the state, and the supplied `onClick` already does nothing
41
+ and calls `preventDefault()` while disabled, so a disabled link will not
42
+ navigate. The examples below name them `_disabled` / `_type` so the discarded
43
+ bindings pass a `no-unused-vars` rule.
44
+ - `disabled` is only the `disabled` you passed. While an action is pending (see
45
+ [Button](#button)), the bag carries `aria-disabled` and `aria-busy` but
46
+ `disabled` stays `false`, so the pressed element keeps focus; the supplied
47
+ `onClick` is what ignores presses meanwhile.
48
+ - Spreading onto a real `<button>` is exact, but write `type` on the element
49
+ anyway: the `button-has-type` lint rule cannot see a `type` that arrives
50
+ through a spread.
51
+
52
+ The link components own less, so their bags are smaller:
53
+
54
+ - `Anchor` hands back `href`, `className`, `children` (with the new-tab icon on
55
+ an external link), `target` / `rel` on an external link, and every other
56
+ anchor attribute the caller passed, plus `kind` (`'internal'` |
57
+ `'external'`). `kind` is not an attribute: destructure it away before
58
+ spreading, or use it to choose between a framework `<Link>` and a plain `<a>`.
59
+ There is no `ref` and no disabled state.
60
+ - `Breadcrumb.Link` hands back `href`, `className`, and `children` only — it
61
+ takes no other attributes. A `current` link renders
62
+ `<span aria-current="page">` and does not call `renderAnchor`.
63
+ - `SideNav.Link` hands back `href`, `className`, `children`, `aria-current`
64
+ (`'page'` on the current link), and every other anchor attribute the caller
65
+ passed. A current link is still a link.
66
+
67
+ **Filling a slot** — `renderInput` on `FormControl`, `renderItem` on
68
+ `Popover.Trigger`, `Tooltip.Trigger`, `FileField.Trigger`, and `Alert`'s
69
+ `action`. Here the component owns no element of its own. It computes wiring —
70
+ ids, ARIA relationships, open/close handlers — and you supply the element that
71
+ wiring belongs to. Those bags carry only the wiring, and they are required
72
+ rather than optional.
73
+
74
+ ## Buttons
18
75
 
19
76
  ### Button
20
77
 
@@ -31,81 +88,100 @@ import { Button } from '@k8ordo/ui';
31
88
  disabled={false}
32
89
  isActive={false}
33
90
  >
34
- ボタン
91
+ Button
35
92
  </Button>
36
93
  ```
37
94
 
38
95
  Props:
39
96
 
40
97
  - `children`: `ReactNode`
41
- - `color`: `'primary'` | `'secondary'` | `'base'`(既定: `'primary'`)
98
+ - `color`: `'primary'` | `'secondary'` | `'base'` (default: `'primary'`)
42
99
  - `endIcon`: `ReactNode`
43
- - `fullWidth`: `boolean`(既定: `false`)
44
- - `isActive`: `boolean`(既定: `false`)
100
+ - `fullWidth`: `boolean` (default: `false`)
101
+ - `isActive`: `boolean` (default: `false`)
45
102
  - `onAction`: `() => void | Promise<void>`
46
- - `renderItem`: `(props: { className: string; children: ReactNode }) => ReactNode`
47
- - `size`: `'sm'` | `'md'` | `'lg'`(既定: `'md'`)
103
+ - `renderItem`: `(props: ButtonRenderItemProps) => ReactNode`
104
+ - `size`: `'sm'` | `'md'` | `'lg'` (default: `'md'`)
48
105
  - `startIcon`: `ReactNode`
49
- - `type`: `'button'` | `'submit'`(既定: `'button'`)
50
- - `variant`: `'solid'` | `'outline'` | `'skeleton'`(既定: `'solid'`)
51
-
52
- リンクとしてレンダーする場合は `renderItem` prop を使う。Next.js の `<Link>` などにも応用できる。
106
+ - `type`: `'button'` | `'submit'` (default: `'button'`)
107
+ - `variant`: `'solid'` | `'outline'` | `'skeleton'` (default: `'solid'`)
108
+ - Other props are forwarded to `ComponentPropsWithRef<'button'>`, except `className` / `style`.
109
+
110
+ `onAction` runs inside a transition. While the promise it returns is pending —
111
+ and, with `type="submit"`, while the form's action is pending — the button shows
112
+ a spinner, carries `aria-busy` and `aria-disabled`, and ignores presses,
113
+ including the implicit submission of pressing Enter in a field. It does not
114
+ become natively `disabled`: Chromium moves focus to `body` when the focused
115
+ element is disabled, so a keyboard user who pressed the button would lose their
116
+ place. The `disabled` you pass is native, and takes the button out of the tab
117
+ order.
118
+
119
+ `renderItem` replaces the `<button>`; see [Render props](#render-props) for the
120
+ contract. It receives `className`, the composed `children`, `ref`, `type`,
121
+ `disabled`, `aria-disabled`, `aria-busy`, `onClick`, and every other attribute
122
+ passed to `Button`. Use it to render a link — the same shape works for things
123
+ like Next.js's `<Link>`.
53
124
 
54
125
  ```tsx
55
126
  <Button
56
127
  color="base"
57
128
  variant="outline"
58
- renderItem={({ className, children }) => (
59
- <a className={className} href="/page">
129
+ renderItem={({ children, disabled: _disabled, type: _type, ...props }) => (
130
+ <a href="/page" {...props}>
60
131
  {children}
61
132
  </a>
62
133
  )}
63
134
  >
64
- リンク
135
+ Link
65
136
  </Button>
66
137
  ```
67
138
 
68
139
  ### IconButton
69
140
 
70
- アイコンのみのボタン。`color` prop でスタイルを制御。
141
+ An icon-only button. Styling is controlled by the `color` prop.
71
142
 
72
143
  ```tsx
73
144
  import { IconButton } from '@k8ordo/ui';
74
145
 
75
- <IconButton label="閉じる" color="transparent" size="md">
146
+ <IconButton label="Close" color="transparent" size="md">
76
147
  <CloseIcon />
77
148
  </IconButton>;
78
149
  ```
79
150
 
80
151
  Props:
81
152
 
82
- - `label`: `string`(必須)
153
+ - `label`: `string` (required)
83
154
  - `children`: `ReactNode`
84
- - `color`: `'transparent'` | `'base'` | `'primary'` | `'secondary'`(既定: `'transparent'`)
155
+ - `color`: `'transparent'` | `'base'` | `'primary'` | `'secondary'` (default: `'transparent'`)
85
156
  - `onAction`: `() => void | Promise<void>`
86
- - `renderItem`: `(props: { className: string; children: ReactNode; 'aria-label': string; triggerProps: IconButtonTriggerProps; }) => ReactNode`
87
- - `size`: `'sm'` | `'md'` | `'lg'`(既定: `'md'`)
88
- - `tooltipDisabled`: `boolean`(既定: `false`)
89
- - `tooltipPlacement`: `Placement`(既定: `'top'`)
90
-
91
- リンクとしてレンダーする場合は `renderItem` prop を使う。`triggerProps` を `<a>` にスプレッドすると hover/focus 時に `label` が Tooltip として表示される。
157
+ - `renderItem`: `(props: IconButtonRenderItemProps) => ReactNode`
158
+ - `size`: `'sm'` | `'md'` | `'lg'` (default: `'md'`)
159
+ - `tooltipDisabled`: `boolean` (default: `false`)
160
+ - `tooltipPlacement`: `Placement` (default: `'top'`)
161
+ - Other props are forwarded to `ComponentPropsWithRef<'button'>`, except `type` / `className` / `style`.
162
+
163
+ `onAction` keeps the button busy the way `Button`'s does — `aria-busy`,
164
+ `aria-disabled`, presses ignored, focus kept — without the spinner.
165
+
166
+ `renderItem` replaces the `<button>` under the same contract as `Button`'s,
167
+ with one addition: the tooltip wiring is kept in a nested `triggerProps` so it
168
+ stays free of any element type. Spread it too, and `label` shows as a tooltip on
169
+ hover and focus. `triggerProps` also carries the merged `ref` and any
170
+ `onMouseEnter` / `onMouseLeave` / `onFocus` / `onBlur` the caller passed, so the
171
+ flat part of the bag holds neither.
92
172
 
93
173
  ```tsx
94
174
  <IconButton
95
175
  color="base"
96
- label="メール"
176
+ label="Mail"
97
177
  renderItem={({
98
- className,
99
178
  children,
100
- 'aria-label': ariaLabel,
179
+ disabled: _disabled,
101
180
  triggerProps,
181
+ type: _type,
182
+ ...props
102
183
  }) => (
103
- <a
104
- aria-label={ariaLabel}
105
- className={className}
106
- href="/contact"
107
- {...triggerProps}
108
- >
184
+ <a href="/contact" {...props} {...triggerProps}>
109
185
  {children}
110
186
  </a>
111
187
  )}
@@ -114,80 +190,117 @@ Props:
114
190
  </IconButton>
115
191
  ```
116
192
 
117
- ### Anchor
193
+ ### CopyButton
118
194
 
119
- テキストリンク。外部リンクには自動で新規タブアイコンが付く。
195
+ A button that copies text to the clipboard and shows that it did: its icon
196
+ turns into a check for two seconds (an error icon if the write fails), and a
197
+ live region beside it announces `copied` / `copyFailed` from the dictionary. The
198
+ button's name stays the same throughout. By default it is an outline `Button`
199
+ with its `label` as text; `iconOnly` makes it a transparent `IconButton` whose
200
+ `label` is the tooltip.
120
201
 
121
202
  ```tsx
122
- import { Anchor } from '@k8ordo/ui';
203
+ import { CopyButton } from '@k8ordo/ui';
204
+
205
+ <CopyButton value={css} label="Copy CSS" size="sm" />;
123
206
 
124
- <Anchor href="https://example.com">外部リンク</Anchor>
125
- <Anchor href="/about">内部リンク</Anchor>
126
- <Anchor href="/docs" openInNewTab>新規タブで開く</Anchor>
207
+ // Icon only, e.g. in the header of a code block
208
+ <CopyButton value={code} label="Copy code" iconOnly size="sm" />;
209
+
210
+ // Build the text when the button is pressed: read the DOM, or fetch it
211
+ <CopyButton
212
+ label="Copy as Markdown"
213
+ value={async () => (await fetch(`/blog/${slug}.md`)).text()}
214
+ />;
127
215
  ```
128
216
 
217
+ `value` may be a function, and it may return a `Promise`. It is called on the
218
+ click, and the promise goes to the clipboard as it is (a `ClipboardItem`), so the
219
+ write starts inside the click even when the text arrives later. Safari refuses
220
+ a write that begins after an `await`.
221
+
129
222
  Props:
130
223
 
131
- - `children`: `ReactNode`(必須)
132
- - `href`: `T`(必須)
133
- - `openInNewTab`: `boolean`(既定: `false`)
134
- - `renderAnchor`: `(props: RenderAnchorProps<T>) => ReactNode`(既定: `defaultRenderAnchor`)
224
+ - `value`: `string` | `(() => string | Promise<string>)` (required)
225
+ - `disabled`: `boolean` (default: `false`)
226
+ - `iconOnly`: `boolean` (default: `false`)
227
+ - `label`: `string`
228
+ - `size`: `'sm'` | `'md'` | `'lg'` (default: `'md'`)
135
229
 
136
- ## レイアウト・ナビゲーション
230
+ ### Toolbar
137
231
 
138
- ### Accordion
232
+ A group of controls that takes one Tab stop (the WAI-ARIA toolbar). Arrow keys
233
+ move between the items — left/right when `orientation` is `horizontal`, up/down
234
+ when `vertical`, and in vertical writing mode the other pair, since the row
235
+ itself runs vertically — `Home` / `End` jump to the ends, and disabled items are
236
+ skipped. Tab leaves the toolbar, and coming back lands on the item last focused.
139
237
 
140
- 折りたたみ可能なセクション。Compound component パターン。
238
+ Each item is a slot: `Toolbar.Item`'s `renderItem` receives `ref`, `tabIndex`,
239
+ and `onFocus` (`ToolbarItemProps`) to spread onto a `Button`, an `IconButton`,
240
+ or any other button. A toggle item sets `aria-pressed`; the toolbar shades a
241
+ pressed item. The root needs a name (`aria-label` or `aria-labelledby`).
242
+ Items are meant to be buttons: a control that uses the arrow keys itself (a text
243
+ field, a slider) would fight the toolbar for them.
141
244
 
142
245
  ```tsx
143
- import { Accordion } from '@k8ordo/ui';
144
-
145
- <Accordion.Root>
146
- <Accordion.Item>
147
- <Accordion.Button>セクション1</Accordion.Button>
148
- <Accordion.Panel>コンテンツ</Accordion.Panel>
149
- </Accordion.Item>
150
- </Accordion.Root>;
246
+ import { IconButton, Toolbar } from '@k8ordo/ui';
247
+
248
+ <Toolbar.Root aria-label="Formatting">
249
+ <Toolbar.Item
250
+ renderItem={(props) => (
251
+ <IconButton {...props} label="Copy">
252
+ <CopyIcon />
253
+ </IconButton>
254
+ )}
255
+ />
256
+ <Toolbar.Separator />
257
+ <Toolbar.Item
258
+ renderItem={(props) => (
259
+ <IconButton
260
+ {...props}
261
+ aria-pressed={isList}
262
+ label="Bulleted list"
263
+ onClick={toggleList}
264
+ >
265
+ <ListIcon />
266
+ </IconButton>
267
+ )}
268
+ />
269
+ </Toolbar.Root>;
151
270
  ```
152
271
 
153
- Props (Accordion.Button):
154
-
155
- - `children`: `ReactNode`
156
-
157
- Props (Accordion.Item):
272
+ Props (Root):
158
273
 
159
274
  - `children`: `ReactNode`
160
- - `defaultOpen`: `boolean`(既定: `false`)
161
- - `isOpen`: `boolean`
162
- - `onChange`: `(isOpen: boolean) => void`
163
-
164
- Props (Accordion.Panel):
275
+ - `orientation`: `'horizontal'` | `'vertical'` (default: `'horizontal'`)
276
+ - `ref`: `Ref<HTMLDivElement>`
277
+ - Other props are forwarded to `HTMLAttributes<HTMLDivElement>`, except `className` / `style` / `role` / `aria-orientation`.
165
278
 
166
- - `children`: `ReactNode`
279
+ Props (Toolbar.Item):
167
280
 
168
- Props (Accordion.Root):
281
+ - `renderItem`: `(props: ToolbarItemProps) => ReactElement` (required)
169
282
 
170
- - `children`: `ReactNode`
283
+ ## Navigation
171
284
 
172
285
  ### Breadcrumb
173
286
 
174
- パンくずリスト。Compound component パターン。
287
+ A breadcrumb trail, as a compound component.
175
288
 
176
289
  ```tsx
177
290
  import { Breadcrumb } from '@k8ordo/ui';
178
291
 
179
292
  <Breadcrumb.List>
180
293
  <Breadcrumb.Item>
181
- <Breadcrumb.Link href="/">ホーム</Breadcrumb.Link>
294
+ <Breadcrumb.Link href="/">Home</Breadcrumb.Link>
182
295
  </Breadcrumb.Item>
183
296
  <Breadcrumb.Separator />
184
297
  <Breadcrumb.Item>
185
- <Breadcrumb.Link href="/products">製品</Breadcrumb.Link>
298
+ <Breadcrumb.Link href="/products">Products</Breadcrumb.Link>
186
299
  </Breadcrumb.Item>
187
300
  <Breadcrumb.Separator />
188
301
  <Breadcrumb.Item>
189
302
  <Breadcrumb.Link href="/products/1" current>
190
- 詳細
303
+ Details
191
304
  </Breadcrumb.Link>
192
305
  </Breadcrumb.Item>
193
306
  </Breadcrumb.List>;
@@ -196,14 +309,17 @@ import { Breadcrumb } from '@k8ordo/ui';
196
309
  Props (Breadcrumb.List):
197
310
 
198
311
  - `children`: `ReactNode`
199
- - `size`: `'sm'` | `'md'` | `'lg'`(既定: `'md'`)
312
+ - `size`: `'sm'` | `'md'` | `'lg'` (default: `'md'`)
200
313
 
201
314
  Props (Breadcrumb.Link):
202
315
 
203
- - `href`: `T`(必須)
316
+ - `href`: `T` (required)
204
317
  - `children`: `ReactNode`
205
- - `current`: `boolean`(既定: `false`)
206
- - `renderAnchor`: `(props: RenderBreadcrumbAnchorProps<T>) => ReactNode`(既定: `defaultRenderBreadcrumbAnchor`)
318
+ - `current`: `boolean` (default: `false`)
319
+ - `renderAnchor`: `(props: RenderBreadcrumbAnchorProps<T>) => ReactNode` (default: `defaultRenderBreadcrumbAnchor`)
320
+
321
+ `Breadcrumb.Link`'s `renderAnchor` receives `href`, `className`, and `children`;
322
+ see [Render props](#render-props).
207
323
 
208
324
  Props (Breadcrumb.Item):
209
325
 
@@ -211,7 +327,7 @@ Props (Breadcrumb.Item):
211
327
 
212
328
  ### Pagination
213
329
 
214
- ページ送り。前後ボタンと現在ページの表示のみで、ページ番号のリストは持たない。
330
+ Pagination. It shows previous/next buttons and the current page only — there is no list of page numbers.
215
331
 
216
332
  ```tsx
217
333
  import { Pagination } from '@k8ordo/ui';
@@ -221,206 +337,294 @@ import { Pagination } from '@k8ordo/ui';
221
337
 
222
338
  Props:
223
339
 
224
- - `currentPage`: `number`(必須)
225
- - `onChange`: `(page: number) => void`(必須)
226
- - `totalPages`: `number`(必須)
340
+ - `currentPage`: `number` (required)
341
+ - `onChange`: `(page: number) => void` (required)
342
+ - `totalPages`: `number` (required)
227
343
  - `aria-label`: `string`
228
- - `disabled`: `boolean`(既定: `false`)
344
+ - `disabled`: `boolean` (default: `false`)
229
345
  - `nextLabel`: `string`
230
346
  - `prevLabel`: `string`
231
347
  - `ref`: `Ref<HTMLElement>`
348
+ - Other props are forwarded to `HTMLAttributes<HTMLElement>`, except `className` / `style` / `children`.
232
349
 
233
- ### Tabs
350
+ ### Stepper
234
351
 
235
- タブ切り替え。Compound component パターン。
352
+ The steps of a process in order, as an `<ol>`: done steps show a check and are
353
+ read with the built-in `stepperComplete` wording, and the current step carries
354
+ `aria-current="step"`. `value` is the index of the current step (0-based);
355
+ `steps.length` marks every step done. With `interactive`, done steps become
356
+ buttons that go back to them (`onChange` receives the index); steps ahead are
357
+ never buttons. Name the list with `aria-label`.
236
358
 
237
- ```tsx
238
- import { Tabs } from '@k8ordo/ui';
359
+ `orientation` is logical: `horizontal` lays the steps along the line and
360
+ `vertical` stacks them, so inside `writing-v` they run top to bottom and right
361
+ to left respectively, with the connecting lines drawn to match and the step
362
+ numbers kept upright. In `horizontal`, every step takes an equal share of the
363
+ width: the first row holds only the step markers and the lines between them,
364
+ and each step's label and description sit under its marker, wrapping within
365
+ that share. The lines keep their length however long the labels are, and a
366
+ narrow container wraps the text rather than squeezing the lines.
239
367
 
240
- <Tabs.Root ids={['tab1', 'tab2']}>
241
- <Tabs.List label="タブ">
242
- <Tabs.Tab id="tab1">タブ1</Tabs.Tab>
243
- <Tabs.Tab id="tab2">タブ2</Tabs.Tab>
244
- </Tabs.List>
245
- <Tabs.Panel id="tab1">パネル1</Tabs.Panel>
246
- <Tabs.Panel id="tab2">パネル2</Tabs.Panel>
247
- </Tabs.Root>;
248
- ```
368
+ In a multi-step form (see `@k8ordo/form`'s guide), keep every step mounted and
369
+ drive `value` from the step you show.
249
370
 
250
- Props (Tabs.Root):
371
+ ```tsx
372
+ import { Stepper } from '@k8ordo/ui';
373
+
374
+ <Stepper
375
+ aria-label="Sign-up"
376
+ interactive
377
+ onChange={setStep}
378
+ steps={[
379
+ { label: 'Plan', description: 'Pick what fits' },
380
+ { label: 'Payment' },
381
+ { label: 'Review' },
382
+ ]}
383
+ value={step}
384
+ />;
385
+ ```
251
386
 
252
- - `ids`: `[string, ...string[]]`(必須)
253
- - `children`: `ReactNode`
254
- - `defaultSelectedId`: `string` | `null`(既定: `null`)
255
- - `onChange`: `(id: string) => void`
256
- - `selectedId`: `string`
387
+ Props:
257
388
 
258
- Props (Tabs.List):
389
+ - `steps`: `readonly StepperStep[]` (required)
390
+ - `defaultValue`: `number`
391
+ - `interactive`: `boolean` (default: `false`)
392
+ - `onChange`: `(value: number) => void`
393
+ - `orientation`: `'horizontal'` | `'vertical'` (default: `'horizontal'`)
394
+ - `ref`: `Ref<HTMLOListElement>`
395
+ - `value`: `number`
396
+ - Other props are forwarded to `OlHTMLAttributes<HTMLOListElement>`, except `className` / `style` / `children`.
259
397
 
260
- - `label`: `string`(必須)
261
- - `children`: `ReactNode`
398
+ ### SideNav
262
399
 
263
- Props (Tabs.Panel):
400
+ Side navigation: groups of links, each under a small title, with the page being
401
+ shown marked by a bar (`aria-current="page"`). The library has no router, so
402
+ you say which link is current, and swap the `<a>` for your router's link with
403
+ `renderAnchor` — it replaces the element, and its bag holds `href`,
404
+ `className`, `children`, `aria-current`, and every other anchor attribute you
405
+ passed (an `onClick` that closes a drawer, say). Every part renders from a
406
+ Server Component.
264
407
 
265
- - `id`: `string`(必須)
266
- - `children`: `ReactNode`
408
+ ```tsx
409
+ import { SideNav } from '@k8ordo/ui';
410
+
411
+ <SideNav.Root label="Components">
412
+ <SideNav.Group title="Buttons">
413
+ <SideNav.Link current={pathname === '/button'} href="/button">
414
+ Button
415
+ </SideNav.Link>
416
+ <SideNav.Link
417
+ href="/icon-button"
418
+ renderAnchor={({ children, ...props }) => (
419
+ <Link {...props}>{children}</Link>
420
+ )}
421
+ >
422
+ IconButton
423
+ </SideNav.Link>
424
+ </SideNav.Group>
425
+ </SideNav.Root>;
426
+ ```
267
427
 
268
- Props (Tabs.Tab):
428
+ Props (SideNav.Root):
269
429
 
270
- - `id`: `string`(必須)
430
+ - `label`: `string` (required)
271
431
  - `children`: `ReactNode`
432
+ - Other props are forwarded to `HTMLAttributes<HTMLElement>`, except `className` / `style` / `aria-label`.
272
433
 
273
- ### Card
274
-
275
- コンテンツをグループ化するカード。
434
+ A group can hold a level that opens and closes, `SideNav.Sub`, to make the
435
+ navigation a tree. It is a `<details>`, so it opens and closes without
436
+ JavaScript; open the one holding the current page with `defaultOpen`.
276
437
 
277
438
  ```tsx
278
- import { Card } from '@k8ordo/ui';
439
+ <SideNav.Group title="Components">
440
+ <SideNav.Link href="/components">Overview</SideNav.Link>
441
+ <SideNav.Sub defaultOpen title="Buttons">
442
+ <SideNav.Link current href="/button">
443
+ Button
444
+ </SideNav.Link>
445
+ </SideNav.Sub>
446
+ <SideNav.Sub title="Navigation">
447
+ <SideNav.Link href="/tabs">Tabs</SideNav.Link>
448
+ </SideNav.Sub>
449
+ </SideNav.Group>
450
+ ```
279
451
 
280
- // 静的カード
281
- <Card width="full" variant="shadow">
282
- <div className="p-6">コンテンツ</div>
283
- </Card>
452
+ Props (SideNav.Group):
284
453
 
285
- // クリック可能なカード(hover:scale-[1.02], active:scale-[0.98])
286
- <Card variant="outline" interactive>
287
- <div className="p-6">コンテンツ</div>
288
- </Card>
289
- ```
454
+ - `title`: `string` (required)
455
+ - `children`: `ReactNode`
290
456
 
291
- Props:
457
+ Props (SideNav.Sub):
292
458
 
459
+ - `title`: `string` (required)
293
460
  - `children`: `ReactNode`
294
- - `interactive`: `boolean`(既定: `false`)
295
- - `variant`: `'shadow'` | `'outline'`(既定: `'shadow'`)
296
- - `width`: `'full'` | `'fit'`(既定: `'full'`)
461
+ - `defaultOpen`: `boolean` (default: `false`)
297
462
 
298
- ### Separator
463
+ Props (SideNav.Link):
299
464
 
300
- 区切り線。
465
+ - `children`: `ReactNode` (required)
466
+ - `href`: `T` (required)
467
+ - `current`: `boolean` (default: `false`)
468
+ - `renderAnchor`: `(props: RenderSideNavAnchorProps<T>) => ReactNode` (default: `defaultRenderAnchor`)
469
+ - Other props are forwarded to `AnchorHTMLAttributes<HTMLAnchorElement>`, except `className` / `style` / `aria-current`.
470
+
471
+ ### TableOfContents
472
+
473
+ The contents of the page, with the heading being read marked
474
+ (`aria-current="location"`). Pass the headings as a tree of `{ id, label,
475
+ children? }`; each item links to `#id`.
301
476
 
302
477
  ```tsx
303
- import { Separator } from '@k8ordo/ui';
478
+ import { TableOfContents } from '@k8ordo/ui';
304
479
 
305
- <Separator />
306
- <Separator color="mute" />
307
- <Separator color="subtle" />
308
- <Separator orientation="vertical" />
480
+ <TableOfContents
481
+ items={[
482
+ { id: 'install', label: 'Install' },
483
+ {
484
+ id: 'usage',
485
+ label: 'Usage',
486
+ children: [{ id: 'usage-basic', label: 'Basics' }],
487
+ },
488
+ ]}
489
+ />;
309
490
  ```
310
491
 
492
+ - The heading being read is the last one whose start has passed the heading's
493
+ own `scroll-margin-block-start`: set the margin your sticky header needs on
494
+ the headings, and a heading reached from the contents becomes the current
495
+ one. At the end of the document, the last heading is current even if its
496
+ section is too short to reach that line.
497
+ - It follows the document's scroll: the headings are expected to scroll with
498
+ the page, and `items` to be in document order. It measures on scroll, on
499
+ resize, and when the page's size changes. In a vertical document it reads
500
+ from right to left (`vertical-rl`) or left to right (`vertical-lr`).
501
+ - `label` replaces the title (`tableOfContents` in the message dictionary),
502
+ which also names the `nav`.
503
+
311
504
  Props:
312
505
 
313
- - `color`: `'base'` | `'mute'` | `'subtle'`(既定: `'base'`)
314
- - `orientation`: `'horizontal'` | `'vertical'`(既定: `'horizontal'`)
506
+ - `items`: `readonly TableOfContentsItem[]` (required)
507
+ - `label`: `string`
508
+ - Other props are forwarded to `HTMLAttributes<HTMLElement>`, except `className` / `style` / `children` / `aria-labelledby`.
315
509
 
316
- ### ScrollLinked
510
+ ### Tabs
317
511
 
318
- スクロール進捗をプログレスバーで表示。
512
+ Tab switching, as a compound component.
319
513
 
320
514
  ```tsx
321
- import { ScrollLinked } from '@k8ordo/ui';
515
+ import { Tabs } from '@k8ordo/ui';
322
516
 
323
- <ScrollLinked />
324
- <ScrollLinked container={containerRef} />
517
+ <Tabs.Root ids={['tab1', 'tab2']}>
518
+ <Tabs.List label="Tabs">
519
+ <Tabs.Tab id="tab1">Tab 1</Tabs.Tab>
520
+ <Tabs.Tab id="tab2">Tab 2</Tabs.Tab>
521
+ </Tabs.List>
522
+ <Tabs.Panel id="tab1">Panel 1</Tabs.Panel>
523
+ <Tabs.Panel id="tab2">Panel 2</Tabs.Panel>
524
+ </Tabs.Root>;
325
525
  ```
326
526
 
327
- Props:
527
+ Selecting a tab is a transition: the panels cross-fade through React's
528
+ `<ViewTransition>` (off under `prefers-reduced-motion`), and a panel that
529
+ suspends keeps the current one on screen until it is ready.
328
530
 
329
- - `container`: `RefObject<HTMLElement | null>`
531
+ The keys follow the WAI-ARIA tabs pattern, and focusing a tab selects it.
532
+ `ArrowLeft` / `ArrowRight` move to the previous / next tab, wrapping at the
533
+ ends, and swap under `dir="rtl"`; in vertical writing mode the list is
534
+ vertical and `ArrowUp` / `ArrowDown` do the same. `Home` / `End` go to the
535
+ first / last tab.
330
536
 
331
- ### Stack
537
+ Props (Tabs.Root):
332
538
 
333
- 縦横一方向に並べるレイアウト。`gap` はスペーシングトークンから選ぶ。
539
+ - `ids`: `[string, ...string[]]` (required)
540
+ - `children`: `ReactNode`
541
+ - `defaultSelectedId`: `string` | `null` (default: `null`)
542
+ - `onChange`: `(id: string) => void`
543
+ - `selectedId`: `string`
334
544
 
335
- ```tsx
336
- import { Stack } from '@k8ordo/ui';
545
+ Props (Tabs.List):
337
546
 
338
- <Stack gap="lg">
339
- <Card>1</Card>
340
- <Card>2</Card>
341
- </Stack>
547
+ - `label`: `string` (required)
548
+ - `children`: `ReactNode`
342
549
 
343
- <Stack direction="row" justify="between" align="center">
344
- <Heading level="h2">タイトル</Heading>
345
- <Button>操作</Button>
346
- </Stack>
347
- ```
550
+ Props (Tabs.Panel):
348
551
 
349
- Props:
552
+ - `id`: `string` (required)
553
+ - `children`: `ReactNode`
350
554
 
351
- - `align`: `'start'` | `'center'` | `'end'` | `'stretch'`
555
+ Props (Tabs.Tab):
556
+
557
+ - `id`: `string` (required)
352
558
  - `children`: `ReactNode`
353
- - `direction`: `'row'` | `'column'`(既定: `'column'`)
354
- - `gap`: `GapSize`(既定: `'md'`)
355
- - `justify`: `'start'` | `'center'` | `'end'` | `'between'`
356
- - `padding`: `PaddingSize`
357
559
 
358
- ### Grid
560
+ ### Anchor
359
561
 
360
- グリッドレイアウト。`cols` に `'auto-fill'` / `'auto-fit'` を渡すと `minItemSize` を下限に折り返す。
562
+ A text link. External links automatically get a new-tab icon.
361
563
 
362
564
  ```tsx
363
- import { Grid } from '@k8ordo/ui';
364
-
365
- <Grid cols={3} gap="md">
366
- <Card>1</Card>
367
- <Card>2</Card>
368
- <Card>3</Card>
369
- </Grid>
565
+ import { Anchor } from '@k8ordo/ui';
370
566
 
371
- <Grid cols="auto-fill" minItemSize={64}>
372
- {items.map((item) => (
373
- <Card key={item.id}>{item.name}</Card>
374
- ))}
375
- </Grid>
567
+ <Anchor href="https://example.com">External link</Anchor>
568
+ <Anchor href="/about">Internal link</Anchor>
569
+ <Anchor href="/docs" openInNewTab>Open in a new tab</Anchor>
376
570
  ```
377
571
 
378
572
  Props:
379
573
 
380
- - `children`: `ReactNode`
381
- - `cols`: `1` | `2` | `3` | `4` | `5` | `6` | `'auto-fill'` | `'auto-fit'`(既定: `'auto-fill'`)
382
- - `gap`: `GapSize`(既定: `'md'`)
383
- - `minItemSize`: `24` | `32` | `40` | `48` | `64` | `80`(既定: `48`)
574
+ - `children`: `ReactNode` (required)
575
+ - `href`: `T` (required)
576
+ - `openInNewTab`: `boolean` (default: `false`)
577
+ - `renderAnchor`: `(props: RenderAnchorProps<T>) => ReactNode` (default: `defaultRenderAnchor`)
578
+ - Other props are forwarded to `AnchorHTMLAttributes<HTMLAnchorElement>`, except `target` / `rel` / `className` / `style`.
579
+
580
+ `renderAnchor` replaces the `<a>`; its bag is described under
581
+ [Render props](#render-props).
384
582
 
385
- ## フォーム
583
+ ## Forms
386
584
 
387
- フォームコンポーネントは `FormControl` の `renderInput` パターンと組み合わせて使用する。各フォームコンポーネントは controlled / uncontrolled の両方に対応。
585
+ Form components are used together with `FormControl`'s `renderInput` pattern. Every form component except `FileField` supports both controlled and uncontrolled use; `FileField.Root` takes only `defaultValue` and keeps the selected files itself.
388
586
 
389
- `ref` は実要素(`input` / `textarea` / `select` / `fieldset`)に届く。内部で ref を使う `Textarea` / `FileField` も内部 ref と合成されるため、`react-hook-form` の `register()` などをそのまま渡せる。`Radio`(複数の input を描くグループ)と `FormControl`(ラッパー)は `ref` を受け取らない。
587
+ `ref` reaches the real element (`input` / `textarea` / `select` / `fieldset`). `FileField` uses a ref internally but composes it with yours, so the `ref` you pass still reaches the element. `Radio` (a group that renders several inputs) puts its `ref` on the radiogroup `<div>`, and `FormControl` (a wrapper) on its wrapper element — a `<div>`, or a `<fieldset>` with `labelAs="legend"`.
588
+
589
+ An uncontrolled field keeps its value in the DOM, so a form reset — `form.reset()`, a reset button, or React resetting the form after an action — puts it back to its `defaultValue`, and a `defaultValue` that changes after mount (the values a failed submission echoes back) is where the next reset goes. A value a component changes in code (a stepper, a chosen option, a removed file) is announced with an `input` event, so a form library listening on the `<form>` hears it like typing.
590
+
591
+ Every field takes the attributes `@k8ordo/form`'s `formFields` derives as they are — spread `field.input` after `FormControl`'s props. Its guide's "Working with @k8ordo/ui" section has one example per component.
390
592
 
391
593
  ### Form
392
594
 
393
- `<form>` のラッパー。`action` には Server Action(`(formData) => …`)も URL 文字列も渡せる。
595
+ A wrapper for `<form>`. `action` accepts a Server Action (`(formData) => …`) or a URL string.
394
596
 
395
597
  ```tsx
396
598
  import { Button, Form, FormControl, TextField } from '@k8ordo/ui';
397
599
 
398
600
  <Form action={submitAction}>
399
601
  <FormControl
400
- label="メール"
602
+ label="Email"
401
603
  required
402
604
  renderInput={(props) => <TextField {...props} name="email" />}
403
605
  />
404
- <Button type="submit">送信</Button>
606
+ <Button type="submit">Submit</Button>
405
607
  </Form>;
406
608
  ```
407
609
 
408
610
  Props:
409
611
 
410
- - `children`: `ReactNode`(必須)
612
+ - `children`: `ReactNode` (required)
411
613
  - `action`: `((formData: FormData) => void | Promise<void>)` | `string`
614
+ - `ref`: `Ref<HTMLFormElement>`
615
+ - Other props are forwarded to `FormHTMLAttributes<HTMLFormElement>`, except `className` / `style`.
412
616
 
413
617
  ### FormControl
414
618
 
415
- フォームフィールドのラッパー。ラベル・ヘルプテキスト・エラー表示を統一する。
619
+ A wrapper for a form field. It unifies the label, help text, and error display.
416
620
 
417
621
  ```tsx
418
622
  import { FormControl, TextField } from '@k8ordo/ui';
419
623
 
420
624
  <FormControl
421
- label="メールアドレス"
422
- errorText="入力してください"
423
- helpText="会社のメールアドレスを入力してください"
625
+ label="Email address"
626
+ errorText="This field is required"
627
+ helpText="Enter your work email address"
424
628
  required
425
629
  renderInput={(props) => (
426
630
  <TextField {...props} placeholder="example@mail.com" />
@@ -430,19 +634,20 @@ import { FormControl, TextField } from '@k8ordo/ui';
430
634
 
431
635
  Props:
432
636
 
433
- - `label`: `string`(必須)
434
- - `renderInput`: `(props: { id: string; 'aria-describedby': string | undefined; 'aria-labelledby': string; disabled: boolean; invalid: boolean; required: boolean; }) => ReactElement`(必須)
435
- - `disabled`: `boolean`(既定: `false`)
637
+ - `label`: `string` (required)
638
+ - `renderInput`: `(props: { id: string; 'aria-describedby': string | undefined; 'aria-labelledby': string; disabled: boolean; invalid: boolean; required: boolean; }) => ReactElement` (required)
639
+ - `disabled`: `boolean` (default: `false`)
436
640
  - `errorText`: `string`
437
641
  - `helpText`: `string`
438
- - `invalid`: `boolean`(既定: `false`)
439
- - `labelAs`: `'label'` | `'legend'`(既定: `'label'`)
642
+ - `invalid`: `boolean` (default: `false`)
643
+ - `labelAs`: `'label'` | `'legend'` (default: `'label'`)
440
644
  - `ref`: `Ref<HTMLElement>`
441
- - `required`: `boolean`(既定: `false`)
645
+ - `required`: `boolean` (default: `false`)
646
+ - Other props are forwarded to `HTMLAttributes<HTMLElement>`, except `className` / `style` / `children`.
442
647
 
443
- `renderInput` は `{ id, 'aria-describedby', 'aria-labelledby', disabled, invalid, required }` を受け取る。
648
+ `renderInput` receives `{ id, 'aria-describedby', 'aria-labelledby', disabled, invalid, required }`.
444
649
 
445
- ラッパー要素は `labelAs` で変わる。`'label'`(既定)は `<div>` + `<label htmlFor>`、`'legend'` は `<fieldset>` + `<legend>`。単一フィールドを名前の無いグループにしないため、`<fieldset>` は `legend` のときだけ使う。`Radio` / `CheckboxGroup` のようなグループ入力を包むときは `labelAs="legend"` を指定する。
650
+ The wrapper element depends on `labelAs`. `'label'` (the default) gives `<div>` + `<label htmlFor>`; `'legend'` gives `<fieldset>` + `<legend>`. `<fieldset>` is used only for `legend`, so that a single field never becomes an unnamed group. Pass `labelAs="legend"` when wrapping a group input such as `Radio` or `CheckboxGroup`.
446
651
 
447
652
  ### TextField
448
653
 
@@ -457,16 +662,23 @@ import { TextField } from '@k8ordo/ui';
457
662
  <TextField id="email" value={value} onChange={onChange}
458
663
  invalid={false} disabled={false} required={false} />
459
664
 
460
- // type も渡せる(デフォルト: "text")
665
+ // type can be passed too (default: "text")
461
666
  <TextField id="tel" type="tel" inputMode="numeric" />
667
+
668
+ // date and time inputs render as the browser's own pickers
669
+ <TextField id="birthday" type="date" />
462
670
  ```
463
671
 
672
+ `type` also accepts any string, so the `type` `@k8ordo/form` derives
673
+ (`email`, `url`, `date`, `time`, `datetime-local`, …) spreads as it is.
674
+
464
675
  Props:
465
676
 
466
677
  - `children`: `ReactNode`
467
- - `invalid`: `boolean`(既定: `false`)
678
+ - `invalid`: `boolean` (default: `false`)
468
679
  - `ref`: `Ref<HTMLInputElement>`
469
- - `type`: `TextInputType`(既定: `'text'`)
680
+ - `type`: `'date'` | `'datetime-local'` | `'email'` | `'month'` | `'search'` | `'tel'` | `'text'` | `'time'` | `'url'` | `'week'` | `(string & Record<never, never>)` (default: `'text'`)
681
+ - Other props are forwarded to `InputHTMLAttributes<HTMLInputElement>`, except `className` / `style`.
470
682
 
471
683
  ### Textarea
472
684
 
@@ -485,44 +697,187 @@ import { Textarea } from '@k8ordo/ui';
485
697
 
486
698
  Props:
487
699
 
488
- - `autoResize`: `boolean`(既定: `false`)
700
+ - `autoResize`: `boolean` (default: `false`)
489
701
  - `children`: `ReactNode`
490
- - `fullHeight`: `boolean`(既定: `false`)
491
- - `invalid`: `boolean`(既定: `false`)
702
+ - `fullHeight`: `boolean` (default: `false`)
703
+ - `invalid`: `boolean` (default: `false`)
492
704
  - `ref`: `Ref<HTMLTextAreaElement>`
705
+ - `type`: `string`
706
+ - Other props are forwarded to `TextareaHTMLAttributes<HTMLTextAreaElement>`, except `className` / `style`.
707
+
708
+ `type` is accepted and dropped: a `<textarea>` has none, and the attributes
709
+ `@k8ordo/form` derives for a string carry `type="text"`. A `pattern` is not
710
+ checked by the browser on a `<textarea>` either.
493
711
 
494
712
  ### NumberField
495
713
 
496
714
  ```tsx
497
715
  import { NumberField } from '@k8ordo/ui';
498
716
 
717
+ // Uncontrolled: starts empty unless defaultValue is given
718
+ <NumberField
719
+ id="quantity"
720
+ name="quantity"
721
+ min={0}
722
+ max={100}
723
+ invalid={false}
724
+ disabled={false}
725
+ required={false}
726
+ />;
727
+
728
+ // Controlled: null is an empty field
729
+ const [value, setValue] = useState<number | null>(null);
499
730
  <NumberField
500
731
  id="quantity"
501
732
  min={0}
502
733
  max={100}
503
734
  value={value}
504
- onChange={onChange}
735
+ onChange={setValue}
505
736
  invalid={false}
506
737
  disabled={false}
507
738
  required={false}
508
739
  />;
509
740
  ```
510
741
 
742
+ An empty field is `null`, never `0`. While empty the input submits `''` and
743
+ has no `aria-valuenow`, and leaving it keeps it empty; clearing the field
744
+ reports `null` to `onChange`. The first ArrowUp / ArrowDown or stepper press on
745
+ an empty field fills in `0`, or the nearer of `min` / `max` when `0` is out of
746
+ range. `required` reaches the input itself, so an empty required field fails
747
+ native validation.
748
+
749
+ The input is `type="text"` (so it can format to `precision` and step with the
750
+ arrow keys), which the browser does not range-check — so the field does it: a
751
+ value below `min` or above `max` is reported with `setCustomValidity`, using
752
+ the `numberFieldRangeUnderflow` / `numberFieldRangeOverflow` wording. Leaving the
753
+ field clamps the value into range. A message set by someone else on the same
754
+ input — a form library's cross-field rule — is left alone.
755
+
756
+ `min`, `max`, and an uncontrolled `defaultValue` also take strings, and `step`
757
+ takes `'any'`, which is what `@k8ordo/form` derives. `precision` defaults to the
758
+ number of decimals in `step`; with `step="any"` the value is not rounded.
759
+
760
+ A value the field writes itself — an arrow key, a stepper press, formatting on
761
+ blur — is announced with one `input` event, and `onChange` is still called once.
762
+
763
+ A form reset — `form.reset()`, a reset button, or React resetting the form after
764
+ an action — puts an uncontrolled field back to `defaultValue` (or to empty) and
765
+ reports that value to `onChange`. A controlled field keeps its `value`; reset
766
+ your own state from the form's `onReset`.
767
+
511
768
  Props:
512
769
 
513
- - `defaultValue`: `never`
514
- - `invalid`: `boolean`(既定: `false`)
515
- - `max`: `number`(既定: `9_007_199_254_740_991`)
516
- - `min`: `number`(既定: `-9_007_199_254_740_991`)
517
- - `onChange`: `(value: number) => void`
518
- - `precision`: `number`(既定: `0`)
770
+ - `defaultValue`: `number` | `string`
771
+ - `invalid`: `boolean` (default: `false`)
772
+ - `max`: `number` | `string`
773
+ - `min`: `number` | `string`
774
+ - `onChange`: `(value: number | null) => void`
775
+ - `precision`: `number`
519
776
  - `ref`: `Ref<HTMLInputElement>`
520
- - `step`: `number`(既定: `1`)
521
- - `value`: `number`
777
+ - `step`: `number` | `'any'` (default: `1`)
778
+ - `value`: `number` | `null`
779
+ - Other props are forwarded to `InputHTMLAttributes<HTMLInputElement>`, except `type` / `role` / `className` / `style` / `children`.
780
+
781
+ ### DateField
782
+
783
+ A native `<input type="date">` styled like `TextField`. The value is a
784
+ `YYYY-MM-DD` string (`''` when empty), and the browser checks `min` / `max` /
785
+ `required` itself. `onChange` is the native event, as with `TextField`.
786
+
787
+ It accepts what `@k8ordo/form` derives from `z.iso.date()` as is: spread the
788
+ field's `input` and nothing needs to be taken out. `type` is always `date`, so a
789
+ `type` in the spread does not replace it.
790
+
791
+ ```tsx
792
+ import { DateField, FormControl } from '@k8ordo/ui';
793
+
794
+ const eventDate = form.field('eventDate'); // z.iso.date()
795
+
796
+ <FormControl
797
+ errorText={eventDate.error}
798
+ invalid={eventDate.invalid}
799
+ label="Date"
800
+ required={eventDate.required}
801
+ renderInput={(props) => <DateField {...props} {...eventDate.input} />}
802
+ />;
803
+ ```
804
+
805
+ Props:
806
+
807
+ - `invalid`: `boolean` (default: `false`)
808
+ - `ref`: `Ref<HTMLInputElement>`
809
+ - Other props are forwarded to `InputHTMLAttributes<HTMLInputElement>`, except `className` / `style` / `type` / `children`.
810
+
811
+ ### DatePicker
812
+
813
+ `DateField` with a button that opens `Calendar` in a popover. The field is the
814
+ same native `<input type="date">`, so typing a date, `name`, `required`, and
815
+ `min` / `max` all work as they do on `DateField`, and spreading a derived
816
+ `@k8ordo/form` field works the same way. `onChange` takes the value
817
+ (`YYYY-MM-DD`, `''` when cleared), not the event, because a date picked from the
818
+ calendar has no input event of its own.
819
+
820
+ Picking a date writes it into the input and dispatches an `input` event, so a
821
+ form sees it exactly as if it had been typed (dirty state, rules, and clearing
822
+ an error). The popover closes and focus returns to the calendar button.
823
+
824
+ Firefox draws its own calendar button inside every `<input type="date">` and
825
+ offers no way to hide it, so there the field shows two calendar buttons: the
826
+ browser's and this component's. Chromium and Safari show only this one.
827
+
828
+ ```tsx
829
+ import { DatePicker } from '@k8ordo/ui';
830
+
831
+ <DatePicker
832
+ aria-label="Check-in"
833
+ min="2026-01-01"
834
+ name="checkIn"
835
+ onChange={setCheckIn}
836
+ value={checkIn}
837
+ />;
838
+ ```
839
+
840
+ Props:
841
+
842
+ - `defaultValue`: `string`
843
+ - `invalid`: `boolean` (default: `false`)
844
+ - `onChange`: `(value: string) => void`
845
+ - `ref`: `Ref<HTMLInputElement>`
846
+ - `value`: `string`
847
+ - Other props are forwarded to `InputHTMLAttributes<HTMLInputElement>`, except `className` / `style` / `type` / `children`.
848
+
849
+ ### Calendar
850
+
851
+ A month grid for picking one day (the WAI-ARIA date picker grid). The value is
852
+ a `YYYY-MM-DD` string. Arrow keys move by day and week, `Home` / `End` to the
853
+ ends of the week, `PageUp` / `PageDown` by month (with `Shift`, by year), and
854
+ `Enter` / `Space` select. Days outside `min` / `max` stay focusable but cannot
855
+ be selected.
856
+
857
+ Month and weekday names, and the first day of the week, follow the same locale
858
+ as the built-in wording (i18n, below). Today is marked with
859
+ `aria-current="date"` in the visitor's time zone, which only the browser knows,
860
+ so the calendar renders in the browser alone: the server writes an empty box of
861
+ the same size. It submits nothing; inside a form, use `DatePicker` or
862
+ `DateField`.
863
+
864
+ ```tsx
865
+ import { Calendar } from '@k8ordo/ui';
866
+
867
+ <Calendar defaultValue="2026-09-25" max="2026-12-31" onChange={setDay} />;
868
+ ```
869
+
870
+ Props:
871
+
872
+ - `defaultValue`: `string`
873
+ - `max`: `string`
874
+ - `min`: `string`
875
+ - `onChange`: `(value: string) => void`
876
+ - `value`: `string` | `null`
522
877
 
523
878
  ### PasswordInput
524
879
 
525
- パスワード入力。表示/非表示トグル付き。
880
+ A password input, with a show/hide toggle.
526
881
 
527
882
  ```tsx
528
883
  import { PasswordInput } from '@k8ordo/ui';
@@ -534,8 +889,8 @@ import { PasswordInput } from '@k8ordo/ui';
534
889
  invalid={false}
535
890
  disabled={false}
536
891
  required={false}
537
- showLabel="表示"
538
- hideLabel="非表示"
892
+ showLabel="Show"
893
+ hideLabel="Hide"
539
894
  />;
540
895
  ```
541
896
 
@@ -543,9 +898,13 @@ Props:
543
898
 
544
899
  - `children`: `ReactNode`
545
900
  - `hideLabel`: `string`
546
- - `invalid`: `boolean`(既定: `false`)
901
+ - `invalid`: `boolean` (default: `false`)
547
902
  - `ref`: `Ref<HTMLInputElement>`
548
903
  - `showLabel`: `string`
904
+ - Other props are forwarded to `InputHTMLAttributes<HTMLInputElement>`, except `type` / `className` / `style`.
905
+
906
+ A spread `type="password"` (what `@k8ordo/form` derives for a password) does not
907
+ override the show/hide toggle.
549
908
 
550
909
  ### Select
551
910
 
@@ -555,8 +914,8 @@ import { Select } from '@k8ordo/ui';
555
914
  <Select
556
915
  id="category"
557
916
  options={[
558
- { value: '1', label: 'オプション1' },
559
- { value: '2', label: 'オプション2' },
917
+ { value: '1', label: 'Option 1' },
918
+ { value: '2', label: 'Option 2' },
560
919
  ]}
561
920
  value={value}
562
921
  onChange={onChange}
@@ -568,14 +927,33 @@ import { Select } from '@k8ordo/ui';
568
927
 
569
928
  Props:
570
929
 
571
- - `options`: `readonly Option[]`(必須)
930
+ - `options`: `readonly Option[]` (required)
572
931
  - `children`: `ReactNode`
573
- - `invalid`: `boolean`(既定: `false`)
932
+ - `invalid`: `boolean` (default: `false`)
574
933
  - `ref`: `Ref<HTMLSelectElement>`
934
+ - Other props are forwarded to `SelectHTMLAttributes<HTMLSelectElement>`, except `className` / `style`.
935
+
936
+ React applies a `<select>`'s `defaultValue` only when it mounts; `Select` also
937
+ applies a later one, so the next reset — React's after a form action included —
938
+ goes back to it. With `required`, put a placeholder option whose `value` is
939
+ `''` first; leaving it selected fails validation.
575
940
 
576
941
  ### Autocomplete
577
942
 
578
- 複数選択のオートコンプリート。`value` / `onChange` は `string[]`。
943
+ A multi-select autocomplete over a fixed list of options, shown as removable
944
+ tags. `value` and `onChange` are `string[]`. To pick one option, or to search a
945
+ list that lives on a server, use `Combobox`.
946
+
947
+ Typing filters `options` by label. `ArrowDown` / `ArrowUp` open the list and
948
+ move through it, `Enter` adds or removes the active option, `Backspace` in an
949
+ empty field removes the last tag, and `Escape` closes the list. Keys pressed
950
+ while an IME is composing belong to the IME.
951
+
952
+ With a `name`, the selection is submitted through a visually hidden
953
+ `<select multiple>`: one entry per selected value, and `required` means at
954
+ least one. It is always present — nothing selected included — so native
955
+ validation and a form library's rules reach it, and when a form moves focus to
956
+ it after a failure, focus goes on to the text input.
579
957
 
580
958
  ```tsx
581
959
  import { Autocomplete } from '@k8ordo/ui';
@@ -593,96 +971,227 @@ import { Autocomplete } from '@k8ordo/ui';
593
971
 
594
972
  Props:
595
973
 
596
- - `id`: `string`(必須)
597
- - `options`: `readonly Option[]`(必須)
598
- - `defaultValue`: `never`
599
- - `invalid`: `boolean`(既定: `false`)
974
+ - `id`: `string` (required)
975
+ - `options`: `readonly Option[]` (required)
976
+ - `defaultValue`: `string[]`
977
+ - `invalid`: `boolean` (default: `false`)
600
978
  - `onChange`: `(value: string[]) => void`
601
979
  - `ref`: `Ref<HTMLInputElement>`
602
980
  - `value`: `string[]`
981
+ - Other props are forwarded to `InputHTMLAttributes<HTMLInputElement>`, except `type` / `role` / `className` / `style` / `children` / `autoComplete` / `aria-autocomplete` / `aria-controls` / `aria-expanded` / `aria-activedescendant`.
982
+
983
+ ### ColorPicker
984
+
985
+ A color field whose value is `#rrggbb`. The value lives in a text input that
986
+ carries `name`, so it submits and resets like any other field; hue, saturation,
987
+ and lightness sliders and optional `swatches` (toggle buttons named by their
988
+ `label`) write into it and announce the change with an `input` event, as if it
989
+ had been typed. The color chip beside the text input is a native
990
+ `<input type="color">`, named by the built-in `colorPickerOpen` wording: pressing
991
+ it opens the browser's own color picker, which writes into the text input the
992
+ same way, while it is dragged too. It carries no `name`, so only the text input
993
+ submits; with no color yet it opens on the sliders' gray. The chip, sliders,
994
+ and swatches are all disabled while the field is `disabled`, `readOnly`, or its
995
+ form is pending. Typing reports a color only once it has six digits; on blur and
996
+ on Enter the text is tidied to lowercase `#rrggbb`, and a three-digit `#f80` is
997
+ expanded. Emptying the field reports `''`. Spread `@k8ordo/form`'s `input` onto
998
+ it as is: a `.regex()` in the schema arrives as `pattern` and replaces the
999
+ built-in `#[0-9a-fA-F]{6}`. The panel stays horizontal inside vertical writing
1000
+ mode.
1001
+
1002
+ ```tsx
1003
+ import { ColorPicker, FormControl } from '@k8ordo/ui';
1004
+
1005
+ <FormControl
1006
+ label="Accent color"
1007
+ renderInput={(props) => (
1008
+ <ColorPicker
1009
+ {...props}
1010
+ defaultValue="#0d9488"
1011
+ name="accent"
1012
+ swatches={[
1013
+ { value: '#0d9488', label: 'Teal' },
1014
+ { value: '#f97316', label: 'Orange' },
1015
+ ]}
1016
+ />
1017
+ )}
1018
+ />;
1019
+ ```
1020
+
1021
+ Props:
1022
+
1023
+ - `defaultValue`: `string`
1024
+ - `invalid`: `boolean` (default: `false`)
1025
+ - `onChange`: `(value: string) => void`
1026
+ - `ref`: `Ref<HTMLInputElement>`
1027
+ - `swatches`: `readonly ColorPickerSwatch[]`
1028
+ - `type`: `string`
1029
+ - `value`: `string`
1030
+ - Other props are forwarded to `InputHTMLAttributes<HTMLInputElement>`, except `className` / `style` / `children`.
1031
+
1032
+ ### Combobox
1033
+
1034
+ A text field with a list of options, for picking one (the WAI-ARIA combobox
1035
+ with list autocomplete and manual selection). `value` and `onChange` are the
1036
+ chosen option's `value`, `''` when nothing is chosen. To pick several from a
1037
+ fixed list, use `Autocomplete`.
1038
+
1039
+ Typing opens the list; nothing is chosen until an option is picked with a click
1040
+ or `Enter`, so leaving half-typed text puts the chosen option's label back, and
1041
+ leaving the field empty clears the choice. `ArrowDown` / `ArrowUp` open the list
1042
+ and move through it (`Alt+ArrowDown` opens it without entering it), `Escape`
1043
+ closes it and, pressed again, drops what was typed. Keys pressed while an IME is
1044
+ composing belong to the IME.
1045
+
1046
+ Without `search`, typing filters `options` by label. With `search`, typing
1047
+ calls it for the options instead — each call gets a `signal` that aborts when
1048
+ the text changes again, so pass it to `fetch` — and `options` becomes the list
1049
+ shown before anything is typed and where the current value's label is looked
1050
+ up. While a search runs, the list is marked busy; a failed one says so with
1051
+ `comboboxFailed`, an empty result with `comboboxEmpty`.
1052
+
1053
+ With a `name`, the choice is submitted through a visually hidden `<select>`, the
1054
+ same way `Autocomplete` submits, so `required`, a form library's rules, reset,
1055
+ and moving focus to the field after a failure all work on it.
1056
+
1057
+ ```tsx
1058
+ import { Combobox } from '@k8ordo/ui';
1059
+
1060
+ <Combobox aria-label="Prefecture" name="prefecture" options={prefectures} />;
1061
+
1062
+ // Options from a server
1063
+ <Combobox
1064
+ aria-label="City"
1065
+ name="city"
1066
+ search={async (query, { signal }) => {
1067
+ const response = await fetch(`/api/cities?q=${encodeURIComponent(query)}`, {
1068
+ signal,
1069
+ });
1070
+ return response.json();
1071
+ }}
1072
+ />;
1073
+ ```
1074
+
1075
+ Props:
1076
+
1077
+ - `defaultValue`: `string`
1078
+ - `invalid`: `boolean` (default: `false`)
1079
+ - `onChange`: `(value: string) => void`
1080
+ - `options`: `readonly Option[]`
1081
+ - `ref`: `Ref<HTMLInputElement>`
1082
+ - `search`: `ComboboxSearch`
1083
+ - `type`: `string`
1084
+ - `value`: `string`
1085
+ - Other props are forwarded to `InputHTMLAttributes<HTMLInputElement>`, except `role` / `className` / `style` / `children` / `autoComplete` / `aria-autocomplete` / `aria-controls` / `aria-expanded` / `aria-activedescendant`.
603
1086
 
604
1087
  ### Checkbox
605
1088
 
606
- ラベルは `label` prop で渡す(children ではない)。`onChange` は `(checked, event)`。
1089
+ The label is passed as the `label` prop, not as children. `onChange` is `(checked, event)`.
1090
+
1091
+ `itemValue` is the input's `value`: the string a checked box submits under its `name`. Without it the box renders no `value` and submits the browser's default, `on`. There is no `value` prop — on a checkbox it is easily mistaken for the checked state, which is `checked`.
607
1092
 
608
1093
  ```tsx
609
1094
  import { Checkbox } from '@k8ordo/ui';
610
1095
 
611
1096
  // Controlled
612
- <Checkbox checked={checked} label="同意する" onChange={onChange} />
1097
+ <Checkbox checked={checked} label="I agree" onChange={onChange} />
613
1098
 
614
1099
  // Uncontrolled
615
- <Checkbox defaultChecked label="同意する" />
1100
+ <Checkbox defaultChecked label="I agree" />
1101
+
1102
+ // Submits inStock=true when checked, instead of inStock=on
1103
+ <Checkbox itemValue="true" label="In stock only" name="inStock" />
616
1104
  ```
617
1105
 
1106
+ `indeterminate` shows the mixed state — some of a set selected — and sets the
1107
+ input's `indeterminate` property, so it is announced as partly checked.
1108
+ `labelHidden` keeps `label` as the accessible name but does not draw it, for a
1109
+ place with no room for text such as a table cell.
1110
+
618
1111
  Props:
619
1112
 
620
- - `label`: `string`(必須)
1113
+ - `label`: `string` (required)
621
1114
  - `checked`: `boolean`
622
- - `defaultChecked`: `never`
1115
+ - `defaultChecked`: `boolean`
1116
+ - `indeterminate`: `boolean` (default: `false`)
1117
+ - `invalid`: `boolean` (default: `false`)
623
1118
  - `itemValue`: `string`
1119
+ - `labelHidden`: `boolean` (default: `false`)
624
1120
  - `onChange`: `(checked: boolean, event: ChangeEvent<HTMLInputElement>) => void`
625
1121
  - `ref`: `Ref<HTMLInputElement>`
1122
+ - Other props are forwarded to `InputHTMLAttributes<HTMLInputElement>`, except `type` / `className` / `style` / `value` / `children`.
626
1123
 
627
1124
  ### CheckboxGroup
628
1125
 
629
- 複数チェックボックスのグループ。子は `CheckboxGroup.Item`(= `Checkbox`)で、`itemValue` が必須。
1126
+ A group of checkboxes. The children are `CheckboxGroup.Item` (= `Checkbox`), and `itemValue` is required.
1127
+
1128
+ The group's selection lives in `value` / `onChange` (`string[]`). That is a different thing from a lone `Checkbox` holding a boolean in `checked` — do not conflate them.
630
1129
 
631
- グループの選択状態は `value` / `onChange`(`string[]`)で持つ。単体の `Checkbox` が真偽値を `checked` で持つのとは別物なので、混同しないこと。
1130
+ It renders a `fieldset[role="group"]`, so `aria-labelledby` is required. Convey that the group is required through the referenced label element (for example `FormControl`'s required marker). `role="group"` does not allow `aria-required`, so do not put it on the group.
632
1131
 
633
- `fieldset[role="group"]` を描くため `aria-labelledby` が必須。必須入力であることは、参照先のラベル要素(`FormControl` の必須表示など)に含めて伝える。`role="group"` は `aria-required` を許可していないので、グループ側には出さない。
1132
+ Uncontrolled, the selection lives in the checkboxes themselves: `onChange`
1133
+ receives the checked values in document order, and a form reset puts the boxes
1134
+ back to `defaultValue` without leaving a stale selection behind.
634
1135
 
635
1136
  ```tsx
636
1137
  import { CheckboxGroup } from '@k8ordo/ui';
637
1138
 
638
- <p id="interests-label">興味のある分野</p>
1139
+ <p id="interests-label">Areas of interest</p>
639
1140
  <CheckboxGroup.Root
640
1141
  aria-labelledby="interests-label"
641
1142
  name="interests"
642
1143
  value={values}
643
1144
  onChange={setValues}
644
1145
  >
645
- <CheckboxGroup.Item itemValue="music" label="音楽" />
646
- <CheckboxGroup.Item itemValue="movie" label="映画" />
1146
+ <CheckboxGroup.Item itemValue="music" label="Music" />
1147
+ <CheckboxGroup.Item itemValue="movie" label="Film" />
647
1148
  </CheckboxGroup.Root>;
648
1149
  ```
649
1150
 
650
1151
  Props (CheckboxGroup.Item):
651
1152
 
652
- - `label`: `string`(必須)
1153
+ - `label`: `string` (required)
653
1154
  - `checked`: `boolean`
654
- - `defaultChecked`: `never`
1155
+ - `defaultChecked`: `boolean`
1156
+ - `indeterminate`: `boolean` (default: `false`)
1157
+ - `invalid`: `boolean` (default: `false`)
655
1158
  - `itemValue`: `string`
1159
+ - `labelHidden`: `boolean` (default: `false`)
656
1160
  - `onChange`: `(checked: boolean, event: ChangeEvent<HTMLInputElement>) => void`
657
1161
  - `ref`: `Ref<HTMLInputElement>`
1162
+ - Other props are forwarded to `InputHTMLAttributes<HTMLInputElement>`, except `type` / `className` / `style` / `value` / `children`.
658
1163
 
659
1164
  Props (CheckboxGroup.Root):
660
1165
 
661
- - `aria-labelledby`: `string`(必須)
662
- - `name`: `string`(必須)
1166
+ - `aria-labelledby`: `string` (required)
1167
+ - `name`: `string` (required)
663
1168
  - `children`: `ReactNode`
664
- - `defaultValue`: `never`
665
- - `invalid`: `boolean`(既定: `false`)
1169
+ - `defaultValue`: `string[]`
1170
+ - `invalid`: `boolean` (default: `false`)
666
1171
  - `onChange`: `(value: string[]) => void`
667
1172
  - `ref`: `Ref<HTMLFieldSetElement>`
668
1173
  - `value`: `string[]`
1174
+ - Other props are forwarded to `FieldsetHTMLAttributes<HTMLFieldSetElement>`, except `className` / `style` / `role`.
669
1175
 
670
1176
  ### CheckboxCard
671
1177
 
672
- カードスタイルのチェックボックス。
1178
+ A card-styled checkbox. Uncontrolled, the selection and its look follow the
1179
+ checkboxes themselves (`:checked`), so a form reset restores both; `onChange`
1180
+ receives the checked values in document order.
673
1181
 
674
1182
  ```tsx
675
1183
  import { CheckboxCard } from '@k8ordo/ui';
676
1184
 
677
1185
  <CheckboxCard
1186
+ aria-labelledby="plan-checkbox"
678
1187
  name="plan"
679
1188
  disabled={false}
680
1189
  options={[
681
- { value: 'basic', label: 'ベーシック', description: '月額980円' },
1190
+ { value: 'basic', label: 'Basic', description: '$9 / month' },
682
1191
  {
683
1192
  value: 'pro',
684
- label: 'プロ',
685
- description: '月額1,980円',
1193
+ label: 'Pro',
1194
+ description: '$19 / month',
686
1195
  visual: <Icon />,
687
1196
  },
688
1197
  ]}
@@ -693,13 +1202,14 @@ import { CheckboxCard } from '@k8ordo/ui';
693
1202
 
694
1203
  Props:
695
1204
 
696
- - `aria-labelledby`: `string`(必須)
697
- - `options`: `readonly CheckboxCardOption[]`(必須)
698
- - `defaultValue`: `never`
699
- - `invalid`: `boolean`(既定: `false`)
1205
+ - `aria-labelledby`: `string` (required)
1206
+ - `options`: `readonly CheckboxCardOption[]` (required)
1207
+ - `defaultValue`: `string[]`
1208
+ - `invalid`: `boolean` (default: `false`)
700
1209
  - `onChange`: `(value: string[]) => void`
701
1210
  - `ref`: `Ref<HTMLFieldSetElement>`
702
1211
  - `value`: `string[]`
1212
+ - Other props are forwarded to `FieldsetHTMLAttributes<HTMLFieldSetElement>`, except `className` / `style` / `children` / `role`.
703
1213
 
704
1214
  ### Radio
705
1215
 
@@ -711,8 +1221,8 @@ import { Radio } from '@k8ordo/ui';
711
1221
  name="example"
712
1222
  onChange={onChange}
713
1223
  options={[
714
- { value: 'a', label: '選択肢A' },
715
- { value: 'b', label: '選択肢B' },
1224
+ { value: 'a', label: 'Choice A' },
1225
+ { value: 'b', label: 'Choice B' },
716
1226
  ]}
717
1227
  value={value}
718
1228
  />;
@@ -720,17 +1230,21 @@ import { Radio } from '@k8ordo/ui';
720
1230
 
721
1231
  Props:
722
1232
 
723
- - `aria-labelledby`: `string`(必須)
724
- - `options`: `readonly Option[]`(必須)
725
- - `disabled`: `boolean`(既定: `false`)
1233
+ - `aria-labelledby`: `string` (required)
1234
+ - `options`: `readonly Option[]` (required)
1235
+ - `defaultValue`: `string`
1236
+ - `disabled`: `boolean` (default: `false`)
1237
+ - `invalid`: `boolean` (default: `false`)
726
1238
  - `name`: `string`
727
1239
  - `onChange`: `(value: string, event: ChangeEvent<HTMLInputElement>) => void`
728
1240
  - `ref`: `Ref<HTMLDivElement>`
1241
+ - `required`: `boolean` (default: `false`)
729
1242
  - `value`: `string`
1243
+ - Other props are forwarded to `HTMLAttributes<HTMLDivElement>`, except `role` / `className` / `style` / `children`.
730
1244
 
731
1245
  ### RadioCard
732
1246
 
733
- カードスタイルのラジオボタン。`fieldset[role="radiogroup"]` の中に本物の `input[type="radio"]` を並べるため、矢印キーのローミングと単一選択はブラウザに任せている。テストからは `getByRole('radio', { checked })` で参照する。
1247
+ A card-styled radio button. Real `input[type="radio"]` elements sit inside a `fieldset[role="radiogroup"]`, so arrow-key roving and single selection are left to the browser. Reach them from tests with `getByRole('radio', { checked })`. `required` goes to every radio, and an uncontrolled selection's look follows `:checked`, so a form reset restores it.
734
1248
 
735
1249
  ```tsx
736
1250
  import { RadioCard } from '@k8ordo/ui';
@@ -740,11 +1254,11 @@ import { RadioCard } from '@k8ordo/ui';
740
1254
  name="plan"
741
1255
  disabled={false}
742
1256
  options={[
743
- { value: 'basic', label: 'ベーシック', description: '月額980円' },
1257
+ { value: 'basic', label: 'Basic', description: '$9 / month' },
744
1258
  {
745
1259
  value: 'pro',
746
- label: 'プロ',
747
- description: '月額1,980円',
1260
+ label: 'Pro',
1261
+ description: '$19 / month',
748
1262
  visual: <Icon />,
749
1263
  },
750
1264
  ]}
@@ -755,17 +1269,21 @@ import { RadioCard } from '@k8ordo/ui';
755
1269
 
756
1270
  Props:
757
1271
 
758
- - `aria-labelledby`: `string`(必須)
759
- - `options`: `readonly RadioCardOption[]`(必須)
760
- - `defaultValue`: `never`
761
- - `invalid`: `boolean`(既定: `false`)
1272
+ - `aria-labelledby`: `string` (required)
1273
+ - `options`: `readonly RadioCardOption[]` (required)
1274
+ - `defaultValue`: `string`
1275
+ - `invalid`: `boolean` (default: `false`)
762
1276
  - `onChange`: `(value: string) => void`
763
1277
  - `ref`: `Ref<HTMLFieldSetElement>`
1278
+ - `required`: `boolean` (default: `false`)
764
1279
  - `value`: `string`
1280
+ - Other props are forwarded to `FieldsetHTMLAttributes<HTMLFieldSetElement>`, except `className` / `style` / `children` / `role`.
765
1281
 
766
1282
  ### Slider
767
1283
 
768
- レンジスライダー。
1284
+ A range slider. Uncontrolled, the value lives in the input, so a form reset
1285
+ puts it back to `defaultValue` and the filled track follows. `min`, `max`, and
1286
+ an uncontrolled `defaultValue` also take strings, and `step` takes `'any'`.
769
1287
 
770
1288
  ```tsx
771
1289
  import { Slider } from '@k8ordo/ui';
@@ -784,18 +1302,62 @@ import { Slider } from '@k8ordo/ui';
784
1302
 
785
1303
  Props:
786
1304
 
787
- - `defaultValue`: `never`
788
- - `invalid`: `boolean`(既定: `false`)
789
- - `max`: `number`(既定: `100`)
790
- - `min`: `number`(既定: `0`)
1305
+ - `defaultValue`: `number` | `string`
1306
+ - `invalid`: `boolean` (default: `false`)
1307
+ - `max`: `number` | `string`
1308
+ - `min`: `number` | `string`
791
1309
  - `onChange`: `(value: number) => void`
792
1310
  - `ref`: `Ref<HTMLInputElement>`
793
- - `step`: `number`(既定: `1`)
1311
+ - `step`: `number` | `'any'` (default: `1`)
794
1312
  - `value`: `number`
1313
+ - Other props are forwarded to `InputHTMLAttributes<HTMLInputElement>`, except `type` / `className` / `style` / `children`.
1314
+
1315
+ ### RangeSlider
1316
+
1317
+ A slider with two thumbs for picking a range (the WAI-ARIA multi-thumb slider).
1318
+ Each thumb is a real `<input type="range">`, so the keyboard behaves as the
1319
+ browser's own slider does, and neither thumb can pass the other: the lower
1320
+ thumb's `aria-valuemax` is the upper value and the upper thumb's
1321
+ `aria-valuemin` the lower one. `value` / `defaultValue` / `onChange` carry the
1322
+ pair `[lower, upper]`.
1323
+
1324
+ `name` is a pair too: the two thumbs submit as two form fields. Uncontrolled,
1325
+ the thumbs keep their values in the DOM, so a form's reset and its dirty check
1326
+ (value against default value) work on them as on any input. The whole slider is
1327
+ a `role="group"`: name it with `aria-label` or `aria-labelledby`
1328
+ (`FormControl`'s `renderInput` props work), and each thumb is read as that name
1329
+ followed by the built-in `rangeSliderStart` / `rangeSliderEnd` wording.
1330
+
1331
+ ```tsx
1332
+ import { RangeSlider } from '@k8ordo/ui';
1333
+
1334
+ <RangeSlider
1335
+ aria-label="Price"
1336
+ defaultValue={[20, 80]}
1337
+ max={100}
1338
+ min={0}
1339
+ name={['priceMin', 'priceMax']}
1340
+ />;
1341
+ ```
1342
+
1343
+ Props:
1344
+
1345
+ - `defaultValue`: `readonly [number, number]`
1346
+ - `disabled`: `boolean` (default: `false`)
1347
+ - `invalid`: `boolean` (default: `false`)
1348
+ - `max`: `number` (default: `100`)
1349
+ - `min`: `number` (default: `0`)
1350
+ - `name`: `readonly [string, string]`
1351
+ - `onChange`: `(value: [number, number]) => void`
1352
+ - `ref`: `Ref<HTMLDivElement>`
1353
+ - `required`: `boolean` (default: `false`)
1354
+ - `step`: `number` (default: `1`)
1355
+ - `value`: `readonly [number, number]`
1356
+ - Other props are forwarded to `HTMLAttributes<HTMLDivElement>`, except `className` / `style` / `children` / `role`.
795
1357
 
796
1358
  ### Switch
797
1359
 
798
- トグルスイッチ。
1360
+ A toggle switch.
799
1361
 
800
1362
  ```tsx
801
1363
  import { Switch } from '@k8ordo/ui';
@@ -804,7 +1366,7 @@ import { Switch } from '@k8ordo/ui';
804
1366
  checked={checked}
805
1367
  disabled={false}
806
1368
  invalid={false}
807
- label="通知を有効にする"
1369
+ label="Enable notifications"
808
1370
  onChange={onChange}
809
1371
  required={false}
810
1372
  />;
@@ -812,16 +1374,18 @@ import { Switch } from '@k8ordo/ui';
812
1374
 
813
1375
  Props:
814
1376
 
815
- - `label`: `string`(必須)
1377
+ - `label`: `string` (required)
816
1378
  - `checked`: `boolean`
817
- - `defaultChecked`: `never`
818
- - `invalid`: `boolean`(既定: `false`)
1379
+ - `defaultChecked`: `boolean`
1380
+ - `invalid`: `boolean` (default: `false`)
819
1381
  - `onChange`: `(checked: boolean, event: ChangeEvent<HTMLInputElement>) => void`
820
1382
  - `ref`: `Ref<HTMLInputElement>`
1383
+ - Other props are forwarded to `InputHTMLAttributes<HTMLInputElement>`, except `type` / `role` / `className` / `style` / `value` / `children`.
821
1384
 
822
1385
  ### FileField
823
1386
 
824
- コンポジットパターンのファイルアップロード。
1387
+ File upload, as a composite pattern. A string `defaultValue` (the type
1388
+ `@k8ordo/form`'s derived attributes carry) is accepted and ignored.
825
1389
 
826
1390
  ```tsx
827
1391
  import { FileField } from '@k8ordo/ui';
@@ -830,7 +1394,7 @@ import { FileField } from '@k8ordo/ui';
830
1394
  <FileField.Trigger
831
1395
  renderItem={({ onClick, disabled }) => (
832
1396
  <Button onClick={onClick} disabled={disabled}>
833
- ファイルを選択
1397
+ Choose files
834
1398
  </Button>
835
1399
  )}
836
1400
  />
@@ -838,15 +1402,53 @@ import { FileField } from '@k8ordo/ui';
838
1402
  </FileField.Root>;
839
1403
  ```
840
1404
 
1405
+ `FileField.Dropzone` is an area files can be dropped onto. Left empty, it holds
1406
+ the built-in `fileFieldDrop` wording and a "choose files" button, so the field
1407
+ stays usable by keyboard; pass children to lay it out yourself (put a
1408
+ `FileField.Trigger` inside). Dropped files are added exactly like picked ones:
1409
+ they respect `multiple` and `maxFiles`, land in the input so they are
1410
+ submitted, and are announced with an `input` event so a form sees the change.
1411
+ A dropped folder is skipped (choose folders through the picker with
1412
+ `webkitDirectory`). The browser applies `accept` only to the picker, so the
1413
+ field applies it to dropped files itself, by the same rules: a file it does not
1414
+ match is left out, and a drop with nothing it matches changes nothing — no
1415
+ `onChange`, no `input` event.
1416
+
1417
+ The input holds exactly what `ItemList` lists, so what is listed is what is
1418
+ submitted:
1419
+
1420
+ - With `multiple` or `webkitDirectory`, each pick or drop adds to the list, up
1421
+ to `maxFiles`, and the input is rewritten to the whole list — the browser
1422
+ alone would keep only the files just picked. A rewrite is announced with an
1423
+ `input` event.
1424
+ - Removing a file from `ItemList` removes it from the input.
1425
+ - A `File[]` `defaultValue` is submitted as well as listed, and a form reset
1426
+ puts both back to it (to an empty list without one).
1427
+ - `onChange` receives that whole list — not only the files just picked or
1428
+ dropped — after every pick, drop, and removal. Only a pick passes the
1429
+ `event`.
1430
+
1431
+ ```tsx
1432
+ <FileField.Root accept="image/*" multiple name="photos">
1433
+ <FileField.Dropzone />
1434
+ <FileField.ItemList clearable />
1435
+ </FileField.Root>
1436
+ ```
1437
+
841
1438
  Props (Root):
842
1439
 
843
1440
  - `children`: `ReactNode`
844
- - `defaultValue`: `File[]`
845
- - `invalid`: `boolean`(既定: `false`)
1441
+ - `defaultValue`: `File[]` | `string`
1442
+ - `invalid`: `boolean` (default: `false`)
846
1443
  - `maxFiles`: `number`
847
1444
  - `onChange`: `(files: FileList | null, event?: ChangeEvent<HTMLInputElement>) => void`
848
1445
  - `ref`: `Ref<HTMLInputElement>`
849
- - `webkitDirectory`: `boolean`(既定: `false`)
1446
+ - `webkitDirectory`: `boolean` (default: `false`)
1447
+ - Other props are forwarded to `InputHTMLAttributes<HTMLInputElement>`, except `type` / `className` / `style` / `value`.
1448
+
1449
+ Props (FileField.Dropzone):
1450
+
1451
+ - `children`: `ReactNode`
850
1452
 
851
1453
  Props (FileField.ItemList):
852
1454
 
@@ -855,37 +1457,38 @@ Props (FileField.ItemList):
855
1457
 
856
1458
  Props (FileField.Trigger):
857
1459
 
858
- - `renderItem`: `(props: { onClick: () => void; disabled: boolean; invalid: boolean; }) => ReactElement`(必須)
1460
+ - `renderItem`: `(props: { onClick: () => void; disabled: boolean; invalid: boolean; }) => ReactElement` (required)
859
1461
 
860
- ## データ表示
1462
+ ## Data display
861
1463
 
862
1464
  ### Heading
863
1465
 
864
- セマンティック見出し。`type` prop で HTML 要素を指定。
1466
+ A semantic heading. The `level` prop selects the HTML element.
865
1467
 
866
1468
  ```tsx
867
1469
  import { Heading } from '@k8ordo/ui';
868
1470
 
869
- <Heading level="h1">ページタイトル</Heading>
870
- <Heading level="h2">セクション見出し</Heading>
871
- <Heading level="h3">サブセクション</Heading>
1471
+ <Heading level="h1">Page title</Heading>
1472
+ <Heading level="h2">Section heading</Heading>
1473
+ <Heading level="h3">Subsection</Heading>
872
1474
  ```
873
1475
 
874
1476
  Props:
875
1477
 
876
- - `level`: `'h1'` | `'h2'` | `'h3'` | `'h4'` | `'h5'` | `'h6'`(必須)
1478
+ - `level`: `'h1'` | `'h2'` | `'h3'` | `'h4'` | `'h5'` | `'h6'` (required)
877
1479
  - `children`: `ReactNode`
878
1480
  - `lineClamp`: `1` | `2` | `3` | `4` | `5` | `6`
1481
+ - Other props are forwarded to `HTMLAttributes<HTMLHeadingElement>`, except `className` / `style`.
879
1482
 
880
1483
  ### Avatar
881
1484
 
882
- ユーザーアバター。
1485
+ A user avatar.
883
1486
 
884
1487
  ```tsx
885
1488
  import { Avatar } from '@k8ordo/ui';
886
1489
 
887
- <Avatar src="/avatar.jpg" alt="ユーザー名" size="md" />
888
- <Avatar name="田中太郎" fallback="田" size="lg" />
1490
+ <Avatar src="/avatar.jpg" alt="User name" size="md" />
1491
+ <Avatar name="Ada Lovelace" fallback="A" size="lg" />
889
1492
  <Avatar color="primary" icon={<AssistantIcon />} name="AI" size="sm" />
890
1493
  ```
891
1494
 
@@ -893,36 +1496,38 @@ Props:
893
1496
 
894
1497
  - `alt`: `string`
895
1498
  - `children`: `ReactNode`
896
- - `color`: `'base'` | `'primary'` | `'secondary'`(既定: `'base'`)
1499
+ - `color`: `'base'` | `'primary'` | `'secondary'` (default: `'base'`)
897
1500
  - `fallback`: `string`
898
1501
  - `icon`: `ReactNode`
899
1502
  - `name`: `string`
900
- - `size`: `'sm'` | `'md'` | `'lg'`(既定: `'md'`)
1503
+ - `size`: `'sm'` | `'md'` | `'lg'` (default: `'md'`)
901
1504
  - `src`: `string`
1505
+ - Other props are forwarded to `HTMLAttributes<HTMLSpanElement>`, except `role` / `aria-label` / `className` / `style`.
902
1506
 
903
1507
  ### Badge
904
1508
 
905
- ステータスバッジ。
1509
+ A status badge.
906
1510
 
907
1511
  ```tsx
908
1512
  import { Badge } from '@k8ordo/ui';
909
1513
 
910
- <Badge label="新着" tone="info" variant="solid" />
911
- <Badge label="完了" tone="success" variant="outline" />
912
- <Badge label="フィルター" interactive />
1514
+ <Badge label="New" tone="info" variant="solid" />
1515
+ <Badge label="Done" tone="success" variant="outline" />
1516
+ <Badge label="Filter" interactive />
913
1517
  ```
914
1518
 
915
1519
  Props:
916
1520
 
917
- - `label`: `string`(必須)
918
- - `interactive`: `true`
919
- - `size`: `Size`
920
- - `tone`: `Tone`
921
- - `variant`: `Variant`
1521
+ - `label`: `string` (required)
1522
+ - `interactive`: `boolean`
1523
+ - `size`: `'sm'` | `'md'` | `'lg'`
1524
+ - `tone`: `'neutral'` | `'info'` | `'success'` | `'warning'` | `'error'`
1525
+ - `variant`: `'solid'` | `'outline'`
1526
+ - Other props are forwarded to `ButtonHTMLAttributes<HTMLButtonElement> | HTMLAttributes<HTMLSpanElement>`, except `children` / `className` / `style` / `type`.
922
1527
 
923
1528
  ### Code
924
1529
 
925
- インラインコード表示。
1530
+ Inline code.
926
1531
 
927
1532
  ```tsx
928
1533
  import { Code } from '@k8ordo/ui';
@@ -932,11 +1537,155 @@ import { Code } from '@k8ordo/ui';
932
1537
 
933
1538
  Props:
934
1539
 
935
- - `children`: `string`(必須)
1540
+ - `children`: `string` (required)
1541
+ - Other props are forwarded to `HTMLAttributes<HTMLElement>`, except `className` / `style`.
936
1542
 
937
- ### Table
1543
+ ### CodeBlock
938
1544
 
939
- データテーブル。Compound component パターン。
1545
+ A block of code, highlighted on the server with shiki, with a copy button.
1546
+ It is an async Server Component on its own subpath, `@k8ordo/ui/code-block`,
1547
+ and imports `server-only`: the highlighter never reaches the browser, and
1548
+ importing it from a Client Component fails the build. Only the copy button is a
1549
+ client module.
1550
+
1551
+ ```tsx
1552
+ import { CodeBlock } from '@k8ordo/ui/code-block';
1553
+
1554
+ <CodeBlock code={source} lang="tsx" title="save.tsx" />;
1555
+ ```
1556
+
1557
+ - `lang` is any language shiki bundles (`tsx`, `bash`, `css`, …). A name it
1558
+ does not know renders as plain text rather than failing, so a Markdown fence
1559
+ can pass its info string through as it is. The header shows `title` when
1560
+ given (as the figure's `figcaption`), and the language otherwise.
1561
+ - It looks like the code blocks on k8o's blog: one surface in `bg-surface`
1562
+ with no border, the language (or `title`, in monospace) as a small label at
1563
+ its top, and the copy button over its top corner. The syntax colors are
1564
+ shiki's `one-light` in light and `plastic` in dark, unchanged, written as
1565
+ `light-dark()` so they follow the `color-scheme` the stylesheet sets with
1566
+ `.dark`. Some of them, the comments among them, fall short of 4.5:1 on the
1567
+ surface; the library's own accessibility checks exempt the code's text from
1568
+ the contrast rule and nothing else. Stretched by its parent, the block gives
1569
+ the extra height to the code, never to the label.
1570
+ - `marks` marks lines by their 1-based number, with a bar and a tint in the
1571
+ status tokens: `highlight`, `add` (drawn with a `+`), or `remove` (drawn
1572
+ with a `-`). `callouts` puts a note under a line
1573
+ (an array puts several, in order) as a bubble pointing up at it, indented
1574
+ like the line, and tints the line it points at. A line can carry both; the
1575
+ note's tint wins. Neither is part of the copied text: the button copies
1576
+ `code` exactly.
1577
+
1578
+ ```tsx
1579
+ <CodeBlock
1580
+ callouts={{ 3: 'Guard the division' }}
1581
+ code={source}
1582
+ lang="ts"
1583
+ marks={{ 2: 'remove', 3: 'add' }}
1584
+ />
1585
+ ```
1586
+
1587
+ - Inside a `.writing-v` tree it stays a horizontal island.
1588
+ - It cannot render in a generative-UI spec, which renders on the client; see
1589
+ [generative-ui](generative-ui.md).
1590
+
1591
+ Props:
1592
+
1593
+ - `code`: `string` (required)
1594
+ - `callouts`: `Readonly<Record<number, string | readonly string[]>>`
1595
+ - `lang`: `string` (default: `'text'`)
1596
+ - `marks`: `Readonly<Record<number, 'highlight' | 'add' | 'remove'>>`
1597
+ - `title`: `string`
1598
+ - Other props are forwarded to `HTMLAttributes<HTMLElement>`, except `children` / `className` / `style`.
1599
+
1600
+ ### Kbd
1601
+
1602
+ One keyboard key, drawn as a key cap. A shortcut is several `Kbd` side by side,
1603
+ one per key. When the key is a symbol a screen reader would not say usefully
1604
+ (`⌘`, `⇧`), pass `label`: the symbol stays on screen and the label is what is
1605
+ read out.
1606
+
1607
+ ```tsx
1608
+ import { Kbd } from '@k8ordo/ui';
1609
+
1610
+ <Kbd>Esc</Kbd>
1611
+
1612
+ <Kbd label="Command">⌘</Kbd>
1613
+ <Kbd>K</Kbd>
1614
+ ```
1615
+
1616
+ Props:
1617
+
1618
+ - `children`: `string` (required)
1619
+ - `label`: `string`
1620
+ - Other props are forwarded to `HTMLAttributes<HTMLElement>`, except `className` / `style`.
1621
+
1622
+ ### Carousel
1623
+
1624
+ Slides that scroll along the inline axis, snapping one slide at a time, with
1625
+ previous and next buttons under them. It is built on scroll snapping, so a
1626
+ trackpad, a touch swipe, and the arrow keys (the track takes focus) all move it
1627
+ as well; the buttons move one slide per press and are disabled at either end.
1628
+
1629
+ ```tsx
1630
+ import { Carousel } from '@k8ordo/ui';
1631
+
1632
+ <Carousel.Root label="Featured posts" slideSize="md">
1633
+ {posts.map((post) => (
1634
+ <Carousel.Slide key={post.id} label={post.title}>
1635
+ <PostCard post={post} />
1636
+ </Carousel.Slide>
1637
+ ))}
1638
+ </Carousel.Root>;
1639
+ ```
1640
+
1641
+ `slideSize` sets how much of the track one slide takes: `full` (one at a time),
1642
+ `lg` (the next one peeks in), `md` (two), `sm` (three). With `full` and `lg` the
1643
+ current position is shown as `2 / 5`; with several slides in view there is no
1644
+ single current slide, so no position is shown. The region is announced as a
1645
+ carousel and each slide as a slide (`aria-roledescription`); give a slide a
1646
+ `label` when its content has a title. The slides follow the writing mode, so
1647
+ under `.writing-v` the track scrolls vertically. There is no autoplay.
1648
+
1649
+ Props (Carousel.Root):
1650
+
1651
+ - `label`: `string` (required)
1652
+ - `children`: `ReactNode`
1653
+ - `slideSize`: `'full'` | `'lg'` | `'md'` | `'sm'` (default: `'full'`)
1654
+
1655
+ Props (Carousel.Slide):
1656
+
1657
+ - `children`: `ReactNode`
1658
+ - `label`: `string`
1659
+
1660
+ ### Prose
1661
+
1662
+ A container that puts the typesetting of body text back — for Markdown or MDX
1663
+ rendered to HTML. Only bare elements (no `class`) are typeset, so components
1664
+ placed inside keep their own look; the spacing between blocks applies to
1665
+ everything. Tuned for Japanese: loose leading, emphasis dots for `em`, and a
1666
+ one-character paragraph indent in vertical writing. See
1667
+ [Typography](typography.md#long-form-text-prose) for what it sets.
1668
+
1669
+ ```tsx
1670
+ import { Prose } from '@k8ordo/ui';
1671
+
1672
+ <article>
1673
+ <Prose>
1674
+ <MDXContent components={{ pre: MyCodeBlock }} />
1675
+ </Prose>
1676
+ </article>;
1677
+ ```
1678
+
1679
+ Props:
1680
+
1681
+ - `children`: `ReactNode`
1682
+ - Other props are forwarded to `HTMLAttributes<HTMLDivElement>`, except `className` / `style`.
1683
+
1684
+ ### Table
1685
+
1686
+ A data table, as a compound component. `Table.EmptyState` is the row to put in
1687
+ `Table.Body` when there are no rows: it spans `colSpan` columns and draws an
1688
+ `EmptyState` with the rest of its props.
940
1689
 
941
1690
  ```tsx
942
1691
  import { Table } from '@k8ordo/ui';
@@ -944,13 +1693,13 @@ import { Table } from '@k8ordo/ui';
944
1693
  <Table.Root>
945
1694
  <Table.Head>
946
1695
  <Table.Row>
947
- <Table.HeaderCell>名前</Table.HeaderCell>
948
- <Table.HeaderCell align="right">金額</Table.HeaderCell>
1696
+ <Table.HeaderCell>Name</Table.HeaderCell>
1697
+ <Table.HeaderCell align="right">Amount</Table.HeaderCell>
949
1698
  </Table.Row>
950
1699
  </Table.Head>
951
1700
  <Table.Body>
952
1701
  <Table.Row interactive>
953
- <Table.Cell>商品A</Table.Cell>
1702
+ <Table.Cell>Product A</Table.Cell>
954
1703
  <Table.Cell align="right">¥1,000</Table.Cell>
955
1704
  </Table.Row>
956
1705
  </Table.Body>
@@ -960,59 +1709,309 @@ import { Table } from '@k8ordo/ui';
960
1709
  Props (Table.Body):
961
1710
 
962
1711
  - `children`: `ReactNode`
1712
+ - Other props are forwarded to `HTMLAttributes<HTMLTableSectionElement>`, except `className` / `style`.
963
1713
 
964
1714
  Props (Table.Caption):
965
1715
 
966
1716
  - `children`: `ReactNode`
1717
+ - Other props are forwarded to `HTMLAttributes<HTMLTableCaptionElement>`, except `className` / `style`.
967
1718
 
968
1719
  Props (Table.Cell):
969
1720
 
970
- - `align`: `CellAlign`(既定: `'left'`)
1721
+ - `align`: `CellAlign` (default: `'left'`)
971
1722
  - `children`: `ReactNode`
972
- - `color`: `'base'` | `'mute'`(既定: `'base'`)
1723
+ - `color`: `'base'` | `'mute'` (default: `'base'`)
1724
+ - Other props are forwarded to `TdHTMLAttributes<HTMLTableCellElement>`, except `className` / `style`.
973
1725
 
974
1726
  Props (Table.EmptyState):
975
1727
 
976
- - `children`: `ReactNode`(必須)
977
- - `colSpan`: `number`(必須)
1728
+ - `colSpan`: `number` (required)
1729
+ - `title`: `string` (required)
1730
+ - `action`: `ReactNode`
1731
+ - `description`: `ReactNode`
1732
+ - `icon`: `ReactNode`
1733
+ - Other props are forwarded to `ComponentProps<typeof EmptyState>`.
978
1734
 
979
1735
  Props (Table.Head):
980
1736
 
981
1737
  - `children`: `ReactNode`
1738
+ - Other props are forwarded to `HTMLAttributes<HTMLTableSectionElement>`, except `className` / `style`.
982
1739
 
983
1740
  Props (Table.HeaderCell):
984
1741
 
985
- - `align`: `CellAlign`(既定: `'left'`)
1742
+ - `align`: `CellAlign` (default: `'left'`)
986
1743
  - `children`: `ReactNode`
987
- - `scope`: `'col'` | `'row'` | `'colgroup'` | `'rowgroup'`(既定: `'col'`)
1744
+ - `scope`: `'col'` | `'row'` | `'colgroup'` | `'rowgroup'` (default: `'col'`)
1745
+ - Other props are forwarded to `ThHTMLAttributes<HTMLTableCellElement>`, except `className` / `style`.
988
1746
 
989
1747
  Props (Table.Root):
990
1748
 
991
1749
  - `children`: `ReactNode`
1750
+ - Other props are forwarded to `TableHTMLAttributes<HTMLTableElement>`, except `className` / `style`.
992
1751
 
993
1752
  Props (Table.Row):
994
1753
 
995
1754
  - `children`: `ReactNode`
996
- - `interactive`: `boolean`(既定: `false`)
1755
+ - `interactive`: `boolean` (default: `false`)
1756
+ - `selected`: `boolean` (default: `false`)
1757
+ - Other props are forwarded to `HTMLAttributes<HTMLTableRowElement>`, except `className` / `style`.
1758
+
1759
+ ### DataTable
1760
+
1761
+ A table with sorting, row selection, and column visibility. Every piece of state
1762
+ is **controlled** and owned by the caller, so it can live anywhere — component
1763
+ state, or the URL through `@k8ordo/state`'s url slot, which keeps the sort and
1764
+ the page in a shareable link. It takes functions (`cell`, `getRowId`, the
1765
+ handlers), so render it from the Client Component that owns that state.
1766
+
1767
+ ```tsx
1768
+ 'use client';
1769
+ import { DataTable, type DataTableSort } from '@k8ordo/ui';
1770
+
1771
+ const [sort, setSort] = useState<DataTableSort | null>(null);
1772
+ const [selectedIds, setSelectedIds] = useState<string[]>([]);
1773
+ const [hiddenColumnIds, setHiddenColumnIds] = useState<string[]>([]);
1774
+
1775
+ <DataTable
1776
+ columns={[
1777
+ { id: 'name', header: 'Name', cell: (m) => m.name, sortable: true },
1778
+ { id: 'role', header: 'Role', cell: (m) => m.role, hideable: false },
1779
+ ]}
1780
+ getRowId={(m) => m.id}
1781
+ hiddenColumnIds={hiddenColumnIds}
1782
+ label="Members"
1783
+ onHiddenColumnIdsChange={setHiddenColumnIds}
1784
+ onSelectedIdsChange={setSelectedIds}
1785
+ onSortChange={setSort}
1786
+ rows={sortMembers(members, sort)}
1787
+ selectedIds={selectedIds}
1788
+ sort={sort}
1789
+ />;
1790
+ ```
1791
+
1792
+ - A column is a `DataTableColumn<Row>`: `id`, `header` (text), `cell(row)`
1793
+ (what to draw), and optionally `align`, `sortable`, and `hideable`.
1794
+ - **It does not sort, filter, or page.** It draws `rows` in the order given, so
1795
+ the same component works when the server sorts. `sort` is
1796
+ `{ columnId, direction: 'ascending' | 'descending' } | null`; a sortable
1797
+ header cycles ascending → descending → unsorted and carries `aria-sort`.
1798
+ Put `Pagination` under it for pages.
1799
+ - Each feature appears only when you pass its handler: sort buttons on the
1800
+ `sortable` columns with `onSortChange`, a checkbox column with
1801
+ `onSelectedIdsChange`, and a "Columns" menu (every column but those with
1802
+ `hideable: false`) with `onHiddenColumnIdsChange`.
1803
+ - The header checkbox selects or clears the rows on screen and shows the mixed
1804
+ state when some are selected (`Checkbox`'s `indeterminate`). The first column
1805
+ is the row header (`th scope="row"`), and each row's checkbox is named after
1806
+ it ("Select row Aoki").
1807
+ - `emptyState` is drawn in a row spanning the columns when `rows` is empty —
1808
+ pass an `EmptyState`.
1809
+ - Selected rows use `Table.Row`'s `selected`. For bulk actions, render your own
1810
+ bar above the table from `selectedIds`.
1811
+
1812
+ Props:
1813
+
1814
+ - `columns`: `ReadonlyArray<DataTableColumn<Row>>` (required)
1815
+ - `getRowId`: `(row: Row) => string` (required)
1816
+ - `label`: `string` (required)
1817
+ - `rows`: `readonly Row[]` (required)
1818
+ - `emptyState`: `ReactNode`
1819
+ - `hiddenColumnIds`: `readonly string[]` (default: `NONE`)
1820
+ - `onHiddenColumnIdsChange`: `(ids: string[]) => void`
1821
+ - `onSelectedIdsChange`: `(ids: string[]) => void`
1822
+ - `onSortChange`: `(sort: DataTableSort | null) => void`
1823
+ - `selectedIds`: `readonly string[]` (default: `NONE`)
1824
+ - `sort`: `DataTableSort` | `null` (default: `null`)
1825
+
1826
+ ### Tree
1827
+
1828
+ A hierarchy whose parents open and close — files and folders, an outline —
1829
+ with the WAI-ARIA tree view keyboard model. Pass the nodes as a tree of
1830
+ `{ id, label, icon?, children? }`.
1831
+
1832
+ ```tsx
1833
+ import { Tree } from '@k8ordo/ui';
1834
+
1835
+ <Tree
1836
+ defaultExpandedIds={['src']}
1837
+ items={[
1838
+ {
1839
+ id: 'src',
1840
+ label: 'src',
1841
+ children: [{ id: 'index', label: 'index.ts' }],
1842
+ },
1843
+ { id: 'readme', label: 'README.md' },
1844
+ ]}
1845
+ label="Files"
1846
+ onChange={(id) => open(id)}
1847
+ />;
1848
+ ```
1849
+
1850
+ - Which parents are open is controllable (`expandedIds` / `defaultExpandedIds`
1851
+ / `onExpandedChange`), and so is the selected node (`selectedId` /
1852
+ `defaultSelectedId` / `onChange`, called with the node's `id`).
1853
+ - Keyboard: Down / Up move between the visible nodes; Right opens a closed
1854
+ parent, then moves to its first child; Left closes an open parent, or moves
1855
+ to the parent; Home / End go to the first / last visible node; Enter or Space
1856
+ selects; a character moves to the next node whose label starts with it.
1857
+ - Clicking a node selects it and, on a parent, opens or closes it.
1858
+ - One node takes Tab at a time (roving tabindex): the focused one, else the
1859
+ selected one, else the first.
1860
+ - Under `.writing-v` the nodes run right to left, so Left / Right move between
1861
+ them and Down / Up open and close.
1862
+
1863
+ Props:
1864
+
1865
+ - `items`: `readonly TreeItem[]` (required)
1866
+ - `label`: `string` (required)
1867
+ - `defaultExpandedIds`: `readonly string[]`
1868
+ - `defaultSelectedId`: `string` | `null` (default: `null`)
1869
+ - `expandedIds`: `readonly string[]`
1870
+ - `onChange`: `(id: string) => void`
1871
+ - `onExpandedChange`: `(ids: readonly string[]) => void`
1872
+ - `selectedId`: `string` | `null`
1873
+ - Other props are forwarded to `HTMLAttributes<HTMLUListElement>`, except `children` / `className` / `style` / `role` / `aria-label`.
1874
+
1875
+ ### Accordion
997
1876
 
998
- ## フィードバック
1877
+ A collapsible section, as a compound component.
1878
+
1879
+ ```tsx
1880
+ import { Accordion } from '@k8ordo/ui';
1881
+
1882
+ <Accordion.Root>
1883
+ <Accordion.Item>
1884
+ <Accordion.Button>Section 1</Accordion.Button>
1885
+ <Accordion.Panel>Content</Accordion.Panel>
1886
+ </Accordion.Item>
1887
+ </Accordion.Root>;
1888
+ ```
1889
+
1890
+ Props (Accordion.Button):
1891
+
1892
+ - `children`: `ReactNode`
1893
+
1894
+ Props (Accordion.Item):
1895
+
1896
+ - `children`: `ReactNode`
1897
+ - `defaultOpen`: `boolean` (default: `false`)
1898
+ - `isOpen`: `boolean`
1899
+ - `onChange`: `(isOpen: boolean) => void`
1900
+
1901
+ Props (Accordion.Panel):
1902
+
1903
+ - `children`: `ReactNode`
1904
+
1905
+ Props (Accordion.Root):
1906
+
1907
+ - `children`: `ReactNode`
1908
+
1909
+ ### Card
1910
+
1911
+ A card that groups content.
1912
+
1913
+ ```tsx
1914
+ import { Card } from '@k8ordo/ui';
1915
+
1916
+ // Static card. The card has no padding of its own
1917
+ <Card width="full" variant="shadow">
1918
+ <div style={{ padding: 'calc(var(--spacing) * 6)' }}>Content</div>
1919
+ </Card>
1920
+
1921
+ // Clickable card (scales to 1.02 on hover and to 0.98 while pressed)
1922
+ <Card variant="outline" interactive>
1923
+ <div style={{ padding: 'calc(var(--spacing) * 6)' }}>Content</div>
1924
+ </Card>
1925
+ ```
1926
+
1927
+ Props:
1928
+
1929
+ - `children`: `ReactNode`
1930
+ - `interactive`: `boolean` (default: `false`)
1931
+ - `variant`: `'shadow'` | `'outline'` (default: `'shadow'`)
1932
+ - `width`: `'full'` | `'fit'` (default: `'full'`)
1933
+ - Other props are forwarded to `HTMLAttributes<HTMLDivElement>`, except `className` / `style`.
1934
+
1935
+ ## Feedback
999
1936
 
1000
1937
  ### Alert
1001
1938
 
1939
+ Reports a status: the result of something the user did, or a state the
1940
+ application is in. It is a live region (`role="alert"` for `warning` and
1941
+ `error`, `role="status"` otherwise), so a screen reader announces it when it
1942
+ appears. For a note that is part of the content, use `Callout`.
1943
+
1002
1944
  ```tsx
1003
1945
  import { Alert } from '@k8ordo/ui';
1004
1946
 
1005
- <Alert tone="info" message="情報メッセージ" />
1006
- <Alert tone="error" message={['エラー1', 'エラー2']} />
1947
+ <Alert tone="info" message="An informational message" />
1948
+ <Alert tone="error" message={['Error 1', 'Error 2']} />
1007
1949
  ```
1008
1950
 
1009
1951
  Props:
1010
1952
 
1011
- - `message`: `string` | `string[]`(必須)
1012
- - `tone`: `Status`(必須)
1953
+ - `message`: `string` | `string[]` (required)
1954
+ - `tone`: `Status` (required)
1013
1955
  - `action`: `AlertAction`
1014
1956
  - `closeLabel`: `string`
1015
1957
  - `onClose`: `() => void`
1958
+ - Other props are forwarded to `HTMLAttributes<HTMLDivElement>`, except `children` / `role` / `className` / `style`.
1959
+
1960
+ `action` is an `AlertAction`, `{ label: string; renderItem: (props: { children: ReactNode }) => ReactNode }`.
1961
+ `renderItem` receives `label` as `children`; render your own button or link
1962
+ around it.
1963
+
1964
+ ### Callout
1965
+
1966
+ A note that sits in the content: a tip beside a paragraph, a pitfall in a
1967
+ guide, a dated-content notice at the top of an article. Unlike `Alert`, it is
1968
+ not a live region (`role="note"`), so a page that renders one, or a client
1969
+ navigation that brings one in, does not have it announced as a warning. The
1970
+ body is `children`, so it can hold paragraphs, `Code`, and links; `label` is an
1971
+ optional bold line above it.
1972
+
1973
+ ```tsx
1974
+ import { Callout, Code } from '@k8ordo/ui';
1975
+
1976
+ <Callout label="Pitfall" tone="warning">
1977
+ <p>
1978
+ Passing <Code>value</Code> makes the field controlled, and a form reset no
1979
+ longer restores it.
1980
+ </p>
1981
+ </Callout>;
1982
+ ```
1983
+
1984
+ Props:
1985
+
1986
+ - `children`: `ReactNode` (required)
1987
+ - `tone`: `Status` (required)
1988
+ - `label`: `string`
1989
+ - Other props are forwarded to `HTMLAttributes<HTMLDivElement>`, except `role` / `className` / `style`.
1990
+
1991
+ ### EmptyState
1992
+
1993
+ What a list, a table, or a search shows when there is nothing in it: a title,
1994
+ an optional description and icon, and an optional action. Inside a table, use
1995
+ `Table.EmptyState`, which puts the same content in a row spanning the columns.
1996
+
1997
+ ```tsx
1998
+ import { Button, EmptyState, TableIcon } from '@k8ordo/ui';
1999
+
2000
+ <EmptyState
2001
+ action={<Button onClick={clearFilters}>Clear filters</Button>}
2002
+ description="Try removing a filter."
2003
+ icon={<TableIcon size="lg" />}
2004
+ title="No matching posts"
2005
+ />;
2006
+ ```
2007
+
2008
+ Props:
2009
+
2010
+ - `title`: `string` (required)
2011
+ - `action`: `ReactNode`
2012
+ - `description`: `ReactNode`
2013
+ - `icon`: `ReactNode`
2014
+ - Other props are forwarded to `HTMLAttributes<HTMLDivElement>`, except `children` / `className` / `style`.
1016
2015
 
1017
2016
  ### Toast
1018
2017
 
@@ -1021,21 +2020,26 @@ import { useToast } from '@k8ordo/ui';
1021
2020
 
1022
2021
  const { open, close, closeAll } = useToast();
1023
2022
 
1024
- open('success', '保存しました');
1025
- open('error', 'エラーが発生しました');
2023
+ open('success', 'Saved');
2024
+ open('error', 'Something went wrong');
2025
+
2026
+ const syncingId = open('info', 'Syncing…', {
2027
+ duration: Number.POSITIVE_INFINITY,
2028
+ });
2029
+ close(syncingId);
1026
2030
  ```
1027
2031
 
1028
- `ToastProvider` は `UIProvider` に含まれるため、別途ラップ不要。
2032
+ `ToastProvider` is already inside `UIProvider`, so no extra wrapper is needed.
1029
2033
 
1030
- `useToast()` の戻り値:
2034
+ What `useToast()` returns:
1031
2035
 
1032
- - `open`: `(tone: Status, message: string, options?: ToastOptions) => void`(`ToastOptions` は `{ duration?: number; action?: ToastAction }`)
1033
- - `close`: `(id: string) => void`
2036
+ - `open`: `(tone: Status, message: string, options?: ToastOptions) => string` (returns the toast's id; `ToastOptions` is `{ duration?: number; action?: ToastAction }`. `duration` is in milliseconds and defaults to `5000`; `Number.POSITIVE_INFINITY` keeps the toast until it is closed. `ToastAction` is the same type as `AlertAction`.)
2037
+ - `close`: `(id: string) => void` (closes only the toast with the id `open` returned)
1034
2038
  - `closeAll`: `() => void`
1035
2039
 
1036
2040
  ### ToastProvider
1037
2041
 
1038
- 出す位置や Portal 先を変えたいときだけ、`UIProvider` の内側で明示的にラップする。
2042
+ Wrap explicitly inside `UIProvider` only when you want to change where toasts appear or which Portal root they use.
1039
2043
 
1040
2044
  ```tsx
1041
2045
  import { ToastProvider } from '@k8ordo/ui';
@@ -1048,43 +2052,53 @@ import { ToastProvider } from '@k8ordo/ui';
1048
2052
  Props:
1049
2053
 
1050
2054
  - `children`: `ReactNode`
1051
- - `portalRef`: `RefObject<HTMLElement | null>`(既定: `null`)
1052
- - `position`: `'fixed'` | `'absolute'`(既定: `'fixed'`)
2055
+ - `portalRef`: `RefObject<HTMLElement | null>` (default: `null`)
2056
+ - `position`: `'fixed'` | `'absolute'` (default: `'fixed'`)
1053
2057
 
1054
2058
  ### Progress
1055
2059
 
2060
+ Leave `value` out when how far along it is cannot be known: the bar then slides
2061
+ back and forth, has no `aria-valuenow`, and is named `label` (the built-in
2062
+ `loading` wording when omitted). With reduced motion it stops sliding and
2063
+ pulses across the whole track instead.
2064
+
1056
2065
  ```tsx
1057
2066
  import { Progress } from '@k8ordo/ui';
1058
2067
 
1059
- <Progress value={50} max={100} />
1060
- <Progress value={50} max={100} min={0} label="進捗" />
2068
+ <Progress value={50} />
2069
+ <Progress value={150} max={200} min={100} label="Progress" />
2070
+
2071
+ // Progress that cannot be measured
2072
+ <Progress label="Uploading" />
1061
2073
  ```
1062
2074
 
1063
2075
  Props:
1064
2076
 
1065
- - `max`: `number`(必須)
1066
- - `value`: `number`(必須)
1067
2077
  - `label`: `string`
1068
- - `min`: `number`(既定: `0`)
2078
+ - `max`: `number` (default: `100`)
2079
+ - `min`: `number` (default: `0`)
2080
+ - `value`: `number`
2081
+ - Other props are forwarded to `HTMLAttributes<HTMLDivElement>`, except `children` / `className` / `style`.
1069
2082
 
1070
2083
  ### Spinner
1071
2084
 
1072
- ローディングスピナー。
2085
+ A loading spinner.
1073
2086
 
1074
2087
  ```tsx
1075
2088
  import { Spinner } from '@k8ordo/ui';
1076
2089
 
1077
- <Spinner size="md" label="読み込み中" />;
2090
+ <Spinner size="md" label="Loading" />;
1078
2091
  ```
1079
2092
 
1080
2093
  Props:
1081
2094
 
1082
2095
  - `label`: `string`
1083
- - `size`: `'sm'` | `'md'` | `'lg'`(既定: `'md'`)
2096
+ - `size`: `'sm'` | `'md'` | `'lg'` (default: `'md'`)
2097
+ - Other props are forwarded to `OutputHTMLAttributes<HTMLOutputElement>`, except `children` / `aria-label` / `className` / `style`.
1084
2098
 
1085
2099
  ### Skeleton
1086
2100
 
1087
- コンテンツプレースホルダー。
2101
+ A content placeholder.
1088
2102
 
1089
2103
  ```tsx
1090
2104
  import { Skeleton } from '@k8ordo/ui';
@@ -1096,21 +2110,22 @@ import { Skeleton } from '@k8ordo/ui';
1096
2110
 
1097
2111
  Props:
1098
2112
 
1099
- - `animate`: `boolean`(既定: `true`)
1100
- - `shape`: `'rect'` | `'circle'`(既定: `'rect'`)
1101
- - `size`: `'sm'` | `'md'` | `'lg'`(既定: `'md'`)
2113
+ - `animate`: `boolean` (default: `true`)
2114
+ - `shape`: `'rect'` | `'circle'` (default: `'rect'`)
2115
+ - `size`: `'sm'` | `'md'` | `'lg'` (default: `'md'`)
2116
+ - Other props are forwarded to `HTMLAttributes<HTMLDivElement>`, except `children` / `className` / `style`.
1102
2117
 
1103
- ## オーバーレイ
2118
+ ## Overlays
1104
2119
 
1105
2120
  ### Modal
1106
2121
 
1107
- ベースのオーバーレイコンポーネント。`<dialog>` 要素を使用。
2122
+ The base overlay component. It uses the `<dialog>` element.
1108
2123
 
1109
2124
  ```tsx
1110
2125
  import { Modal } from '@k8ordo/ui';
1111
2126
 
1112
2127
  <Modal isOpen={open} onClose={onClose} side="center">
1113
- コンテンツ
2128
+ Content
1114
2129
  </Modal>;
1115
2130
  ```
1116
2131
 
@@ -1124,27 +2139,27 @@ Props:
1124
2139
  - `isOpen`: `boolean`
1125
2140
  - `onClose`: `() => void`
1126
2141
  - `ref`: `Ref<HTMLDialogElement>`
1127
- - `side`: `ModalSide`(既定: `'center'`)
2142
+ - `side`: `ModalSide` (default: `'center'`)
1128
2143
 
1129
- 名前の解決順は `aria-label` / `aria-labelledby` > 中の `Dialog.Root` が登録した見出し。どちらも無ければ無名の dialog になるため、`Dialog` を入れずに直接コンテンツを置くときは `aria-label` を渡す。
2144
+ Name resolution goes `aria-label` / `aria-labelledby` first, then the heading registered by a `Dialog.Root` inside. With neither, the dialog is unnamed — so pass `aria-label` when you place content directly without a `Dialog`.
1130
2145
 
1131
2146
  ```tsx
1132
- <Modal aria-label="画像プレビュー" isOpen={open} onClose={onClose}>
2147
+ <Modal aria-label="Image preview" isOpen={open} onClose={onClose}>
1133
2148
  <img alt="" src={src} />
1134
2149
  </Modal>
1135
2150
  ```
1136
2151
 
1137
2152
  ### Dialog
1138
2153
 
1139
- Compound component パターン。Modal と組み合わせて使用。
2154
+ A compound component, used together with Modal.
1140
2155
 
1141
2156
  ```tsx
1142
2157
  import { Modal, Dialog } from '@k8ordo/ui';
1143
2158
 
1144
2159
  <Modal isOpen={open} onClose={onClose}>
1145
2160
  <Dialog.Root>
1146
- <Dialog.Header title="確認" onClose={onClose} />
1147
- <Dialog.Content>コンテンツ</Dialog.Content>
2161
+ <Dialog.Header title="Confirm" onClose={onClose} />
2162
+ <Dialog.Content>Content</Dialog.Content>
1148
2163
  </Dialog.Root>
1149
2164
  </Modal>;
1150
2165
  ```
@@ -1155,8 +2170,8 @@ Props (Dialog.Content):
1155
2170
 
1156
2171
  Props (Dialog.Header):
1157
2172
 
1158
- - `onClose`: `() => void`(必須)
1159
- - `title`: `ReactNode`(必須)
2173
+ - `onClose`: `() => void` (required)
2174
+ - `title`: `ReactNode` (required)
1160
2175
 
1161
2176
  Props (Dialog.Root):
1162
2177
 
@@ -1166,38 +2181,85 @@ Props (Dialog.Root):
1166
2181
  - `role`: `'dialog'` | `'alertdialog'`
1167
2182
  - `tabIndex`: `number`
1168
2183
 
2184
+ ### CommandPalette
2185
+
2186
+ A command palette: a `Modal` holding a search field and the list of commands it
2187
+ filters. Typing matches each item's `label` and `keywords`, case-insensitively.
2188
+ `ArrowDown` / `ArrowUp` move through the matches and wrap around, `Enter` or a
2189
+ click runs the item's `onSelect` after closing the palette, and `Escape` closes
2190
+ it; focus stays in the search field throughout (the WAI-ARIA combobox, with the
2191
+ list always shown). Items that share a `group` are gathered under that heading,
2192
+ in the order the group first appears, and `shortcut` keys are drawn with `Kbd`.
2193
+ Each opening starts from an empty search. Open and close it like `Modal`
2194
+ (`isOpen` / `defaultOpen` / `onClose`); a key such as ⌘K / Ctrl+K is the
2195
+ application's to wire.
2196
+
2197
+ ```tsx
2198
+ import { CommandPalette } from '@k8ordo/ui';
2199
+
2200
+ <CommandPalette
2201
+ isOpen={isOpen}
2202
+ onClose={() => setIsOpen(false)}
2203
+ items={[
2204
+ {
2205
+ id: 'new-file',
2206
+ label: 'New file',
2207
+ group: 'File',
2208
+ shortcut: ['⌘', 'N'],
2209
+ onSelect: createFile,
2210
+ },
2211
+ {
2212
+ id: 'theme',
2213
+ label: 'Toggle theme',
2214
+ keywords: ['dark', 'light'],
2215
+ onSelect: toggleTheme,
2216
+ },
2217
+ ]}
2218
+ />;
2219
+ ```
2220
+
2221
+ Props:
2222
+
2223
+ - `items`: `readonly CommandPaletteItem[]` (required)
2224
+ - `aria-label`: `string`
2225
+ - `defaultOpen`: `boolean`
2226
+ - `isOpen`: `boolean`
2227
+ - `onClose`: `() => void`
2228
+ - `placeholder`: `string`
2229
+ - `ref`: `Ref<HTMLDialogElement>`
2230
+
1169
2231
  ### Drawer
1170
2232
 
1171
- サイドパネル。内部で Modal を使用。
2233
+ A side panel. It uses Modal internally.
1172
2234
 
1173
2235
  ```tsx
1174
2236
  import { Drawer } from '@k8ordo/ui';
1175
2237
 
1176
- <Drawer title="メニュー" isOpen={open} onClose={onClose} side="right">
1177
- コンテンツ
2238
+ <Drawer title="Menu" isOpen={open} onClose={onClose} side="right">
2239
+ Content
1178
2240
  </Drawer>;
1179
2241
  ```
1180
2242
 
1181
2243
  Props:
1182
2244
 
1183
- - `title`: `ReactNode`(必須)
2245
+ - `title`: `ReactNode` (required)
1184
2246
  - `children`: `ReactNode`
1185
2247
  - `defaultOpen`: `boolean`
1186
2248
  - `isOpen`: `boolean`
1187
2249
  - `onClose`: `() => void`
1188
- - `side`: `DrawerSide`(既定: `'right'`)
2250
+ - `side`: `DrawerSide` (default: `'right'`)
1189
2251
 
1190
2252
  ### Popover
1191
2253
 
1192
- CSS Anchor Positioning ベースのポップオーバー。Compound component パターン。
2254
+ A popover built on CSS Anchor Positioning, as a compound component.
1193
2255
 
1194
2256
  ```tsx
1195
2257
  import { Popover } from '@k8ordo/ui';
1196
2258
 
1197
2259
  <Popover.Root placement="bottom">
1198
- <Popover.Trigger renderItem={(props) => <Button {...props}>開く</Button>} />
2260
+ <Popover.Trigger renderItem={(props) => <Button {...props}>Open</Button>} />
1199
2261
  <Popover.Content
1200
- renderItem={(props) => <div {...props}>ポップオーバーコンテンツ</div>}
2262
+ renderItem={(props) => <div {...props}>Popover content</div>}
1201
2263
  />
1202
2264
  </Popover.Root>;
1203
2265
  ```
@@ -1205,48 +2267,48 @@ import { Popover } from '@k8ordo/ui';
1205
2267
  Props (Root):
1206
2268
 
1207
2269
  - `children`: `ReactNode`
1208
- - `closeOnClickAway`: `boolean`(既定: `true`)
1209
- - `defaultOpen`: `boolean`(既定: `false`)
1210
- - `flipDisabled`: `boolean`(既定: `false`)
2270
+ - `closeOnClickAway`: `boolean` (default: `true`)
2271
+ - `defaultOpen`: `boolean` (default: `false`)
2272
+ - `flipDisabled`: `boolean` (default: `false`)
1211
2273
  - `isOpen`: `boolean`
1212
2274
  - `onChange`: `(isOpen: boolean) => void`
1213
- - `placement`: `Placement`(既定: `'bottom-start'`)
1214
- - `role`: `'dialog'` | `'menu'` | `'listbox'`(既定: `'menu'`)
1215
- - `trapFocus`: `boolean`(既定: `true`)
2275
+ - `placement`: `Placement` (default: `'bottom-start'`)
2276
+ - `role`: `'dialog'` | `'menu'` | `'listbox'` (default: `'menu'`)
2277
+ - `trapFocus`: `boolean` (default: `true`)
1216
2278
 
1217
- Escape は入れ子のうち**最も内側の 1 枚だけ**を閉じる。
2279
+ Escape closes **only the innermost one** when they are nested.
1218
2280
 
1219
2281
  Props (Popover.Content):
1220
2282
 
1221
- - `renderItem`: `(props: PopoverContentProps) => ReactElement`(必須)
1222
- - `animation`: `'scale'` | `'fade'`(既定: `'scale'`)
2283
+ - `renderItem`: `(props: PopoverContentProps) => ReactElement` (required)
2284
+ - `animation`: `'scale'` | `'fade'` (default: `'scale'`)
1223
2285
 
1224
2286
  Props (Popover.Trigger):
1225
2287
 
1226
- - `renderItem`: `(props: PopoverTriggerProps) => ReactElement`(必須)
2288
+ - `renderItem`: `(props: PopoverTriggerProps) => ReactElement` (required)
1227
2289
 
1228
2290
  ### Tooltip
1229
2291
 
1230
- ツールチップ。Compound component パターン。
2292
+ A tooltip, as a compound component.
1231
2293
 
1232
2294
  ```tsx
1233
2295
  import { Tooltip } from '@k8ordo/ui';
1234
2296
 
1235
2297
  <Tooltip.Root placement="top">
1236
- <Tooltip.Trigger renderItem={(props) => <Button {...props}>ホバー</Button>} />
1237
- <Tooltip.Content>ヒント</Tooltip.Content>
2298
+ <Tooltip.Trigger renderItem={(props) => <Button {...props}>Hover</Button>} />
2299
+ <Tooltip.Content>A hint</Tooltip.Content>
1238
2300
  </Tooltip.Root>;
1239
2301
  ```
1240
2302
 
1241
2303
  Props (Root):
1242
2304
 
1243
2305
  - `children`: `ReactNode`
1244
- - `closeDelay`: `number`(既定: `150`)
2306
+ - `closeDelay`: `number` (default: `150`)
1245
2307
  - `defaultOpen`: `boolean`
1246
2308
  - `isOpen`: `boolean`
1247
2309
  - `onChange`: `(isOpen: boolean) => void`
1248
- - `openDelay`: `number`(既定: `0`)
1249
- - `placement`: `Placement`(既定: `'bottom'`)
2310
+ - `openDelay`: `number` (default: `0`)
2311
+ - `placement`: `Placement` (default: `'bottom'`)
1250
2312
 
1251
2313
  Props (Tooltip.Content):
1252
2314
 
@@ -1254,20 +2316,20 @@ Props (Tooltip.Content):
1254
2316
 
1255
2317
  Props (Tooltip.Trigger):
1256
2318
 
1257
- - `renderItem`: `(props: TooltipTriggerProps) => ReactElement`(必須)
2319
+ - `renderItem`: `(props: TooltipTriggerProps) => ReactElement` (required)
1258
2320
 
1259
2321
  ### DropdownMenu
1260
2322
 
1261
- ドロップダウンメニュー。Compound component パターン。
2323
+ A dropdown menu, as a compound component.
1262
2324
 
1263
2325
  ```tsx
1264
2326
  import { DropdownMenu } from '@k8ordo/ui';
1265
2327
 
1266
2328
  <DropdownMenu.Root>
1267
- <DropdownMenu.Trigger label="メニュー" />
2329
+ <DropdownMenu.Trigger label="Menu" />
1268
2330
  <DropdownMenu.Content>
1269
- <DropdownMenu.Item label="アイテム1" onAction={handleClick} />
1270
- <DropdownMenu.Item label="アイテム2" onAction={handleClick} />
2331
+ <DropdownMenu.Item label="Item 1" onAction={handleClick} />
2332
+ <DropdownMenu.Item label="Item 2" onAction={handleClick} />
1271
2333
  </DropdownMenu.Content>
1272
2334
  </DropdownMenu.Root>;
1273
2335
  ```
@@ -1278,12 +2340,12 @@ Props (Root):
1278
2340
  - `defaultOpen`: `boolean`
1279
2341
  - `isOpen`: `boolean`
1280
2342
  - `onChange`: `(isOpen: boolean) => void`
1281
- - `placement`: `Placement`(既定: `'bottom-start'`)
2343
+ - `placement`: `Placement` (default: `'bottom-start'`)
1282
2344
 
1283
- Trigger バリアント:
2345
+ Trigger variants:
1284
2346
 
1285
- - `DropdownMenu.Trigger`: テキストベース(`label`, `size`, `variant`)
1286
- - `DropdownMenu.IconTrigger`: アイコンベース(`icon`, `label`)
2347
+ - `DropdownMenu.Trigger`: text-based (`label`, `size`, `variant`)
2348
+ - `DropdownMenu.IconTrigger`: icon-based (`icon`, `label`)
1287
2349
 
1288
2350
  Props (DropdownMenu.Content):
1289
2351
 
@@ -1291,30 +2353,90 @@ Props (DropdownMenu.Content):
1291
2353
 
1292
2354
  Props (DropdownMenu.IconTrigger):
1293
2355
 
1294
- - `icon`: `ReactNode`(必須)
1295
- - `label`: `string`(必須)
2356
+ - `icon`: `ReactNode` (required)
2357
+ - `label`: `string` (required)
1296
2358
 
1297
2359
  Props (DropdownMenu.Item):
1298
2360
 
1299
- - `label`: `string`(必須)
1300
- - `onAction`: `() => void`(必須)
2361
+ - `label`: `string` (required)
2362
+ - `onAction`: `() => void` (required)
1301
2363
 
1302
- `DropdownMenu.SubMenu` は入れ子メニュー。`label` の行をホバーまたはキーボードで開くと、子要素のメニューが右側に開く。
2364
+ `DropdownMenu.SubMenu` is a nested menu. Hovering the `label` row, or opening it from the keyboard, opens the child menu to the right.
1303
2365
 
1304
2366
  Props (DropdownMenu.SubMenu):
1305
2367
 
1306
- - `label`: `string`(必須)
2368
+ - `label`: `string` (required)
1307
2369
  - `children`: `ReactNode`
1308
2370
 
1309
2371
  Props (DropdownMenu.Trigger):
1310
2372
 
1311
- - `label`: `string`(必須)
1312
- - `size`: `ComponentProps<typeof Button>['size']`(既定: `'md'`)
1313
- - `variant`: `ComponentProps<typeof Button>['variant']`(既定: `'solid'`)
2373
+ - `label`: `string` (required)
2374
+ - `size`: `ComponentProps<typeof Button>['size']` (default: `'md'`)
2375
+ - `variant`: `ComponentProps<typeof Button>['variant']` (default: `'solid'`)
2376
+
2377
+ ### ContextMenu
2378
+
2379
+ A menu opened by right-clicking (or by the keyboard's context-menu key or
2380
+ Shift+F10) on an area, shown at the pointer. The inside is `DropdownMenu`'s —
2381
+ `ContextMenu.Content`, `ContextMenu.Item` (`label` / `onAction`), and
2382
+ `ContextMenu.SubMenu` behave exactly like theirs — and only how it opens and
2383
+ where differ. When it closes from inside (an item, Escape), focus returns to
2384
+ the element that had it before it opened; closing by clicking elsewhere leaves
2385
+ focus where the click put it.
2386
+
2387
+ `ContextMenu.Trigger` fills a slot: `renderItem` receives `onContextMenu` to
2388
+ put on the area. To open it from the keyboard, the area (or something in it)
2389
+ has to be able to take focus.
2390
+
2391
+ ```tsx
2392
+ import { ContextMenu } from '@k8ordo/ui';
2393
+
2394
+ <ContextMenu.Root>
2395
+ <ContextMenu.Trigger
2396
+ renderItem={(props) => (
2397
+ <div {...props} tabIndex={0}>
2398
+ report.pdf
2399
+ </div>
2400
+ )}
2401
+ />
2402
+ <ContextMenu.Content>
2403
+ <ContextMenu.Item label="Rename" onAction={rename} />
2404
+ <ContextMenu.SubMenu label="Move to">
2405
+ <ContextMenu.Item label="Archive" onAction={archive} />
2406
+ </ContextMenu.SubMenu>
2407
+ <ContextMenu.Item label="Delete" onAction={remove} />
2408
+ </ContextMenu.Content>
2409
+ </ContextMenu.Root>;
2410
+ ```
2411
+
2412
+ Props (Root):
2413
+
2414
+ - `children`: `ReactNode`
2415
+ - `defaultOpen`: `boolean`
2416
+ - `isOpen`: `boolean`
2417
+ - `onChange`: `(isOpen: boolean) => void`
2418
+
2419
+ Props (ContextMenu.Content):
2420
+
2421
+ - `children`: `ReactNode`
2422
+
2423
+ Props (ContextMenu.Item):
2424
+
2425
+ - `label`: `string` (required)
2426
+ - `onAction`: `() => void` (required)
2427
+
2428
+ Props (ContextMenu.SubMenu):
2429
+
2430
+ - `label`: `string` (required)
2431
+ - `children`: `ReactNode`
2432
+
2433
+ Props (ContextMenu.Trigger):
2434
+
2435
+ - `renderItem`: `(props: { onContextMenu: MouseEventHandler<HTMLElement>; }) => ReactElement` (required)
1314
2436
 
1315
2437
  ### ListBox
1316
2438
 
1317
- リスト選択。Compound component パターン。選択肢は `Select` と同じ `Option`(`{ value, label }`)。
2439
+ List selection, as a compound component. The choices use the same `Option` (`{ value, label }`) as `Select`.
1318
2440
 
1319
2441
  ```tsx
1320
2442
  import { ListBox } from '@k8ordo/ui';
@@ -1322,31 +2444,31 @@ import { ListBox } from '@k8ordo/ui';
1322
2444
  <ListBox.Root
1323
2445
  onChange={onChange}
1324
2446
  options={[
1325
- { value: '1', label: 'オプション1' },
1326
- { value: '2', label: 'オプション2' },
2447
+ { value: '1', label: 'Option 1' },
2448
+ { value: '2', label: 'Option 2' },
1327
2449
  ]}
1328
2450
  value={value}
1329
2451
  >
1330
- <ListBox.Trigger label="表示件数" size="md" />
2452
+ <ListBox.Trigger label="Items per page" size="md" />
1331
2453
  <ListBox.Content />
1332
2454
  </ListBox.Root>;
1333
2455
  ```
1334
2456
 
1335
2457
  Props (Root):
1336
2458
 
1337
- - `options`: `readonly Option[]`(必須)
2459
+ - `options`: `readonly Option[]` (required)
1338
2460
  - `children`: `ReactNode`
1339
2461
  - `defaultValue`: `Option['value']`
1340
2462
  - `onChange`: `(value: Option['value']) => void`
1341
- - `placement`: `Placement`(既定: `'bottom'`)
2463
+ - `placement`: `Placement` (default: `'bottom'`)
1342
2464
  - `value`: `Option['value']`
1343
2465
 
1344
- Trigger バリアント:
2466
+ Trigger variants:
1345
2467
 
1346
- - `ListBox.Trigger`: テキストベース(`size`, `label`)
1347
- - `ListBox.IconTrigger`: アイコンベース(`size`, `icon`, `label`)
2468
+ - `ListBox.Trigger`: text-based (`size`, `label`)
2469
+ - `ListBox.IconTrigger`: icon-based (`size`, `icon`, `label`)
1348
2470
 
1349
- `label` を渡すとトリガーのアクセシブル名が「ラベル + 現在値」になる。省略すると現在値だけになるため、周囲に見出しが無いときは渡す。
2471
+ Passing `label` makes the trigger's accessible name "label + current value". Omit it and only the current value is used, so pass it when there is no heading nearby.
1350
2472
 
1351
2473
  Props (Content):
1352
2474
 
@@ -1354,113 +2476,421 @@ Props (Content):
1354
2476
 
1355
2477
  Props (ListBox.IconTrigger):
1356
2478
 
1357
- - `icon`: `ReactElement`(必須)
2479
+ - `icon`: `ReactElement` (required)
1358
2480
  - `label`: `string`
1359
- - `size`: `ComponentProps<typeof Button>['size']`(既定: `'md'`)
2481
+ - `size`: `ComponentProps<typeof Button>['size']` (default: `'md'`)
1360
2482
 
1361
2483
  Props (ListBox.Trigger):
1362
2484
 
1363
2485
  - `label`: `string`
1364
- - `size`: `ComponentProps<typeof Button>['size']`(既定: `'md'`)
2486
+ - `size`: `ComponentProps<typeof Button>['size']` (default: `'md'`)
1365
2487
 
1366
- ## プロバイダー
2488
+ ## Layout
1367
2489
 
1368
- ### UIProvider
2490
+ ### Separator
1369
2491
 
1370
- アプリのルートで1回ラップする。ToastProvider と文言辞書(下記 i18n)を含む。
2492
+ A dividing rule.
1371
2493
 
1372
2494
  ```tsx
1373
- import { UIProvider } from '@k8ordo/ui';
2495
+ import { Separator } from '@k8ordo/ui';
1374
2496
 
1375
- <UIProvider>
1376
- <App />
1377
- </UIProvider>;
2497
+ <Separator />
2498
+ <Separator color="mute" />
2499
+ <Separator color="subtle" />
2500
+ <Separator orientation="vertical" />
1378
2501
  ```
1379
2502
 
1380
2503
  Props:
1381
2504
 
2505
+ - `color`: `'base'` | `'mute'` | `'subtle'` (default: `'base'`)
2506
+ - `orientation`: `'horizontal'` | `'vertical'` (default: `'horizontal'`)
2507
+ - Other props are forwarded to `HTMLAttributes<HTMLSpanElement>`, except `children` / `role` / `aria-orientation` / `className` / `style`.
2508
+
2509
+ ### Stack
2510
+
2511
+ Lays children out along one axis. Pick `gap` from the spacing tokens.
2512
+
2513
+ ```tsx
2514
+ import { Stack } from '@k8ordo/ui';
2515
+
2516
+ <Stack gap="lg">
2517
+ <Card>1</Card>
2518
+ <Card>2</Card>
2519
+ </Stack>
2520
+
2521
+ <Stack direction="row" justify="between" align="center">
2522
+ <Heading level="h2">Title</Heading>
2523
+ <Button>Action</Button>
2524
+ </Stack>
2525
+ ```
2526
+
2527
+ Props:
2528
+
2529
+ - `align`: `'start'` | `'center'` | `'end'` | `'stretch'`
1382
2530
  - `children`: `ReactNode`
1383
- - `messages`: `Partial<Messages>`
2531
+ - `direction`: `'row'` | `'column'` (default: `'column'`)
2532
+ - `gap`: `GapSize` (default: `'md'`)
2533
+ - `justify`: `'start'` | `'center'` | `'end'` | `'between'`
2534
+ - `padding`: `PaddingSize`
2535
+ - Other props are forwarded to `HTMLAttributes<HTMLDivElement>`, except `className` / `style`.
1384
2536
 
1385
- ### PortalRootProvider
2537
+ ### Grid
1386
2538
 
1387
- Portal のルート要素を指定する。
2539
+ A grid layout. Passing `'auto-fill'` or `'auto-fit'` to `cols` wraps with `minItemSize` as the lower bound.
1388
2540
 
1389
2541
  ```tsx
1390
- import { PortalRootProvider, usePortalRoot } from '@k8ordo/ui';
2542
+ import { Grid } from '@k8ordo/ui';
1391
2543
 
1392
- <PortalRootProvider value={containerRef}>{children}</PortalRootProvider>;
2544
+ <Grid cols={3} gap="md">
2545
+ <Card>1</Card>
2546
+ <Card>2</Card>
2547
+ <Card>3</Card>
2548
+ </Grid>
2549
+
2550
+ <Grid cols="auto-fill" minItemSize={64}>
2551
+ {items.map((item) => (
2552
+ <Card key={item.id}>{item.name}</Card>
2553
+ ))}
2554
+ </Grid>
1393
2555
  ```
1394
2556
 
1395
2557
  Props:
1396
2558
 
1397
2559
  - `children`: `ReactNode`
1398
- - `value`: `RefObject<HTMLElement | null>`
2560
+ - `cols`: `1` | `2` | `3` | `4` | `5` | `6` | `'auto-fill'` | `'auto-fit'` (default: `'auto-fill'`)
2561
+ - `gap`: `GapSize` (default: `'md'`)
2562
+ - `minItemSize`: `24` | `32` | `40` | `48` | `64` | `80` (default: `48`)
2563
+ - Other props are forwarded to `HTMLAttributes<HTMLDivElement>`, except `className` / `style`.
2564
+
2565
+ ### ResizablePanels
2566
+
2567
+ Two panes with a divider between them that the user drags or moves with the
2568
+ arrow keys (the WAI-ARIA window splitter). `value` is the first pane's share in
2569
+ percent, kept between `min` and `max`; the second pane takes the rest. The root
2570
+ fills its parent, so give that parent a size — a vertical split needs a height.
2571
+ Each pane scrolls on its own.
2572
+
2573
+ The divider is a focusable `separator` whose value is the first pane's size and
2574
+ whose `aria-controls` points at it. The arrow keys move it the way they point
2575
+ on screen — left/right when the panes sit side by side, up/down when they are
2576
+ stacked — so in a right-to-left page `ArrowLeft` widens a first pane that sits
2577
+ on the right; `Home` / `End` jump to `min` / `max`. `orientation="horizontal"`
2578
+ lays the panes along the line of text, so in vertical writing mode they stack.
2579
+ Name the divider after the first pane with `aria-labelledby` when it has a
2580
+ heading; otherwise it falls back to `resizablePanelsHandle` from the dictionary.
2581
+
2582
+ ```tsx
2583
+ import { ResizablePanels } from '@k8ordo/ui';
2584
+
2585
+ <div style={{ height: '24rem' }}>
2586
+ <ResizablePanels.Root defaultValue={25}>
2587
+ <ResizablePanels.Panel>
2588
+ <h2 id="files">Files</h2>
2589
+ </ResizablePanels.Panel>
2590
+ <ResizablePanels.Handle aria-labelledby="files" />
2591
+ <ResizablePanels.Panel>…</ResizablePanels.Panel>
2592
+ </ResizablePanels.Root>
2593
+ </div>;
2594
+ ```
2595
+
2596
+ Props (Root):
2597
+
2598
+ - `children`: `ReactNode`
2599
+ - `defaultValue`: `number` (default: `50`)
2600
+ - `max`: `number` (default: `90`)
2601
+ - `min`: `number` (default: `10`)
2602
+ - `onChange`: `(value: number) => void`
2603
+ - `orientation`: `'horizontal'` | `'vertical'` (default: `'horizontal'`)
2604
+ - `ref`: `Ref<HTMLDivElement>`
2605
+ - `step`: `number` (default: `5`)
2606
+ - `value`: `number`
2607
+ - Other props are forwarded to `HTMLAttributes<HTMLDivElement>`, except `className` / `style`.
2608
+
2609
+ Props (ResizablePanels.Panel):
2610
+
2611
+ - `children`: `ReactNode`
2612
+ - `ref`: `Ref<HTMLDivElement>`
2613
+ - Other props are forwarded to `HTMLAttributes<HTMLDivElement>`, except `className` / `style`.
2614
+
2615
+ Props (ResizablePanels.Handle):
2616
+
2617
+ - _No props of its own._
2618
+ - Other props are forwarded to `HTMLAttributes<HTMLDivElement>`, except `className` / `style` / `role` / `children` / `tabIndex` / `aria-orientation` / `aria-valuenow` / `aria-valuemin` / `aria-valuemax` / `aria-controls`.
2619
+
2620
+ ## Observers
2621
+
2622
+ Components that watch their children and report back without adding a wrapper
2623
+ element. They are built on React's Fragment refs, so whatever the children
2624
+ render is what gets observed — including host elements that mount later.
2625
+
2626
+ ### InView
2627
+
2628
+ Reports whether its children are inside the viewport, or inside `root`.
2629
+
2630
+ ```tsx
2631
+ import { InView } from '@k8ordo/ui';
2632
+
2633
+ const [isInView, setIsInView] = useState(false);
2634
+
2635
+ <InView onChange={setIsInView}>
2636
+ <section>…</section>
2637
+ </InView>;
2638
+
2639
+ // inside a scroll container, and only until it has been seen once
2640
+ const [container, setContainer] = useState<HTMLElement | null>(null);
2641
+
2642
+ <div ref={setContainer} style={{ overflowY: 'auto' }}>
2643
+ <InView once onChange={reveal} root={container} rootMargin="0px 0px 24px 0px">
2644
+ <img alt="" src="…" />
2645
+ </InView>
2646
+ </div>;
2647
+ ```
2648
+
2649
+ - `onChange` reports the state as soon as a host element is observed, then again
2650
+ each time it flips. The same value is never reported twice in a row, even
2651
+ when `root` changes and the observer is re-created.
2652
+ - With several host elements, `isInView` is `true` while **any** of them
2653
+ intersects, and it follows children that mount or unmount later. While the
2654
+ children render no host element, `onChange` is not called at all — the first
2655
+ report comes once one mounts.
2656
+ - `once` stops observing after the first `true`.
2657
+ - Hold `root` in state, not a `RefObject`: the observer has to be re-created
2658
+ once the element exists.
2659
+
2660
+ Props:
2661
+
2662
+ - `children`: `ReactNode` (required)
2663
+ - `onChange`: `(isInView: boolean) => void` (required)
2664
+ - `once`: `boolean` (default: `false`)
2665
+ - `root`: `Element` | `null` (default: `null`)
2666
+ - `rootMargin`: `string` (default: `'0px'`)
2667
+ - `threshold`: `number` (default: `0`)
2668
+
2669
+ ### Resize
2670
+
2671
+ Calls `onChange` when the size of its children changes.
2672
+
2673
+ ```tsx
2674
+ import { Resize } from '@k8ordo/ui';
2675
+
2676
+ <Resize onChange={remeasure}>
2677
+ <div>…</div>
2678
+ </Resize>;
2679
+ ```
2680
+
2681
+ - `onChange` is also called once when observation starts, as a native
2682
+ `ResizeObserver` is.
2683
+ - It takes no argument; read what you need from the DOM in the handler.
2684
+
2685
+ Props:
1399
2686
 
1400
- ## i18n(文言辞書)
2687
+ - `children`: `ReactNode` (required)
2688
+ - `onChange`: `() => void` (required)
1401
2689
 
1402
- コンポーネントが内部で持つ文言(閉じる、必須、読み込み中 …)は辞書から引く。**既定は日本語**で、Provider を置かなくても、`messages` を渡さなくても日本語で動く。
2690
+ ## Icons
1403
2691
 
1404
- 英語に切り替えるときは `@k8ordo/ui/i18n` の `en` を渡す。
2692
+ Decorative icons, all from the root entry. Each renders an `<svg>` with
2693
+ `aria-hidden` and `focusable="false"`, so the accessible name belongs to the
2694
+ control around it — an `IconButton`'s `label`, for example.
2695
+
2696
+ ```tsx
2697
+ import { AlertIcon, ChevronIcon, CloseIcon } from '@k8ordo/ui';
2698
+
2699
+ <CloseIcon />
2700
+ <ChevronIcon direction="down" size="sm" />
2701
+ <AlertIcon status="warning" />
2702
+ ```
2703
+
2704
+ Every icon takes one optional prop and nothing else:
2705
+
2706
+ - `size`: `'xs'` | `'sm'` | `'md'` | `'lg'` | `'xl'` | `'2xl'` | `'3xl'` (default: `'md'`)
2707
+
2708
+ Two of them also require a prop that picks the glyph:
2709
+
2710
+ - `ChevronIcon`: `direction`: `Direction` (`'up'` | `'down'` | `'left'` | `'right'`)
2711
+ - `AlertIcon`: `status`: `Status` (`'success'` | `'info'` | `'warning'` | `'error'`)
2712
+
2713
+ <!-- generated:icons -->
2714
+
2715
+ The icons: `AccessibilityIcon`, `AIIcon`, `AlertIcon`, `AssistantIcon`,
2716
+ `AtomIcon`, `BadIcon`, `BlogIcon`, `BoringIcon`, `CheckIcon`, `ChevronIcon`,
2717
+ `ChromeIcon`, `CloseIcon`, `CodeXmlIcon`, `ColorContrastIcon`, `ColorInfoIcon`,
2718
+ `ColorScaleIcon`, `CopyIcon`, `DarkModeIcon`, `DifficultIcon`, `EasyIcon`,
2719
+ `EdgeIcon`, `ExternalLinkIcon`, `FirefoxIcon`, `FlaskIcon`, `ForkIcon`,
2720
+ `FormIcon`, `FullscreenIcon`, `GitHubIcon`, `GoodIcon`, `HistoryIcon`,
2721
+ `HorizontalWritingIcon`, `InformativeIcon`, `InterestingIcon`, `LightModeIcon`,
2722
+ `LinkIcon`, `ListIcon`, `LocationIcon`, `LockIcon`, `LockOpenIcon`, `LogoIcon`,
2723
+ `MailIcon`, `MinusIcon`, `MixedColorIcon`, `NavigationMenuIcon`, `NewsIcon`,
2724
+ `PackageIcon`, `PaletteIcon`, `PlusIcon`, `PrepareIcon`, `PublishDateIcon`,
2725
+ `QiitaIcon`, `RefreshIcon`, `RSSIcon`, `SafariIcon`, `SendIcon`, `ShallowIcon`,
2726
+ `ShieldCheckIcon`, `SlideIcon`, `SparklesIcon`, `SquircleIcon`, `SubscribeIcon`,
2727
+ `TableIcon`, `TagIcon`, `TwitterIcon`, `UpdateDateIcon`, `VerticalWritingIcon`,
2728
+ `ViewIcon`, `ViewOffIcon`.
2729
+
2730
+ <!-- /generated:icons -->
2731
+
2732
+ `Logo` is the mark `LogoIcon` draws, as a bare `<svg>` without the sizing: it
2733
+ takes `className`, `aria-hidden`, and `focusable` (`Partial<IconRenderProps>`)
2734
+ instead of `size`. The types `BaseIconProps` (`{ size }`) and
2735
+ `IconRenderProps` (`{ className: string; 'aria-hidden': true; focusable: 'false' }`)
2736
+ are exported as well.
2737
+
2738
+ ## Providers
2739
+
2740
+ ### UIProvider
2741
+
2742
+ Wrap the app root once. It includes ToastProvider. The components' own wording needs no provider: it follows `@k8ordo/i18n` (i18n, below).
1405
2743
 
1406
2744
  ```tsx
1407
2745
  import { UIProvider } from '@k8ordo/ui';
1408
- import { en } from '@k8ordo/ui/i18n';
1409
2746
 
1410
- <UIProvider messages={en}>
2747
+ <UIProvider>
1411
2748
  <App />
1412
2749
  </UIProvider>;
1413
2750
  ```
1414
2751
 
1415
- 一部だけ差し替えるときは辞書をスプレッドして上書きする(`Partial<Messages>` なので全キーを埋める必要はない)。
2752
+ Props:
2753
+
2754
+ - `children`: `ReactNode`
2755
+
2756
+ ### PortalRootProvider
2757
+
2758
+ A context that shares a portal container with your own `createPortal` calls;
2759
+ read it with `usePortalRoot()`. The library's overlays do not read it — they
2760
+ open in the top layer (`<dialog>`, the Popover API), and toasts go where
2761
+ `ToastProvider`'s `portalRef` points. `Modal` passes its own `<dialog>` as the
2762
+ value, so a portal placed through `usePortalRoot()` inside a modal stays in it.
1416
2763
 
1417
2764
  ```tsx
1418
- <UIProvider messages={{ ...en, close: 'Dismiss' }}>
1419
- <App />
1420
- </UIProvider>
2765
+ import { PortalRootProvider, usePortalRoot } from '@k8ordo/ui';
2766
+
2767
+ <PortalRootProvider value={containerRef}>{children}</PortalRootProvider>;
1421
2768
  ```
1422
2769
 
1423
- 日本語のまま一部だけ変えるなら、そのキーだけ渡せばよい。
2770
+ Props:
2771
+
2772
+ - `value`: `RefObject<HTMLElement | null>` (required)
2773
+ - `children`: `ReactNode`
2774
+
2775
+ ## i18n (message dictionary)
2776
+
2777
+ The wording components own internally (close, required, loading, …) comes from a dictionary, picked by `@k8ordo/i18n`'s current locale. There is no provider and nothing to pass.
2778
+
2779
+ - An application that defines its locale set with `defineLocales` gets the locale its messages render in: the one the URL names, or the set's default.
2780
+ - An application that defines no set gets **English**, whatever its URL starts with, so the server and the browser agree.
2781
+ - The module defining the set has to be loaded in the browser as well; where no set is defined the components speak English.
2782
+
2783
+ `ja` and `en` ship with the library. Register any other locale — or replace a built-in one — with `registerMessages`, next to where the set is defined:
1424
2784
 
1425
2785
  ```tsx
1426
- <UIProvider messages={{ close: '閉じる(Esc)' }}>
1427
- <App />
1428
- </UIProvider>
2786
+ import { en, registerMessages } from '@k8ordo/ui/i18n';
2787
+ import type { Messages } from '@k8ordo/ui/i18n';
2788
+
2789
+ const fr: Messages = { close: 'Fermer' /* …every key */ };
2790
+ registerMessages('fr', fr);
2791
+
2792
+ registerMessages('en', { ...en, close: 'Dismiss' });
1429
2793
  ```
1430
2794
 
1431
- ### 優先順位
2795
+ A regional tag without a dictionary of its own (`en-US`) reads its language's (`en`). Rendering in a locale nothing has text for throws, naming the locale and `registerMessages`.
2796
+
2797
+ ### Resolution order
1432
2798
 
1433
- **コンポーネントの prop > Provider に渡した辞書 > 既定(日本語)**。
2799
+ **Component prop > registered dictionary > built-in dictionary**.
1434
2800
 
1435
- `Spinner` の `label`、`Alert` の `closeLabel`、`PasswordInput` の `showLabel` / `hideLabel`、`Pagination` の `prevLabel` / `nextLabel` のように個別の文言 prop を持つコンポーネントは、その prop が辞書より優先される。
2801
+ A component with a wording prop of its own — `Spinner`'s `label`, `Alert`'s `closeLabel`, `PasswordInput`'s `showLabel` / `hideLabel`, `Pagination`'s `prevLabel` / `nextLabel` — takes that prop over the dictionary.
1436
2802
 
1437
2803
  ```tsx
1438
- // 辞書が en でも、この Spinner だけは「保存中」になる
2804
+ // Whatever the locale, this one Spinner reads 「保存中」
1439
2805
  <Spinner label="保存中" />
1440
2806
  ```
1441
2807
 
1442
- ### エクスポート
2808
+ ### Exports
1443
2809
 
1444
2810
  ```tsx
1445
- import { en, ja, type Messages } from '@k8ordo/ui/i18n';
2811
+ import {
2812
+ en,
2813
+ getMessages,
2814
+ ja,
2815
+ messageUsage,
2816
+ registerMessages,
2817
+ type Messages,
2818
+ } from '@k8ordo/ui/i18n';
1446
2819
  ```
1447
2820
 
1448
- `ja` / `en` は本体のバンドルに載らないよう、ルートではなく `@k8ordo/ui/i18n` サブパスからのみ export される。
2821
+ ### Reading the wording in your own elements
1449
2822
 
1450
- ### キー一覧
2823
+ `getMessages` returns the wording in effect: the dictionary for the current locale, a registered one before a built-in one. Read from it in an element you draw through `renderItem`, or in a component of your own that sits beside the library, and it follows the same language and replacements as the components do. It is not a hook, so a Server Component calls it too.
1451
2824
 
1452
- `Messages` 型の全キー。値はすべて `string`。
2825
+ ```tsx
2826
+ import { getMessages } from '@k8ordo/ui/i18n';
2827
+
2828
+ function DismissButton({ onDismiss }) {
2829
+ const { close } = getMessages();
2830
+ return (
2831
+ <button aria-label={close} onClick={onDismiss} type="button">
2832
+ ×
2833
+ </button>
2834
+ );
2835
+ }
2836
+ ```
1453
2837
 
1454
- | 分類 | キー |
1455
- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
1456
- | 共通 | `close`, `required`, `loading`, `avatar`, `color` |
1457
- | Alert | `alertSuccess`, `alertInfo`, `alertWarning`, `alertError` |
1458
- | Toast | `toastRegion` |
1459
- | Autocomplete | `autocompletePlaceholder`, `autocompleteRemoveTag`, `autocompleteClear`, `autocompleteEmpty` |
1460
- | FileField | `fileFieldRemove` |
1461
- | NumberField | `numberFieldIncrement`, `numberFieldDecrement` |
1462
- | PasswordInput | `passwordShow`, `passwordHide` |
1463
- | ListBox | `listBoxPlaceholder` |
1464
- | Breadcrumb | `breadcrumb` |
1465
- | Pagination | `paginationLabel`, `paginationPrevious`, `paginationNext` |
1466
- | AI チャット | `chat`, `scrollToLatest`, `reasoning`, `reasoningStreaming`, `suggestions`, `send`, `stop`, `toolInput`, `toolOutput`, `toolError` |
2838
+ ### Key list
2839
+
2840
+ Every key in the `Messages` type, grouped by the components that draw it —
2841
+ the same mapping `messageUsage` exports. All values are `string`.
2842
+
2843
+ <!-- generated:message-keys -->
2844
+
2845
+ - Alert / Dialog / Drawer / Response: `close`
2846
+ - FormControl: `required`
2847
+ - Spinner / Progress / Combobox: `loading`
2848
+ - Avatar: `avatar`
2849
+ - Code: `color`
2850
+ - Alert / Callout: `alertSuccess`, `alertInfo`, `alertWarning`, `alertError`
2851
+ - ToastProvider: `toastRegion`
2852
+ - CopyButton / Message.Copy: `copy`
2853
+ - CopyButton / CodeBlock / Message.Copy: `copied`, `copyFailed`
2854
+ - Autocomplete: `autocompletePlaceholder`, `autocompleteRemoveTag`, `autocompleteClear`, `autocompleteEmpty`
2855
+ - Combobox: `comboboxToggle`, `comboboxEmpty`, `comboboxFailed`
2856
+ - FileField: `fileFieldRemove`
2857
+ - FileField.Dropzone / FileField (generative UI): `fileFieldTrigger`, `fileFieldDrop`
2858
+ - NumberField: `numberFieldIncrement`, `numberFieldDecrement`, `numberFieldRangeUnderflow` (`{min}` is replaced), `numberFieldRangeOverflow` (`{max}` is replaced)
2859
+ - RangeSlider: `rangeSliderStart`, `rangeSliderEnd`
2860
+ - Calendar / DatePicker: `calendarPreviousMonth`, `calendarNextMonth`
2861
+ - DatePicker: `datePickerOpen`, `datePickerDialog`
2862
+ - ColorPicker: `colorPickerHue`, `colorPickerSaturation`, `colorPickerLightness`, `colorPickerSwatches`, `colorPickerOpen`
2863
+ - PasswordInput: `passwordShow`, `passwordHide`
2864
+ - ListBox: `listBoxPlaceholder`
2865
+ - Breadcrumb: `breadcrumb`
2866
+ - Tabs (generative UI): `tabList`
2867
+ - Pagination: `paginationLabel`, `paginationPrevious`, `paginationNext`
2868
+ - Stepper: `stepperComplete`
2869
+ - DataTable: `dataTableColumns`, `dataTableSelectAll`, `dataTableSelectRow`
2870
+ - CodeBlock: `codeBlockCopy`
2871
+ - Carousel: `carousel`, `carouselPrevious`, `carouselNext`
2872
+ - Carousel.Slide: `carouselSlide`
2873
+ - ResizablePanels.Handle: `resizablePanelsHandle`
2874
+ - TableOfContents: `tableOfContents`
2875
+ - CommandPalette: `commandPalette`, `commandPaletteSearch`, `commandPaletteEmpty`
2876
+ - Conversation.Messages: `chat`
2877
+ - Conversation.ScrollButton: `scrollToLatest`
2878
+ - Reasoning: `reasoning`, `reasoningStreaming`
2879
+ - Suggestion.List: `suggestions`
2880
+ - PromptInput: `send`, `stop`
2881
+ - PromptInput.Attach: `attach`
2882
+ - Attachment.List / PromptInput.Attachments: `attachments`
2883
+ - PromptInput.Attachments: `attachmentRemove`
2884
+ - Attachment.Item / PromptInput.Attachments: `attachmentImage`
2885
+ - Source.List: `sources`
2886
+ - Message.Actions: `messageActions`
2887
+ - Message.Regenerate: `regenerate`
2888
+ - Message.Feedback: `feedbackPositive`, `feedbackNegative`
2889
+ - ToolInvocation: `toolInput`, `toolOutput`, `toolError`, `toolDenied`, `toolApprovalRequest`, `toolApprove`, `toolDeny`
2890
+ - Response: `responseCopied`, `responseCopyCode`, `responseCopyLink`, `responseCopyTable`, `responseCopyTableAsCsv`, `responseCopyTableAsMarkdown`, `responseCopyTableAsTsv`, `responseDownloadDiagram`, `responseDownloadDiagramAsMmd`, `responseDownloadDiagramAsPng`, `responseDownloadDiagramAsSvg`, `responseDownloadFile`, `responseDownloadImage`, `responseDownloadTable`, `responseDownloadTableAsCsv`, `responseDownloadTableAsMarkdown`, `responseExitFullscreen`, `responseViewFullscreen`, `responseImageNotAvailable`, `responseOpenExternalLink`, `responseExternalLinkWarning`, `responseOpenLink`
2891
+
2892
+ <!-- /generated:message-keys -->
2893
+
2894
+ `fileFieldTrigger` is the button text of an empty `FileField.Dropzone`, and
2895
+ with `tabList` it is also what the generative-UI renderers fall back to when a
2896
+ spec leaves the trigger text or the tab-list name out.