prime-ui-kit 0.16.0 → 0.18.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 (477) hide show
  1. package/README.md +15 -18
  2. package/dist/chunks/{chunk-A7OQWH6R.js → chunk-IVS3J7AS.js} +1 -1
  3. package/dist/chunks/{chunk-6TPHKCUJ.js → chunk-MB4CXSLL.js} +27732 -26723
  4. package/dist/chunks/{chunk-4PSQ64S4.js → chunk-OAXJWF3L.js} +6818 -6264
  5. package/dist/chunks/{chunk-U3Q2I3MY.js → chunk-QFHE5GKW.js} +3 -2
  6. package/dist/chunks/{chunk-HDBQICPW.js → chunk-X3JT5CLR.js} +60 -20
  7. package/dist/color-picker.d.ts +1 -1
  8. package/dist/color-picker.js +3 -3
  9. package/dist/components/badge/Badge.d.ts +17 -0
  10. package/dist/components/breadcrumb/Breadcrumb.d.ts +12 -3
  11. package/dist/components/button/Button.d.ts +1 -1
  12. package/dist/components/button-group/ButtonGroup.d.ts +1 -1
  13. package/dist/components/card/Card.d.ts +8 -4
  14. package/dist/components/chart-frame/ChartFrame.d.ts +1 -1
  15. package/dist/components/chat/Chat.d.ts +3 -3
  16. package/dist/components/chat/ChatRows.d.ts +5 -1
  17. package/dist/components/chat/MessageList.d.ts +5 -1
  18. package/dist/components/chat/groupMessages.d.ts +12 -4
  19. package/dist/components/chat-list/ChatList.d.ts +18 -9
  20. package/dist/components/chat-list/formatChatTime.d.ts +3 -3
  21. package/dist/components/checkbox/Checkbox.d.ts +6 -1
  22. package/dist/components/color-field/ColorField.d.ts +1 -1
  23. package/dist/components/color-picker/ColorPicker.d.ts +23 -1
  24. package/dist/components/color-picker/ColorPresets.d.ts +9 -1
  25. package/dist/components/crossfade/Crossfade.d.ts +1 -1
  26. package/dist/components/data-table/DataTable.d.ts +3 -1
  27. package/dist/components/data-table/Head.d.ts +3 -1
  28. package/dist/components/data-table/types.d.ts +5 -0
  29. package/dist/components/digit-input/DigitInput.d.ts +1 -1
  30. package/dist/components/drawer/Drawer.d.ts +3 -2
  31. package/dist/components/field-list/FieldList.d.ts +18 -6
  32. package/dist/components/hint/Hint.d.ts +8 -2
  33. package/dist/components/index.d.ts +6 -7
  34. package/dist/components/input/Input.d.ts +27 -5
  35. package/dist/components/input/inputSuggestions.d.ts +39 -0
  36. package/dist/components/kanban/Kanban.d.ts +4 -9
  37. package/dist/components/list/List.d.ts +19 -5
  38. package/dist/components/message/Message.d.ts +15 -3
  39. package/dist/components/message/MessageSticker.d.ts +27 -0
  40. package/dist/components/message/formatMessageTime.d.ts +5 -2
  41. package/dist/components/modal/Modal.d.ts +3 -2
  42. package/dist/components/native-select/NativeSelect.d.ts +1 -1
  43. package/dist/components/pagination/Pagination.d.ts +5 -1
  44. package/dist/components/popover/Popover.d.ts +1 -1
  45. package/dist/components/radio/Radio.d.ts +11 -2
  46. package/dist/components/rich-text/RichText.d.ts +23 -0
  47. package/dist/components/scroll-container/ScrollContainer.d.ts +1 -1
  48. package/dist/components/scroll-container/scrollGlide.d.ts +26 -0
  49. package/dist/components/scroll-container/useScrollMotion.d.ts +25 -0
  50. package/dist/components/segmented-control/SegmentedControl.d.ts +1 -1
  51. package/dist/components/select/selectContext.d.ts +7 -0
  52. package/dist/components/slider/Slider.d.ts +2 -2
  53. package/dist/components/smart-filter/SmartFilter.d.ts +4 -5
  54. package/dist/components/switch/Switch.d.ts +6 -1
  55. package/dist/components/tag-select/TagSelect.d.ts +1 -1
  56. package/dist/components/textarea/Textarea.d.ts +6 -1
  57. package/dist/components/timeline/Timeline.d.ts +1 -1
  58. package/dist/icon-set.js +2 -2
  59. package/dist/index.css +1 -1
  60. package/dist/index.js +7 -9
  61. package/dist/internal/ChoiceField.d.ts +3 -1
  62. package/dist/internal/FieldFrame.d.ts +8 -2
  63. package/dist/internal/barPlan.d.ts +44 -0
  64. package/dist/internal/fieldCell.d.ts +1 -1
  65. package/dist/internal/formatClock.d.ts +23 -2
  66. package/dist/internal/leaveGuard.d.ts +21 -0
  67. package/dist/internal/messageList.d.ts +2 -0
  68. package/dist/internal/overlay/DialogParts.d.ts +27 -2
  69. package/dist/internal/overlay/FloatingPanel.d.ts +1 -1
  70. package/dist/internal/overlay/focus.d.ts +3 -2
  71. package/dist/internal/parts.d.ts +1 -1
  72. package/dist/internal/slot.d.ts +0 -30
  73. package/dist/internal/swatch.d.ts +5 -0
  74. package/dist/internal/tokenDefaults.d.ts +1 -0
  75. package/dist/layout/app-shell/AppShell.d.ts +19 -38
  76. package/dist/layout/index.d.ts +3 -3
  77. package/dist/layout/page/Page.d.ts +302 -0
  78. package/dist/layout/sidebar/Sidebar.d.ts +1 -1
  79. package/dist/skill/SKILL.md +10 -10
  80. package/dist/skill/anti-slop.md +106 -5
  81. package/dist/skill/api-contract.md +15 -8
  82. package/dist/skill/cheatsheet.md +46 -26
  83. package/dist/skill/checklist.md +12 -3
  84. package/dist/skill/choosing.md +34 -20
  85. package/dist/skill/components.md +4 -5
  86. package/dist/skill/composition.md +193 -154
  87. package/dist/skill/foundations.md +9 -9
  88. package/dist/skill/layouts.md +42 -99
  89. package/dist/skill/reference/components/avatar/COMPONENT.md +2 -2
  90. package/dist/skill/reference/components/avatar/examples/team-group.tsx +1 -1
  91. package/dist/skill/reference/components/badge/COMPONENT.md +14 -1
  92. package/dist/skill/reference/components/badge/examples/examples.module.css +7 -0
  93. package/dist/skill/reference/components/badge/examples/tag-row.tsx +34 -0
  94. package/dist/skill/reference/components/banner/COMPONENT.md +4 -4
  95. package/dist/skill/reference/components/banner/examples/examples.module.css +6 -1
  96. package/dist/skill/reference/components/banner/examples/page-strip.tsx +24 -22
  97. package/dist/skill/reference/components/breadcrumb/COMPONENT.md +18 -12
  98. package/dist/skill/reference/components/breadcrumb/examples/router.tsx +17 -0
  99. package/dist/skill/reference/components/button/COMPONENT.md +2 -1
  100. package/dist/skill/reference/components/button/examples/hold-to-confirm.tsx +1 -1
  101. package/dist/skill/reference/components/button/examples/on-colored-host.tsx +8 -8
  102. package/dist/skill/reference/components/button-group/COMPONENT.md +1 -0
  103. package/dist/skill/reference/components/card/COMPONENT.md +14 -8
  104. package/dist/skill/reference/components/card/examples/screen.module.css +1 -1
  105. package/dist/skill/reference/components/card/examples/screen.tsx +184 -198
  106. package/dist/skill/reference/components/card/examples/states.tsx +59 -0
  107. package/dist/skill/reference/components/chart-frame/COMPONENT.md +1 -1
  108. package/dist/skill/reference/components/chart-frame/examples/fill-height.tsx +9 -9
  109. package/dist/skill/reference/components/chat/COMPONENT.md +8 -5
  110. package/dist/skill/reference/components/chat/examples/screen.module.css +1 -1
  111. package/dist/skill/reference/components/chat/examples/screen.tsx +110 -117
  112. package/dist/skill/reference/components/chat/examples/time-zone.tsx +83 -0
  113. package/dist/skill/reference/components/chat-list/COMPONENT.md +14 -8
  114. package/dist/skill/reference/components/chat-list/examples/controlled.tsx +2 -2
  115. package/dist/skill/reference/components/chat-list/examples/examples.module.css +8 -0
  116. package/dist/skill/reference/components/chat-list/examples/links.tsx +1 -1
  117. package/dist/skill/reference/components/chat-list/examples/router.tsx +63 -0
  118. package/dist/skill/reference/components/checkbox/COMPONENT.md +1 -0
  119. package/dist/skill/reference/components/checkbox/examples/examples.module.css +3 -2
  120. package/dist/skill/reference/components/code-block/COMPONENT.md +1 -1
  121. package/dist/skill/reference/components/code-block/examples/color-scheme.tsx +2 -4
  122. package/dist/skill/reference/components/code-block/examples/examples.module.css +0 -11
  123. package/dist/skill/reference/components/color-field/COMPONENT.md +2 -1
  124. package/dist/skill/reference/components/color-picker/COMPONENT.md +31 -11
  125. package/dist/skill/reference/components/color-picker/examples/examples.module.css +2 -5
  126. package/dist/skill/reference/components/color-picker/examples/overview.tsx +5 -10
  127. package/dist/skill/reference/components/color-picker/examples/presets-custom.tsx +31 -0
  128. package/dist/skill/reference/components/color-picker/examples/sizes.tsx +4 -8
  129. package/dist/skill/reference/components/color-swatches/COMPONENT.md +1 -0
  130. package/dist/skill/reference/components/crossfade/COMPONENT.md +3 -3
  131. package/dist/skill/reference/components/crossfade/examples/screen.tsx +107 -112
  132. package/dist/skill/reference/components/data-table/COMPONENT.md +12 -7
  133. package/dist/skill/reference/components/data-table/examples/examples.module.css +9 -0
  134. package/dist/skill/reference/components/data-table/examples/numeric.tsx +9 -2
  135. package/dist/skill/reference/components/data-table/examples/screen.tsx +42 -52
  136. package/dist/skill/reference/components/data-table/examples/server.tsx +6 -2
  137. package/dist/skill/reference/components/datepicker/COMPONENT.md +3 -1
  138. package/dist/skill/reference/components/datepicker/examples/deadline.tsx +33 -0
  139. package/dist/skill/reference/components/datepicker/examples/examples.module.css +6 -0
  140. package/dist/skill/reference/components/datepicker/examples/inline-panel.tsx +3 -1
  141. package/dist/skill/reference/components/description-list/COMPONENT.md +1 -1
  142. package/dist/skill/reference/components/description-list/examples/screen.tsx +120 -127
  143. package/dist/skill/reference/components/digit-input/COMPONENT.md +1 -0
  144. package/dist/skill/reference/components/digit-input/examples/grouped.tsx +4 -4
  145. package/dist/skill/reference/components/digit-input/examples/validation.tsx +1 -1
  146. package/dist/skill/reference/components/divider/COMPONENT.md +2 -2
  147. package/dist/skill/reference/components/divider/examples/examples.module.css +4 -1
  148. package/dist/skill/reference/components/divider/examples/vertical.tsx +22 -9
  149. package/dist/skill/reference/components/dnd/examples/examples.module.css +3 -1
  150. package/dist/skill/reference/components/drawer/COMPONENT.md +16 -3
  151. package/dist/skill/reference/components/drawer/examples/client-card.tsx +32 -8
  152. package/dist/skill/reference/components/drawer/examples/placement.tsx +26 -31
  153. package/dist/skill/reference/components/drawer/examples/screen.tsx +137 -160
  154. package/dist/skill/reference/components/dropdown/COMPONENT.md +1 -1
  155. package/dist/skill/reference/components/example-frame/COMPONENT.md +3 -3
  156. package/dist/skill/reference/components/field-list/COMPONENT.md +15 -3
  157. package/dist/skill/reference/components/field-list/examples/saving.tsx +83 -0
  158. package/dist/skill/reference/components/field-list/examples/screen.module.css +1 -1
  159. package/dist/skill/reference/components/field-list/examples/screen.tsx +19 -19
  160. package/dist/skill/reference/components/field-list/examples/totals.tsx +82 -0
  161. package/dist/skill/reference/components/fieldset/COMPONENT.md +1 -1
  162. package/dist/skill/reference/components/fieldset/examples/states.tsx +1 -1
  163. package/dist/skill/reference/components/file-upload/COMPONENT.md +2 -1
  164. package/dist/skill/reference/components/file-upload/examples/screen.module.css +2 -2
  165. package/dist/skill/reference/components/file-upload/examples/screen.tsx +65 -81
  166. package/dist/skill/reference/components/gallery/COMPONENT.md +1 -0
  167. package/dist/skill/reference/components/gantt/COMPONENT.md +1 -1
  168. package/dist/skill/reference/components/gantt/examples/screen.module.css +1 -1
  169. package/dist/skill/reference/components/gantt/examples/screen.tsx +55 -73
  170. package/dist/skill/reference/components/hint/COMPONENT.md +16 -2
  171. package/dist/skill/reference/components/hint/examples/examples.module.css +10 -1
  172. package/dist/skill/reference/components/hint/examples/overview.tsx +1 -1
  173. package/dist/skill/reference/components/hint/examples/variants.tsx +48 -0
  174. package/dist/skill/reference/components/input/COMPONENT.md +39 -9
  175. package/dist/skill/reference/components/input/examples/affixes.tsx +4 -2
  176. package/dist/skill/reference/components/input/examples/dismiss.tsx +29 -0
  177. package/dist/skill/reference/components/input/examples/suggestions.tsx +26 -0
  178. package/dist/skill/reference/components/input/examples/time.tsx +24 -0
  179. package/dist/skill/reference/components/input/examples/with-select.tsx +44 -0
  180. package/dist/skill/reference/components/kanban/COMPONENT.md +7 -7
  181. package/dist/skill/reference/components/kanban/examples/columns.tsx +4 -2
  182. package/dist/skill/reference/components/kanban/examples/screen.module.css +1 -1
  183. package/dist/skill/reference/components/kanban/examples/screen.tsx +50 -65
  184. package/dist/skill/reference/components/kbd/COMPONENT.md +1 -1
  185. package/dist/skill/reference/components/label/examples/examples.module.css +12 -1
  186. package/dist/skill/reference/components/label/examples/overview.tsx +1 -1
  187. package/dist/skill/reference/components/list/COMPONENT.md +26 -10
  188. package/dist/skill/reference/components/list/examples/row-controls.tsx +80 -0
  189. package/dist/skill/reference/components/list/examples/with-icon.tsx +23 -2
  190. package/dist/skill/reference/components/login-form/COMPONENT.md +8 -7
  191. package/dist/skill/reference/components/login-form/examples/states.tsx +12 -14
  192. package/dist/skill/reference/components/media-viewer/examples/controlled.tsx +16 -16
  193. package/dist/skill/reference/components/media-viewer/examples/examples.module.css +1 -3
  194. package/dist/skill/reference/components/message/COMPONENT.md +30 -9
  195. package/dist/skill/reference/components/message/examples/preview.tsx +28 -0
  196. package/dist/skill/reference/components/message/examples/sticker.tsx +35 -0
  197. package/dist/skill/reference/components/modal/COMPONENT.md +15 -3
  198. package/dist/skill/reference/components/modal/examples/long-content.tsx +37 -18
  199. package/dist/skill/reference/components/native-select/COMPONENT.md +1 -0
  200. package/dist/skill/reference/components/notification/COMPONENT.md +1 -1
  201. package/dist/skill/reference/components/pagination/COMPONENT.md +11 -3
  202. package/dist/skill/reference/components/pagination/examples/controlled.tsx +2 -1
  203. package/dist/skill/reference/components/popover/COMPONENT.md +3 -2
  204. package/dist/skill/reference/components/popover/examples/width.tsx +13 -1
  205. package/dist/skill/reference/components/radio/COMPONENT.md +2 -0
  206. package/dist/skill/reference/components/rich-text/COMPONENT.md +93 -0
  207. package/dist/skill/reference/components/rich-text/examples/overview.tsx +19 -0
  208. package/dist/skill/reference/components/scroll-container/COMPONENT.md +8 -5
  209. package/dist/skill/reference/components/segmented-control/COMPONENT.md +1 -0
  210. package/dist/skill/reference/components/segmented-control/examples/in-form.tsx +1 -1
  211. package/dist/skill/reference/components/select/COMPONENT.md +7 -3
  212. package/dist/skill/reference/components/slider/COMPONENT.md +4 -3
  213. package/dist/skill/reference/components/slider/examples/controlled.tsx +1 -1
  214. package/dist/skill/reference/components/slider/examples/states.tsx +14 -10
  215. package/dist/skill/reference/components/smart-filter/COMPONENT.md +13 -13
  216. package/dist/skill/reference/components/smart-filter/examples/examples.module.css +3 -0
  217. package/dist/skill/reference/components/smart-filter/examples/many-values.tsx +12 -8
  218. package/dist/skill/reference/components/smart-filter/examples/sizes.tsx +7 -3
  219. package/dist/skill/reference/components/sparkline/COMPONENT.md +1 -0
  220. package/dist/skill/reference/components/sparkline/examples/curve.tsx +16 -11
  221. package/dist/skill/reference/components/sparkline/examples/states.tsx +14 -10
  222. package/dist/skill/reference/components/switch/COMPONENT.md +2 -1
  223. package/dist/skill/reference/components/tabs/COMPONENT.md +1 -1
  224. package/dist/skill/reference/components/tag-select/COMPONENT.md +1 -0
  225. package/dist/skill/reference/components/textarea/COMPONENT.md +1 -0
  226. package/dist/skill/reference/components/timeline/COMPONENT.md +3 -3
  227. package/dist/skill/reference/components/timeline/examples/structure.tsx +2 -1
  228. package/dist/skill/reference/components/typography/COMPONENT.md +2 -2
  229. package/dist/skill/reference/foundation.md +15 -11
  230. package/dist/skill/reference/layout/app-shell/COMPONENT.md +25 -38
  231. package/dist/skill/reference/layout/app-shell/examples/footer.tsx +10 -10
  232. package/dist/skill/reference/layout/app-shell/examples/overview.tsx +20 -22
  233. package/dist/skill/reference/layout/app-shell/examples/screen.module.css +2 -2
  234. package/dist/skill/reference/layout/app-shell/examples/screen.tsx +25 -30
  235. package/dist/skill/reference/layout/app-shell/examples/template.tsx +13 -17
  236. package/dist/skill/reference/layout/bottom-nav/COMPONENT.md +4 -3
  237. package/dist/skill/reference/layout/bottom-nav/examples/floating-action.tsx +10 -19
  238. package/dist/skill/reference/layout/bottom-nav/examples/floating.tsx +10 -19
  239. package/dist/skill/reference/layout/bottom-nav/examples/in-app-shell.tsx +11 -19
  240. package/dist/skill/reference/layout/page/COMPONENT.md +382 -0
  241. package/dist/skill/reference/layout/page/examples/actions-collapse.tsx +45 -0
  242. package/dist/skill/reference/layout/page/examples/collapse.tsx +68 -0
  243. package/dist/skill/reference/layout/page/examples/examples.module.css +92 -0
  244. package/{src/components/page-content → dist/skill/reference/layout/page}/examples/grid.tsx +15 -15
  245. package/dist/skill/reference/layout/page/examples/guard.tsx +87 -0
  246. package/dist/skill/reference/{components/page-content → layout/page}/examples/list-detail.tsx +14 -14
  247. package/dist/skill/reference/layout/page/examples/loading.tsx +57 -0
  248. package/dist/skill/reference/layout/page/examples/narrow.tsx +75 -0
  249. package/dist/skill/reference/layout/page/examples/overview.tsx +57 -0
  250. package/dist/skill/reference/{components/page-content → layout/page}/examples/screen.module.css +1 -1
  251. package/{src/components/page-content → dist/skill/reference/layout/page}/examples/screen.tsx +29 -19
  252. package/dist/skill/reference/{components/page-content → layout/page}/examples/sections.tsx +17 -24
  253. package/dist/skill/reference/layout/page/examples/structure.tsx +41 -0
  254. package/dist/skill/reference/{components/page-toolbar/examples/narrow.tsx → layout/page/examples/tools.tsx} +38 -35
  255. package/dist/skill/reference/layout/page/examples/top-bar.tsx +85 -0
  256. package/dist/skill/reference/{components/page-content → layout/page}/examples/variants.tsx +7 -7
  257. package/dist/skill/reference/layout/sidebar/COMPONENT.md +6 -4
  258. package/dist/skill/reference/layout/sidebar/examples/dismiss.tsx +10 -7
  259. package/dist/skill/reference/layout/sidebar/examples/narrow.tsx +11 -8
  260. package/dist/skill/responsive.md +94 -75
  261. package/dist/skill/ux.md +5 -3
  262. package/dist/tokens/layers.d.ts +2 -0
  263. package/dist/tokens/primitives.d.ts +12 -2
  264. package/dist/tokens/semantic.d.ts +9 -0
  265. package/dist/tokens/themes/dark.d.ts +7 -2
  266. package/package.json +2 -2
  267. package/src/components/avatar/COMPONENT.md +2 -2
  268. package/src/components/avatar/examples/team-group.tsx +1 -1
  269. package/src/components/badge/COMPONENT.md +14 -1
  270. package/src/components/badge/examples/examples.module.css +7 -0
  271. package/src/components/badge/examples/tag-row.tsx +34 -0
  272. package/src/components/banner/COMPONENT.md +4 -4
  273. package/src/components/banner/examples/examples.module.css +6 -1
  274. package/src/components/banner/examples/page-strip.tsx +24 -22
  275. package/src/components/breadcrumb/COMPONENT.md +18 -12
  276. package/src/components/breadcrumb/examples/router.tsx +17 -0
  277. package/src/components/button/COMPONENT.md +2 -1
  278. package/src/components/button/examples/hold-to-confirm.tsx +1 -1
  279. package/src/components/button/examples/on-colored-host.tsx +8 -8
  280. package/src/components/button-group/COMPONENT.md +1 -0
  281. package/src/components/card/COMPONENT.md +14 -8
  282. package/src/components/card/examples/screen.module.css +1 -1
  283. package/src/components/card/examples/screen.tsx +184 -198
  284. package/src/components/card/examples/states.tsx +59 -0
  285. package/src/components/chart-frame/COMPONENT.md +1 -1
  286. package/src/components/chart-frame/examples/fill-height.tsx +9 -9
  287. package/src/components/chat/COMPONENT.md +8 -5
  288. package/src/components/chat/examples/screen.module.css +1 -1
  289. package/src/components/chat/examples/screen.tsx +110 -117
  290. package/src/components/chat/examples/time-zone.tsx +83 -0
  291. package/src/components/chat-list/COMPONENT.md +14 -8
  292. package/src/components/chat-list/examples/controlled.tsx +2 -2
  293. package/src/components/chat-list/examples/examples.module.css +8 -0
  294. package/src/components/chat-list/examples/links.tsx +1 -1
  295. package/src/components/chat-list/examples/router.tsx +63 -0
  296. package/src/components/checkbox/COMPONENT.md +1 -0
  297. package/src/components/checkbox/examples/examples.module.css +3 -2
  298. package/src/components/code-block/COMPONENT.md +1 -1
  299. package/src/components/code-block/examples/color-scheme.tsx +2 -4
  300. package/src/components/code-block/examples/examples.module.css +0 -11
  301. package/src/components/color-field/COMPONENT.md +2 -1
  302. package/src/components/color-picker/COMPONENT.md +31 -11
  303. package/src/components/color-picker/examples/examples.module.css +2 -5
  304. package/src/components/color-picker/examples/overview.tsx +5 -10
  305. package/src/components/color-picker/examples/presets-custom.tsx +31 -0
  306. package/src/components/color-picker/examples/sizes.tsx +4 -8
  307. package/src/components/color-swatches/COMPONENT.md +1 -0
  308. package/src/components/crossfade/COMPONENT.md +3 -3
  309. package/src/components/crossfade/examples/screen.tsx +107 -112
  310. package/src/components/data-table/COMPONENT.md +12 -7
  311. package/src/components/data-table/examples/examples.module.css +9 -0
  312. package/src/components/data-table/examples/numeric.tsx +9 -2
  313. package/src/components/data-table/examples/screen.tsx +42 -52
  314. package/src/components/data-table/examples/server.tsx +6 -2
  315. package/src/components/datepicker/COMPONENT.md +3 -1
  316. package/src/components/datepicker/examples/deadline.tsx +33 -0
  317. package/src/components/datepicker/examples/examples.module.css +6 -0
  318. package/src/components/datepicker/examples/inline-panel.tsx +3 -1
  319. package/src/components/description-list/COMPONENT.md +1 -1
  320. package/src/components/description-list/examples/screen.tsx +120 -127
  321. package/src/components/digit-input/COMPONENT.md +1 -0
  322. package/src/components/digit-input/examples/grouped.tsx +4 -4
  323. package/src/components/digit-input/examples/validation.tsx +1 -1
  324. package/src/components/divider/COMPONENT.md +2 -2
  325. package/src/components/divider/examples/examples.module.css +4 -1
  326. package/src/components/divider/examples/vertical.tsx +22 -9
  327. package/src/components/dnd/examples/examples.module.css +3 -1
  328. package/src/components/drawer/COMPONENT.md +16 -3
  329. package/src/components/drawer/examples/client-card.tsx +32 -8
  330. package/src/components/drawer/examples/placement.tsx +26 -31
  331. package/src/components/drawer/examples/screen.tsx +137 -160
  332. package/src/components/dropdown/COMPONENT.md +1 -1
  333. package/src/components/example-frame/COMPONENT.md +3 -3
  334. package/src/components/field-list/COMPONENT.md +15 -3
  335. package/src/components/field-list/examples/saving.tsx +83 -0
  336. package/src/components/field-list/examples/screen.module.css +1 -1
  337. package/src/components/field-list/examples/screen.tsx +19 -19
  338. package/src/components/field-list/examples/totals.tsx +82 -0
  339. package/src/components/fieldset/COMPONENT.md +1 -1
  340. package/src/components/fieldset/examples/states.tsx +1 -1
  341. package/src/components/file-upload/COMPONENT.md +2 -1
  342. package/src/components/file-upload/examples/screen.module.css +2 -2
  343. package/src/components/file-upload/examples/screen.tsx +65 -81
  344. package/src/components/gallery/COMPONENT.md +1 -0
  345. package/src/components/gantt/COMPONENT.md +1 -1
  346. package/src/components/gantt/examples/screen.module.css +1 -1
  347. package/src/components/gantt/examples/screen.tsx +55 -73
  348. package/src/components/hint/COMPONENT.md +16 -2
  349. package/src/components/hint/examples/examples.module.css +10 -1
  350. package/src/components/hint/examples/overview.tsx +1 -1
  351. package/src/components/hint/examples/variants.tsx +48 -0
  352. package/src/components/input/COMPONENT.md +39 -9
  353. package/src/components/input/examples/affixes.tsx +4 -2
  354. package/src/components/input/examples/dismiss.tsx +29 -0
  355. package/src/components/input/examples/suggestions.tsx +26 -0
  356. package/src/components/input/examples/time.tsx +24 -0
  357. package/src/components/input/examples/with-select.tsx +44 -0
  358. package/src/components/kanban/COMPONENT.md +7 -7
  359. package/src/components/kanban/examples/columns.tsx +4 -2
  360. package/src/components/kanban/examples/screen.module.css +1 -1
  361. package/src/components/kanban/examples/screen.tsx +50 -65
  362. package/src/components/kbd/COMPONENT.md +1 -1
  363. package/src/components/label/examples/examples.module.css +12 -1
  364. package/src/components/label/examples/overview.tsx +1 -1
  365. package/src/components/list/COMPONENT.md +26 -10
  366. package/src/components/list/examples/row-controls.tsx +80 -0
  367. package/src/components/list/examples/with-icon.tsx +23 -2
  368. package/src/components/login-form/COMPONENT.md +8 -7
  369. package/src/components/login-form/examples/states.tsx +12 -14
  370. package/src/components/media-viewer/examples/controlled.tsx +16 -16
  371. package/src/components/media-viewer/examples/examples.module.css +1 -3
  372. package/src/components/message/COMPONENT.md +30 -9
  373. package/src/components/message/examples/preview.tsx +28 -0
  374. package/src/components/message/examples/sticker.tsx +35 -0
  375. package/src/components/modal/COMPONENT.md +15 -3
  376. package/src/components/modal/examples/long-content.tsx +37 -18
  377. package/src/components/native-select/COMPONENT.md +1 -0
  378. package/src/components/notification/COMPONENT.md +1 -1
  379. package/src/components/pagination/COMPONENT.md +11 -3
  380. package/src/components/pagination/examples/controlled.tsx +2 -1
  381. package/src/components/popover/COMPONENT.md +3 -2
  382. package/src/components/popover/examples/width.tsx +13 -1
  383. package/src/components/radio/COMPONENT.md +2 -0
  384. package/src/components/rich-text/COMPONENT.md +93 -0
  385. package/src/components/rich-text/examples/overview.tsx +19 -0
  386. package/src/components/scroll-container/COMPONENT.md +8 -5
  387. package/src/components/segmented-control/COMPONENT.md +1 -0
  388. package/src/components/segmented-control/examples/in-form.tsx +1 -1
  389. package/src/components/select/COMPONENT.md +7 -3
  390. package/src/components/slider/COMPONENT.md +4 -3
  391. package/src/components/slider/examples/controlled.tsx +1 -1
  392. package/src/components/slider/examples/states.tsx +14 -10
  393. package/src/components/smart-filter/COMPONENT.md +13 -13
  394. package/src/components/smart-filter/examples/examples.module.css +3 -0
  395. package/src/components/smart-filter/examples/many-values.tsx +12 -8
  396. package/src/components/smart-filter/examples/sizes.tsx +7 -3
  397. package/src/components/sparkline/COMPONENT.md +1 -0
  398. package/src/components/sparkline/examples/curve.tsx +16 -11
  399. package/src/components/sparkline/examples/states.tsx +14 -10
  400. package/src/components/switch/COMPONENT.md +2 -1
  401. package/src/components/tabs/COMPONENT.md +1 -1
  402. package/src/components/tag-select/COMPONENT.md +1 -0
  403. package/src/components/textarea/COMPONENT.md +1 -0
  404. package/src/components/timeline/COMPONENT.md +3 -3
  405. package/src/components/timeline/examples/structure.tsx +2 -1
  406. package/src/components/typography/COMPONENT.md +2 -2
  407. package/src/layout/app-shell/COMPONENT.md +25 -38
  408. package/src/layout/app-shell/examples/footer.tsx +10 -10
  409. package/src/layout/app-shell/examples/overview.tsx +20 -22
  410. package/src/layout/app-shell/examples/screen.module.css +2 -2
  411. package/src/layout/app-shell/examples/screen.tsx +25 -30
  412. package/src/layout/app-shell/examples/template.tsx +13 -17
  413. package/src/layout/bottom-nav/COMPONENT.md +4 -3
  414. package/src/layout/bottom-nav/examples/floating-action.tsx +10 -19
  415. package/src/layout/bottom-nav/examples/floating.tsx +10 -19
  416. package/src/layout/bottom-nav/examples/in-app-shell.tsx +11 -19
  417. package/src/layout/page/COMPONENT.md +382 -0
  418. package/src/layout/page/examples/actions-collapse.tsx +45 -0
  419. package/src/layout/page/examples/collapse.tsx +68 -0
  420. package/src/layout/page/examples/examples.module.css +92 -0
  421. package/{dist/skill/reference/components/page-content → src/layout/page}/examples/grid.tsx +15 -15
  422. package/src/layout/page/examples/guard.tsx +87 -0
  423. package/src/{components/page-content → layout/page}/examples/list-detail.tsx +14 -14
  424. package/src/layout/page/examples/loading.tsx +57 -0
  425. package/src/layout/page/examples/narrow.tsx +75 -0
  426. package/src/layout/page/examples/overview.tsx +57 -0
  427. package/src/{components/page-content → layout/page}/examples/screen.module.css +1 -1
  428. package/{dist/skill/reference/components/page-content → src/layout/page}/examples/screen.tsx +29 -19
  429. package/src/{components/page-content → layout/page}/examples/sections.tsx +17 -24
  430. package/src/layout/page/examples/structure.tsx +41 -0
  431. package/src/{components/page-toolbar/examples/narrow.tsx → layout/page/examples/tools.tsx} +38 -35
  432. package/src/layout/page/examples/top-bar.tsx +85 -0
  433. package/src/{components/page-content → layout/page}/examples/variants.tsx +7 -7
  434. package/src/layout/sidebar/COMPONENT.md +6 -4
  435. package/src/layout/sidebar/examples/dismiss.tsx +10 -7
  436. package/src/layout/sidebar/examples/narrow.tsx +11 -8
  437. package/src/styles/theme-dark.css +12 -10
  438. package/src/styles/theme-light.css +4 -0
  439. package/src/styles/tokens.css +3 -1
  440. package/dist/components/page-content/PageContent.d.ts +0 -192
  441. package/dist/components/page-toolbar/PageToolbar.d.ts +0 -55
  442. package/dist/components/scroll-container/useWheelToInline.d.ts +0 -10
  443. package/dist/layout/app-header/AppHeader.d.ts +0 -118
  444. package/dist/skill/reference/components/page-content/COMPONENT.md +0 -264
  445. package/dist/skill/reference/components/page-content/examples/examples.module.css +0 -56
  446. package/dist/skill/reference/components/page-content/examples/narrow.tsx +0 -25
  447. package/dist/skill/reference/components/page-content/examples/overview.tsx +0 -41
  448. package/dist/skill/reference/components/page-toolbar/COMPONENT.md +0 -147
  449. package/dist/skill/reference/components/page-toolbar/examples/examples.module.css +0 -16
  450. package/dist/skill/reference/components/page-toolbar/examples/overview.tsx +0 -113
  451. package/dist/skill/reference/components/page-toolbar/examples/save-changes.tsx +0 -43
  452. package/dist/skill/reference/components/page-toolbar/examples/without-search.tsx +0 -60
  453. package/dist/skill/reference/layout/app-header/COMPONENT.md +0 -187
  454. package/dist/skill/reference/layout/app-header/examples/breadcrumbs.tsx +0 -37
  455. package/dist/skill/reference/layout/app-header/examples/examples.module.css +0 -28
  456. package/dist/skill/reference/layout/app-header/examples/in-app-shell.tsx +0 -67
  457. package/dist/skill/reference/layout/app-header/examples/narrow.tsx +0 -66
  458. package/dist/skill/reference/layout/app-header/examples/overview.tsx +0 -34
  459. package/dist/skill/reference/layout/app-header/examples/page-title.tsx +0 -78
  460. package/dist/skill/reference/layout/app-shell/examples/contained.tsx +0 -30
  461. package/src/components/page-content/COMPONENT.md +0 -264
  462. package/src/components/page-content/examples/examples.module.css +0 -56
  463. package/src/components/page-content/examples/narrow.tsx +0 -25
  464. package/src/components/page-content/examples/overview.tsx +0 -41
  465. package/src/components/page-toolbar/COMPONENT.md +0 -147
  466. package/src/components/page-toolbar/examples/examples.module.css +0 -16
  467. package/src/components/page-toolbar/examples/overview.tsx +0 -113
  468. package/src/components/page-toolbar/examples/save-changes.tsx +0 -43
  469. package/src/components/page-toolbar/examples/without-search.tsx +0 -60
  470. package/src/layout/app-header/COMPONENT.md +0 -187
  471. package/src/layout/app-header/examples/breadcrumbs.tsx +0 -37
  472. package/src/layout/app-header/examples/examples.module.css +0 -28
  473. package/src/layout/app-header/examples/in-app-shell.tsx +0 -67
  474. package/src/layout/app-header/examples/narrow.tsx +0 -66
  475. package/src/layout/app-header/examples/overview.tsx +0 -34
  476. package/src/layout/app-header/examples/page-title.tsx +0 -78
  477. package/src/layout/app-shell/examples/contained.tsx +0 -30
@@ -0,0 +1,35 @@
1
+ /** Stickers in a conversation: a picture by its address and a video sticker in your own player, no bubble, the time on a pill over the corner — `Message.Sticker`, `src`, `loading`. */
2
+ import { Message } from "prime-ui-kit";
3
+ import * as React from "react";
4
+
5
+ import styles from "./examples.module.css";
6
+
7
+ const THUMBS_UP = "https://fonts.gstatic.com/s/e/notoemoji/latest/1f44d/512.webp";
8
+ const CLIP = "https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4";
9
+
10
+ export default function MessageStickerExample() {
11
+ const [clipReady, setClipReady] = React.useState(false);
12
+
13
+ return (
14
+ <div className={styles.thread}>
15
+ <Message.Root value="sticker-text" time="10:42">
16
+ <Message.Text>Отгрузку подтвердили, машина выезжает в 14:00.</Message.Text>
17
+ </Message.Root>
18
+ <Message.Root value="sticker-image" direction="outgoing" time="10:43" status="read">
19
+ <Message.Sticker src={THUMBS_UP} aria-label="Стикер «Класс»" />
20
+ </Message.Root>
21
+ <Message.Root value="sticker-video" time="10:44">
22
+ <Message.Sticker aria-label="Видеостикер «Цветок»" loading={!clipReady}>
23
+ <video
24
+ src={CLIP}
25
+ autoPlay
26
+ loop
27
+ muted
28
+ playsInline
29
+ onLoadedData={() => setClipReady(true)}
30
+ />
31
+ </Message.Sticker>
32
+ </Message.Root>
33
+ </div>
34
+ );
35
+ }
@@ -34,6 +34,7 @@ Modal.Root state and dismiss policy (no DOM)
34
34
  │ ├── Modal.Description <p>, describes the dialog
35
35
  │ └── Modal.Actions row of tier-s controls before the close button
36
36
  ├── Modal.Body the only scrolling zone
37
+ │ └── Modal.Section <section>: <h3> label, description, Modal.Actions at the heading's end
37
38
  └── Modal.Footer actions, primary last
38
39
  ├── Modal.Meta <p>, muted status at the start
39
40
  ├── Modal.Close clones its child; closes on click
@@ -83,7 +84,7 @@ No DOM, no ref. State and dismiss policy.
83
84
  | `…rest` | `HTMLAttributes<HTMLElement>` | — | `className` and the other attributes of the `<header>`. |
84
85
 
85
86
  ### Modal.Actions
86
- `ref` → `HTMLDivElement`. A row of controls at the end of the header, before the close button: a status Badge, a ⋯ Dropdown, an icon button. Controls inside take tier `s`.
87
+ `ref` → `HTMLDivElement`. A row of controls at the end of the header, before the close button: a status Badge, a ⋯ Dropdown, an icon button; or at the end of a `Modal.Section` heading. Controls inside take tier `s`.
87
88
 
88
89
  | Prop | Type | Default | Description |
89
90
  |---|---|---|---|
@@ -112,6 +113,15 @@ No DOM, no ref. State and dismiss policy.
112
113
  |---|---|---|---|
113
114
  | `…rest` | `HTMLAttributes<HTMLDivElement>` | — | `className`, `children` and the other attributes of the zone. |
114
115
 
116
+ ### Modal.Section
117
+ `ref` → `HTMLElement`. A titled `<section>` of the body: an `<h3>` (title-s, under the `<h2>` title), an optional description, a `Modal.Actions` at the end of the heading row; the content 16 below, sections 32 apart. Fields group in a `Fieldset`.
118
+
119
+ | Prop | Type | Default | Description |
120
+ |---|---|---|---|
121
+ | `label` | `ReactNode` | — (required) | The heading of the section; it names the `<section>`. |
122
+ | `description` | `ReactNode` | — | One line of context under the heading (body-s). |
123
+ | `…rest` | `Omit<HTMLAttributes<HTMLElement>, "title">` | — | `children` (the content and an optional `Modal.Actions`), `className` and the other attributes of the `<section>`. |
124
+
115
125
  ### Modal.Footer
116
126
  `ref` → `HTMLElement`. Renders `<footer>` with the actions, primary last, and an optional `Meta` at the start.
117
127
 
@@ -168,7 +178,7 @@ Below 640px of viewport a centred dialog of every size becomes a full-width bott
168
178
  | `fill` | Equal-width buttons in one row, gap 12 | Narrow dialogs with two actions | for `xs`, `s`, `m` |
169
179
  | `end` | Auto-width buttons at the end, gap 8 | Wide dialogs | for `l`, `xl` |
170
180
 
171
- With a `Modal.Meta` the footer is a row in any layout: the status takes the free room at the start, the buttons keep their width at the end. On phones (viewport below 640px, where the dialog is a bottom sheet) and in a dialog narrower than 360px, actions stack full width in DOM order (primary last), the status above them.
181
+ With a `Modal.Meta` the footer is a row in any layout: the status takes the free room at the start, the buttons keep their width at the end and stay one row — when the footer runs short the status goes above them first. On phones (viewport below 640px, where the dialog is a bottom sheet) and in a dialog narrower than 360px, actions stack full width in DOM order (primary last), the status above them.
172
182
 
173
183
  ### tone (Icon)
174
184
  | Value | Looks like | Use when | Default |
@@ -221,6 +231,7 @@ Motion (`overlayMotion`): the scrim fades in and out over `base`; the dialog fad
221
231
  - Max height = viewport minus `--prime-modal-viewport-padding` on both sides; only the body scrolls.
222
232
  - Tabs in the header: a `Tabs.List` inside `Modal.Header` (with `Tabs.Root` around the header and the body) spans the header's last row. The header becomes the tab strip, edge to edge and without the hairline; the active tab is the body rising into it, the panels sit in the body.
223
233
  - Fields inside take the floating layer's fill; a card inside is the next layer (`floating-1`), a flat tile. Group fields with a 20 gap.
234
+ - Titled groups of a long body: `Modal.Section label` — an `<h3>` under the dialog's `<h2>` title, an optional `description`, a `Modal.Actions` at the end of its heading row; content 16 below, sections 32 apart. A group of fields is a `Fieldset`.
224
235
  - Narrow viewport (< 640px), `placement="center"`: the shared bottom-sheet surface (`src/internal/sheet.module.css`) — full width, rounded top, a grab handle strip on top while it swipes, up to the sheet top gap high, the bottom safe-area inset below the content.
225
236
  - `placement="top"`: the dialog hangs from a line 12% of the viewport down (between `--prime-modal-viewport-padding` and `--prime-space-24`) and grows downward.
226
237
 
@@ -262,7 +273,7 @@ Motion (`overlayMotion`): the scrim fades in and out over `base`; the dialog fad
262
273
  | [overview.tsx](examples/overview.tsx) | A trigger opens a dialog with a title, a field and two actions; Enter presses the confirm — `Modal.Trigger`, `Modal.Confirm`. |
263
274
  | [structure.tsx](examples/structure.tsx) | Optional parts: an icon tile with a header-only notice, and a header with a status before the close button and a footer with no body between them — `Modal.Icon`, `Modal.Actions`, `Modal.Footer`. |
264
275
  | [sizes.tsx](examples/sizes.tsx) | Every width; xs, s and m fill the footer with equal buttons, l and xl align them to the end — `size`. |
265
- | [long-content.tsx](examples/long-content.tsx) | A long body scrolls on its own while the header and the footer stay in place; the primary closes the dialog and is the Enter target — `Modal.Body`, `Modal.Confirm`. |
276
+ | [long-content.tsx](examples/long-content.tsx) | A long body in titled sections scrolls on its own while the header and the footer stay in place; the primary closes the dialog and is the Enter target — `Modal.Body`, `Modal.Section`, `Modal.Confirm`. |
266
277
  | [custom-container.tsx](examples/custom-container.tsx) | The dialog portals into a given node instead of the document body — `container`. |
267
278
  | [guard.tsx](examples/guard.tsx) | An edit form that holds the dialog: changes make any dismiss ask first and show a note in the footer, the submit button saves the form, and while saving nothing closes it — `Modal.Guard`, `Modal.Meta`. |
268
279
  | [enter-key.tsx](examples/enter-key.tsx) | Enter in a dialog: handing a workspace over takes a click, never Enter in its field; in the tags dialog Enter adds the typed tag instead of closing — `confirmOnEnter`, `onEnterConfirm`. |
@@ -274,6 +285,7 @@ Motion (`overlayMotion`): the scrim fades in and out over `base`; the dialog fad
274
285
  - A destructive confirm built as a Modal → use ConfirmDialog. A destructive step that needs input (type the name to delete) stays a Modal with `closeOnOutsideClick={false}`.
275
286
  - Primary action not in `Modal.Confirm` → Enter does nothing; wrap it. In a form, the `type="submit"` button is the primary and stays outside `Modal.Confirm`: Enter in a field submits the form.
276
287
  - Primary action first in the footer → put it last (DOM order is the visual order).
288
+ - A hand-made heading row (`Typography as="h3"` + buttons) over a group in the body → `Modal.Section label` with `Modal.Actions`.
277
289
  - Busy or unsaved state lifted out of the form into Root props → put `Modal.Guard` next to the form, inside Content.
278
290
  - `key` or a conditional around `Modal.Root` to reset a form → the dialog unmounts at once, without its exit; keep the Root mounted and drive `open`.
279
291
  - Scrolling wrapper inside Modal.Body → Body already scrolls.
@@ -1,19 +1,34 @@
1
- /** A long body scrolls on its own while the header and the footer stay in place; the primary closes the dialog and is the Enter target — `Modal.Body`, `Modal.Confirm`. */
1
+ /** A long body in titled sections scrolls on its own while the header and the footer stay in place; the primary closes the dialog and is the Enter target — `Modal.Body`, `Modal.Section`, `Modal.Confirm`. */
2
2
  import { Button, Modal, Typography } from "prime-ui-kit";
3
3
 
4
- const TERMS = [
5
- "Исполнитель обрабатывает персональные данные только для оказания услуги.",
6
- "Данные не передаются третьим лицам без письменного согласия заказчика.",
7
- "Доступ к данным получают только сотрудники, которым он нужен для работы.",
8
- "Резервные копии хранятся в зашифрованном виде в дата-центрах на территории РФ.",
9
- "Заказчик может запросить выгрузку своих данных в течение 10 рабочих дней.",
10
- "По запросу заказчика данные удаляются в течение 30 дней после расторжения договора.",
11
- "О каждом инциденте безопасности исполнитель сообщает заказчику в течение 24 часов.",
12
- "Журналы доступа хранятся не меньше одного года и выдаются по запросу.",
13
- "Исполнитель ежегодно проходит внешний аудит защиты информации.",
14
- "Субподрядчики допускаются только с согласия заказчика и на тех же условиях.",
15
- "Изменения условий публикуются за 30 дней до вступления в силу.",
16
- "Споры решаются в арбитражном суде по месту нахождения исполнителя.",
4
+ const SECTIONS = [
5
+ {
6
+ title: "Обработка и хранение",
7
+ terms: [
8
+ "Исполнитель обрабатывает персональные данные только для оказания услуги.",
9
+ "Данные не передаются третьим лицам без письменного согласия заказчика.",
10
+ "Доступ к данным получают только сотрудники, которым он нужен для работы.",
11
+ "Резервные копии хранятся в зашифрованном виде в дата-центрах на территории РФ.",
12
+ ],
13
+ },
14
+ {
15
+ title: "Права заказчика",
16
+ terms: [
17
+ "Заказчик может запросить выгрузку своих данных в течение 10 рабочих дней.",
18
+ "По запросу заказчика данные удаляются в течение 30 дней после расторжения договора.",
19
+ "О каждом инциденте безопасности исполнитель сообщает заказчику в течение 24 часов.",
20
+ "Журналы доступа хранятся не меньше одного года и выдаются по запросу.",
21
+ ],
22
+ },
23
+ {
24
+ title: "Аудит и изменения",
25
+ terms: [
26
+ "Исполнитель ежегодно проходит внешний аудит защиты информации.",
27
+ "Субподрядчики допускаются только с согласия заказчика и на тех же условиях.",
28
+ "Изменения условий публикуются за 30 дней до вступления в силу.",
29
+ "Споры решаются в арбитражном суде по месту нахождения исполнителя.",
30
+ ],
31
+ },
17
32
  ];
18
33
 
19
34
  export default function ModalLongContentExample() {
@@ -30,10 +45,14 @@ export default function ModalLongContentExample() {
30
45
  <Modal.Description>Редакция от 1 октября 2026 года</Modal.Description>
31
46
  </Modal.Header>
32
47
  <Modal.Body>
33
- {TERMS.map((line) => (
34
- <Typography key={line} variant="body-m" tone="secondary">
35
- {line}
36
- </Typography>
48
+ {SECTIONS.map((section) => (
49
+ <Modal.Section key={section.title} label={section.title}>
50
+ {section.terms.map((line) => (
51
+ <Typography key={line} variant="body-m" tone="secondary">
52
+ {line}
53
+ </Typography>
54
+ ))}
55
+ </Modal.Section>
37
56
  ))}
38
57
  </Modal.Body>
39
58
  <Modal.Footer>
@@ -41,6 +41,7 @@ NativeSelect field frame: label row · control · support row
41
41
  |---|---|---|---|
42
42
  | `label` | `ReactNode` | — | Field label above; a `<label htmlFor>` of the select. |
43
43
  | `hint` | `ReactNode` | — | Support text under the field; linked by `aria-describedby`. |
44
+ | `hintTone` | `"neutral" \| "success" \| "warning" \| "danger"` | `"neutral"` | Status color of `hint` («Осталось 12 дней» in `warning`). The words carry the status, the color repeats it; an `error` replaces the hint and its tone. A validation error is `error`, never a `danger` hint. |
44
45
  | `error` | `ReactNode` | — | Error message; replaces the hint and implies `invalid`. |
45
46
  | `required` | `boolean` | `false` | Red `*` after the label and native `required`. |
46
47
  | `optional` | `boolean` | — | Muted `labels.optional` after the label. |
@@ -156,7 +156,7 @@ Collapsed stacks show up to 3 cards peeking behind each other. Hover or keyboard
156
156
  - Each stack is an `<ol>` named by the region label of its position; each card is an `<article>`: `role="status"` + `aria-live="polite"`, or `role="alert"` + `aria-live="assertive"` for `warning` / `danger`.
157
157
  - The icon and the countdown are `aria-hidden`; the close button is named by `labels.close`.
158
158
  - Focus never leaves with a toast: a card that goes while it holds focus hands it to the front card still open in its stack, else back to where focus came from.
159
- - A toast is a non-modal live region, not a layer of the overlay stack: Escape and a press elsewhere belong to the page and to the topmost open layer, so a toast takes no `closeOnEscape` / `closeOnOutsideClick` — it leaves by its timer, the close button, a swipe or `dismiss()`.
159
+ - A toast is a non-modal live region, not a layer of the overlay stack: Escape and a press elsewhere belong to the page and to the topmost open layer, so a toast takes no `closeOnEscape` / `closeOnOutsideClick` — it leaves by its timer, the close button, a swipe or `dismiss()`. The toasts stay usable above an open Modal or Drawer, and a press on a toast is outside no layer: it never closes the dialog below.
160
160
  - Do not keep the only copy of important information in a toast with a timer — use `persistent` or a Banner.
161
161
 
162
162
  ### Labels
@@ -44,6 +44,7 @@ Pagination <nav aria-label={labels.nav}>; size and compact mode
44
44
  | `siblingCount` | `number` | `1` | Pages on each side of the current one before an ellipsis (when `totalPages > 2·siblingCount+5`). |
45
45
  | `size` | `"xs" \| "s" \| "m" \| "l" \| "xl"` | host tier, else `"m"` | Control tier of the buttons: height 28 · 32 · 36 · 40 · 48. Without it the tier of its host, else `m`. |
46
46
  | `compact` | `boolean` | `false` | Always arrows + «current / total» instead of numbers. Without it the nav fills its parent and shows that view only below 22rem of its width. |
47
+ | `align` | `"start" \| "center" \| "end"` | `"center"` | Where the page numbers sit in the width the nav fills: centred under a list, `end` beside a range line (the DataTable footer). The compact view keeps its arrows at the edges. |
47
48
  | `labels` | `Partial<PaginationLabels>` | — | Built-in strings, see Labels. |
48
49
  | `…rest` | `Omit<HTMLAttributes<HTMLElement>, "defaultValue" \| "onChange">` | — | `className`, `data-*` and the other `<nav>` attributes; `aria-label` comes from `labels.nav`. |
49
50
 
@@ -52,9 +53,16 @@ Pagination <nav aria-label={labels.nav}>; size and compact mode
52
53
  ### compact
53
54
  | Value | Looks like | Use when | Default |
54
55
  |---|---|---|---|
55
- | `false` | fills the parent: arrows around page numbers right-aligned, «…» for skipped ranges; below 22rem of its width the compact view with arrows at the edges | list and table footers, anywhere the width varies | yes |
56
+ | `false` | fills the parent: arrows around page numbers placed by `align`, «…» for skipped ranges; below 22rem of its width the compact view with arrows at the edges | list and table footers, anywhere the width varies | yes |
56
57
  | `true` | arrows around «3 / 12» (current in primary medium, total muted, tabular figures) at any width | tight toolbars, a pager that must never show numbers | |
57
58
 
59
+ ### align
60
+ | Value | Looks like | Use when | Default |
61
+ |---|---|---|---|
62
+ | `center` | the numbers centred in the width the nav fills | a pager under a list or a grid of cards | yes |
63
+ | `start` | the numbers at the start | a pager under left-aligned content | |
64
+ | `end` | the numbers at the end | beside a range line in a footer (the DataTable footer passes it) | |
65
+
58
66
  ### size
59
67
  | Value | Looks like | Use when | Default |
60
68
  |---|---|---|---|
@@ -78,7 +86,7 @@ Pagination <nav aria-label={labels.nav}>; size and compact mode
78
86
  | hover / active | pointer | `fill-subtle` / `fill-subtle-active`, primary text, press scale |
79
87
  | focus-visible | keyboard | outer focus ring of the Button |
80
88
  | disabled arrow | first / last page | native `disabled`, `text-disabled` |
81
- | size / compact | `size` (else the host tier), `compact` | `data-size`, `data-compact` (`"auto"` · `"compact"`) |
89
+ | size / compact / align | `size` (else the host tier), `compact`, `align` | `data-size`, `data-compact` (`"auto"` · `"compact"`), `data-align` |
82
90
 
83
91
  ## Layout & spacing
84
92
  - In a list footer: the range text on the left, rows-per-page Select and Pagination on the right (`justify-content: space-between`), the row wraps.
@@ -120,7 +128,7 @@ Pagination <nav aria-label={labels.nav}>; size and compact mode
120
128
  | [overview.tsx](examples/overview.tsx) | Pages of an order list: arrows, page numbers and the current page — `totalPages`, `defaultValue`. |
121
129
  | [sizes.tsx](examples/sizes.tsx) | Every size tier; buttons are as high as Button and Input of the same tier, 28 to 48 px — `size`. |
122
130
  | [overflow.tsx](examples/overflow.tsx) | Up to 7 pages without an ellipsis, then a window around the current page; a wider window — `siblingCount`. |
123
- | [controlled.tsx](examples/controlled.tsx) | A list footer owns the page: changing rows per page returns it to page 1 — `value`, `onValueChange`. |
131
+ | [controlled.tsx](examples/controlled.tsx) | A list footer owns the page: changing rows per page returns it to page 1, the pages at the end beside the range — `value`, `onValueChange`, `align`. |
124
132
  | [narrow.tsx](examples/narrow.tsx) | A 320 px card footer: by default the numbers give way to «current / total» on a narrow width, `compact` always shows it — `compact`. |
125
133
 
126
134
  ## Mistakes
@@ -1,4 +1,4 @@
1
- /** A list footer owns the page: changing rows per page returns it to page 1 — `value`, `onValueChange`. */
1
+ /** A list footer owns the page: changing rows per page returns it to page 1, the pages at the end beside the range — `value`, `onValueChange`, `align`. */
2
2
  import { Card, Pagination, Select, Typography } from "prime-ui-kit";
3
3
  import * as React from "react";
4
4
 
@@ -39,6 +39,7 @@ export default function PaginationControlledExample() {
39
39
  </Select.Content>
40
40
  </Select.Root>
41
41
  <Pagination
42
+ align="end"
42
43
  value={page}
43
44
  onValueChange={setPage}
44
45
  totalPages={Math.ceil(TOTAL_INVOICES / pageSize)}
@@ -70,7 +70,7 @@ No DOM: clone the single child and merge `ref` and `onClick`. Trigger toggles th
70
70
  | `side` | `"top" \| "right" \| "bottom" \| "left"` | `"bottom"` | Preferred side; flips to the opposite side when there is no room. |
71
71
  | `align` | `"auto" \| "start" \| "center" \| "end"` | `"auto"` | Alignment along the trigger. `auto` lines the panel up with the trigger edge that has more room beyond it; `start`, `center` or `end` fix the edge. |
72
72
  | `size` | `"xs" \| "s" \| "m" \| "l" \| "xl"` | `"m"` | Tier of the text, padding and gap; also the size context of the controls inside. |
73
- | `width` | `"auto" \| "trigger" \| "content"` | `"auto"` | `auto`: by content, from the panel minimum to twice that. `trigger`: exactly the trigger's width, below the minimum too. `content`: what the content needs, within the viewport. A sheet is full width. |
73
+ | `width` | `"auto" \| "trigger" \| "min-trigger" \| "content"` | `"auto"` | `auto`: by content, panel minimum to twice that. `trigger`: exactly the trigger. `min-trigger`: `auto`, never narrower than the trigger. `content`: what the content needs. A sheet is full width. |
74
74
  | `trapFocus` | `boolean` | `false` | Tab cycles inside the panel (forms). Without it Tab past the last (Shift+Tab before the first) stop closes the panel and returns focus to the trigger. |
75
75
  | `initialFocus` | `boolean` | `true` with `Popover.Trigger`, `false` with `Popover.Anchor` | Focus moves into the panel on open (`[data-autofocus]`, else the first tab stop, else the panel). Turn it on for an anchored panel opened by a command, such as a Dropdown item, so focus does not stay on the menu trigger. |
76
76
  | `flush` | `boolean` | `false` | No inner padding and no gap: rows and dividers reach the panel edges; the content lays out its own spacing. |
@@ -122,6 +122,7 @@ Title uses the tier text size with title weight; Description uses the tier label
122
122
  |---|---|---|---|
123
123
  | `auto` | As wide as the content, between `--prime-panel-min-width` and twice that | Most panels | yes |
124
124
  | `trigger` | Exactly as wide as the trigger, below the minimum too; text wraps | Full-width triggers in narrow columns | |
125
+ | `min-trigger` | As `auto`, never narrower than the trigger | A panel under a wide anchor that must stay readable when the anchor is narrow ([SmartFilter](../smart-filter/COMPONENT.md)) | |
125
126
  | `content` | What the content needs, within the viewport | A wide calendar, a table of limits | |
126
127
 
127
128
  A bottom sheet is always full width, whatever `width` says.
@@ -185,7 +186,7 @@ No `labels`.
185
186
  | [structure.tsx](examples/structure.tsx) | Optional parts: a panel with plain text only, and a panel with a title, a description and actions — `Popover.Header`, `Popover.Actions`. |
186
187
  | [sizes.tsx](examples/sizes.tsx) | Every size tier with a header and actions; the tier is the panel's own, set on `Popover.Content`, not taken from its trigger — `size`. |
187
188
  | [placement.tsx](examples/placement.tsx) | Every side and alignment relative to the trigger; near the viewport edge the panel flips and shifts — `side`, `align`. |
188
- | [width.tsx](examples/width.tsx) | In a narrow column the panel takes the exact width of a full-width trigger and its text wraps; a table of limits takes the width it needs — `width`. |
189
+ | [width.tsx](examples/width.tsx) | In a narrow column the panel takes the exact width of a full-width trigger and its text wraps; a short trigger opens a panel at least as wide as itself; a table of limits takes the width it needs — `width`. |
189
190
  | [flush.tsx](examples/flush.tsx) | A notification list whose rows and dividers reach the panel edges; each row brings its own padding — `flush`. |
190
191
  | [from-menu.tsx](examples/from-menu.tsx) | A menu command opens a panel at the same button: the rename item shows a form anchored to the menu button and focus lands in its field, not back on that button — `Popover.Anchor`, `initialFocus`. |
191
192
  | [dismiss.tsx](examples/dismiss.tsx) | A note being typed is not lost to a stray click: the panel closes only from its buttons, and not at all while the note is saved — `closeOnOutsideClick`, `closeOnEscape`. |
@@ -1,4 +1,4 @@
1
- /** In a narrow column the panel takes the exact width of a full-width trigger and its text wraps; a table of limits takes the width it needs — `width`. */
1
+ /** In a narrow column the panel takes the exact width of a full-width trigger and its text wraps; a short trigger opens a panel at least as wide as itself; a table of limits takes the width it needs — `width`. */
2
2
  import { Button, DescriptionList, Popover, Typography } from "prime-ui-kit";
3
3
 
4
4
  import styles from "./examples.module.css";
@@ -24,6 +24,18 @@ export default function PopoverWidthExample() {
24
24
  </Typography>
25
25
  </Popover.Content>
26
26
  </Popover.Root>
27
+ <Popover.Root>
28
+ <Popover.Trigger>
29
+ <Button.Root variant="soft" tone="neutral" fullWidth>
30
+ Что входит в поддержку
31
+ </Button.Root>
32
+ </Popover.Trigger>
33
+ <Popover.Content width="min-trigger">
34
+ <Typography variant="body-s" tone="secondary">
35
+ Ответ в течение 4 часов, персональный менеджер и разбор инцидентов.
36
+ </Typography>
37
+ </Popover.Content>
38
+ </Popover.Root>
27
39
  <Popover.Root>
28
40
  <Popover.Trigger>
29
41
  <Button.Root variant="ghost" tone="neutral" fullWidth>
@@ -47,6 +47,7 @@ Radio.Group field: group label → role="radiogroup" → hint | erro
47
47
  | `required` | `boolean` | `false` | Red `*` after the label, native `required` on the radios and `aria-required` on the group. |
48
48
  | `optional` | `boolean` | `false` | Muted marker right after the label text (`labels.optional`). |
49
49
  | `hint` | `ReactNode` | — | Help text under the options. Hidden while `error` is shown. |
50
+ | `hintTone` | `"neutral" \| "success" \| "warning" \| "danger"` | `"neutral"` | Status color of `hint` («Осталось 12 дней» in `warning`). The words carry the status, the color repeats it; an `error` replaces the hint and its tone. A validation error is `error`, never a `danger` hint. |
50
51
  | `error` | `ReactNode` | — | Error message under the options; implies `invalid`. |
51
52
  | `invalid` | `boolean` | `false` | Danger ring on the unchecked circles and `aria-invalid` on the group and the inputs. A non-empty `error` implies it. |
52
53
  | `disabled` | `boolean` | `false` | Disables every option. |
@@ -64,6 +65,7 @@ Radio.Group field: group label → role="radiogroup" → hint | erro
64
65
  |---|---|---|---|
65
66
  | `value` | `string` | — (required) | Value reported to the group when this option is chosen. |
66
67
  | `hint` | `ReactNode` | — | Description under the option text, linked through `aria-describedby`. |
68
+ | `hintTone` | `"neutral" \| "success" \| "warning" \| "danger"` | `"neutral"` | Status color of `hint` («Осталось 12 дней» in `warning`). The words carry the status, the color repeats it; an `error` replaces the hint and its tone. A validation error is `error`, never a `danger` hint. |
67
69
  | `disabled` | `boolean` | `false` | Disables this option only. |
68
70
  | `children` | `ReactNode` | — | `Radio.Label`. Without it only the circle renders — give the root an `aria-label`. |
69
71
  | `className` | `string` | — | Class on the option `<div>`. |
@@ -0,0 +1,93 @@
1
+ # RichText
2
+
3
+ **Category:** data-display
4
+ **Kind:** primitive
5
+
6
+ > Text in the chat's Markdown subset outside a message — a bot's welcome text, a template, a comment — rendered as elements, never as HTML.
7
+
8
+ ## When to use
9
+ - A text written with the formatting toolbar of `Composer` or `Textarea formatting` is shown somewhere other than a chat: a bot's settings, a template list, a card.
10
+ - Text from users or bots that may carry `**bold**`, links or a `||spoiler||` and must be rendered safely.
11
+
12
+ ## When not to use
13
+ - The text of a chat message → [Message](../message/COMPONENT.md) `Message.Text` (it marks search matches and holds the meta's room).
14
+ - A whole message shown outside a chat (a bot's welcome message with its keyboard) → `Message.Root preview`.
15
+ - Plain text with a role → [Typography](../typography/COMPONENT.md).
16
+ - Source code → [CodeBlock](../code-block/COMPONENT.md).
17
+
18
+ ## Import
19
+ ```tsx
20
+ import { RichText } from "prime-ui-kit";
21
+ ```
22
+
23
+ ## Anatomy
24
+ ```
25
+ RichText <div>; the source as children
26
+ ├─ <p> a run of text, line breaks kept
27
+ ├─ <blockquote> lines starting with "> "
28
+ └─ <pre> fenced code
29
+ ```
30
+
31
+ ## API
32
+
33
+ <!-- Generated from api.ts by `bun run docs:build`. Edit api.ts, not this section. -->
34
+
35
+ ### RichText
36
+ `ref` → `HTMLDivElement`. Text in the chat's Markdown subset outside a message, rendered as elements in the type of its host.
37
+
38
+ | Prop | Type | Default | Description |
39
+ |---|---|---|---|
40
+ | `children` | `string` | — (required) | The source: `**bold**`, `_italic_`, `~~strike~~`, `\|\|spoiler\|\|`, inline and fenced code, links (`[label]` then the address in parentheses), bare URLs, `> ` quotes; line breaks are kept. |
41
+ | `labels` | `Partial<RichTextLabels>` | — | Built-in strings, see Labels. |
42
+ | `…rest` | `Omit<HTMLAttributes<HTMLDivElement>, "children">` | — | `className`, `id`, `data-*` and the other div attributes. |
43
+
44
+ ## Variants
45
+ One look: the type of its host. Wrap it in `Typography as="div"` to pick a text role.
46
+
47
+ ## States
48
+ | State | Driven by | DOM |
49
+ |---|---|---|
50
+ | masked spoiler | `\|\|text\|\|` in `children` | `role="button"`, `data-state="masked"`: a wash over transparent words |
51
+ | revealed spoiler | a press, `Enter` or `Space` | `data-state="revealed"`: the wash and the words cross-fade on the fade clock; one way, like a chat |
52
+
53
+ ## Layout & spacing
54
+ - Paragraphs, quotes and code blocks keep their line breaks and wrap anywhere, so a long address never widens the host; blocks stand 4px apart.
55
+ - A quote is a wash with an accent bar on its start edge; code is the mono face on a wash.
56
+ - No size of its own: the root takes the font and color of its host.
57
+
58
+ ## Accessibility
59
+
60
+ ### Keyboard
61
+ <!-- Generated from api.ts by `bun run docs:build`. Edit api.ts, not this section. -->
62
+
63
+ | Key | Action |
64
+ |---|---|
65
+ | `Tab` | Moves through the links and the masked spoilers. |
66
+ | `Enter` · `Space` | On a masked spoiler: reveals it and moves the focus onto its text. |
67
+
68
+ ### ARIA
69
+ <!-- Generated from api.ts by `bun run docs:build`. Edit api.ts, not this section. -->
70
+
71
+ - A masked spoiler is a `role="button"` named `labels.spoiler`; its words are out of the accessibility tree until it is revealed.
72
+ - Links take only http(s), `mailto:` and `tel:` addresses and open in a new tab (`rel="noopener noreferrer"`); markup is never parsed as HTML.
73
+
74
+ ### Labels
75
+ <!-- Generated from api.ts by `bun run docs:build`. Edit api.ts, not this section. -->
76
+
77
+ | Key | Default | Used for |
78
+ |---|---|---|
79
+ | `spoiler` | `"Скрытый текст"` | The name of a masked spoiler until it is revealed. |
80
+
81
+ ## Examples
82
+ | Example | Shows |
83
+ |---|---|
84
+ | [overview.tsx](examples/overview.tsx) | The welcome text of a support bot shown outside the chat: bold, a link, a quote, code and a spoiler from the chat's Markdown — `children`. |
85
+
86
+ ## Mistakes
87
+ - `dangerouslySetInnerHTML` with a Markdown library for a chat text → `RichText`: the same subset as the chat, never HTML.
88
+ - A `Message.Root` with no time and no author only to render formatted text → `RichText`.
89
+ - Sizing the text with a class on `RichText` → put it inside the host that sets the type.
90
+
91
+ ## Related
92
+ - **Built from:** `internal/richText` (the parser and the elements, shared with `Message.Text`)
93
+ - **See also:** [Message](../message/COMPONENT.md), [Composer](../composer/COMPONENT.md), [Textarea](../textarea/COMPONENT.md), [Typography](../typography/COMPONENT.md)
@@ -0,0 +1,19 @@
1
+ /** The welcome text of a support bot shown outside the chat: bold, a link, a quote, code and a spoiler from the chat's Markdown — `children`. */
2
+ import { Card, RichText } from "prime-ui-kit";
3
+
4
+ const WELCOME = [
5
+ "**Здравствуйте!** Это бот поддержки «Прайм».",
6
+ "Счета и акты — в [личном кабинете](https://prime.app/billing), номер договора начинается с `PR-`.",
7
+ "> Отвечаем в рабочие дни с 9:00 до 19:00 по Москве.",
8
+ "Код для входа в приложение: ||4821||",
9
+ ].join("\n");
10
+
11
+ export default function RichTextOverviewExample() {
12
+ return (
13
+ <Card.Root>
14
+ <Card.Body>
15
+ <RichText>{WELCOME}</RichText>
16
+ </Card.Body>
17
+ </Card.Root>
18
+ );
19
+ }
@@ -44,7 +44,7 @@ ScrollContainer <div> (or the `as` tag); thin scrollbar, soft hidden edges
44
44
  | `edges` | `"fade" \| "shadow" \| "none"` | `"fade"` | Edges that hide content: `fade` dissolves them over any background; `shadow` — a soft shadow on the region's own fill (a floating panel, a code well); `none` — plain edges. |
45
45
  | `scrollbar` | `"thin" \| "hidden"` | `"thin"` | `thin` — the kit's quiet scrollbar; `hidden` — no scrollbar, keep `edges` on so the overflow stays visible. |
46
46
  | `lock` | `boolean` | `false` | The person cannot scroll the region (wheel, touch, keys, a drag's auto-scroll); code still can. Sets `data-lock`. |
47
- | `snap` | `boolean \| "mandatory"` | `false` | Scrolling comes to rest on the start of a child: `true` near one (strips of tiles and cards), `"mandatory"` always on one (board columns, a carousel). A Dnd drag inside turns it off; not with `anchor="end"`. |
47
+ | `snap` | `boolean \| "mandatory"` | `false` | Once a scroll ends, the region glides to the start of a child: `true` near one (strips of tiles), `"mandatory"` always (board columns, a carousel). Native scrolling meanwhile; any input stops the glide. |
48
48
  | `anchor` | `"start" \| "end"` | `"start"` | `end` — a chat or a log: opens at the end and follows new content while the person is at the end; scrolled away, the view holds still. |
49
49
  | `onReachStart` | `() => void \| Promise<void>` | — | Fires within 120 px of the start, once per approach: load older content. A returned promise blocks repeats and sets `aria-busy`; content added above keeps the view. |
50
50
  | `onReachEnd` | `() => void \| Promise<void>` | — | The scroll position came within 120 px of the end: load the next page. Same once-per-approach and promise rules as `onReachStart`. |
@@ -93,11 +93,12 @@ Only the reader scrolling back unpins the end: content that keeps growing (an an
93
93
  | Value | Looks like | Use when | Default |
94
94
  |---|---|---|---|
95
95
  | `lock` | nothing the person does scrolls the region (wheel, touch, keys, a drag's edge auto-scroll); the position stays, and code may still set it | a list behind an open review, a gesture that must not move it | off |
96
- | `snap` | a scroll comes to rest on the start of a direct child near one (proximity); a host aligns deeper items itself | strips of tiles or cards | off |
97
- | `snap="mandatory"` | a scroll always comes to rest on the start of a child | board columns, a carousel of cards | off |
96
+ | `snap` | once a scroll ends near the start of a direct child (within 30% of the view), the region glides there; a host marks deeper items with `scroll-snap-align` itself | strips of tiles or cards | off |
97
+ | `snap="mandatory"` | once a scroll ends, the region always glides to the nearest start of a child | board columns on a phone, a carousel of cards | off |
98
98
 
99
99
  ### Wheel and auto-scroll
100
- - `axis="horizontal"`: a vertical mouse wheel scrolls the strip sideways while it can move, gliding to an accumulated target (instant under reduced motion). A trackpad's sideways swipe and Shift + wheel stay native; a wheel gesture that began outside the strip keeps scrolling the page; at the strip's edge the wheel chains to the page. There is no drag-to-scroll: a press-and-drag in a strip belongs to its items (reordering tiles, tabs); touch pans natively.
100
+ - Snapping never takes over the scroll: the trackpad, touch, the scrollbar and the keys scroll natively with their momentum, and the browser does not snap (no `scroll-snap-type` — it damps a trackpad's momentum and pulls a scroll near the end back to merged rest points). Once the scroll ends — no movement for a moment, nothing held — the region glides to its rest point on the kit's own frames, and any wheel, touch, press or key stops that glide at once; it settles again when the input goes quiet. A Dnd drag inside never settles.
101
+ - `axis="horizontal"`: a vertical mouse wheel (whole notches; a trackpad stays native) scrolls the strip sideways while it can move — by the wheel's distance, or a rest point per notch on a strip that snaps — on the kit's frames (instant under reduced motion), each notch from where the glide is heading, so a turn the other way goes back mid-glide. Shift + wheel stays native; a wheel gesture that began outside the strip keeps scrolling the page; at the strip's edge the wheel chains to the page. There is no drag-to-scroll: a press-and-drag in a strip belongs to its items (reordering tiles, tabs); touch pans natively.
101
102
  - A gesture held near an edge — a Dnd drag, a Gantt bar moved or drawn, a drag that paints a selection over table rows or messages — scrolls the region toward it, faster the closer the pointer (`src/internal/edgeAutoScroll`, one speed curve for the kit). A `lock`ed region or one whose content fits never moves.
102
103
 
103
104
  ### Edge events
@@ -116,7 +117,7 @@ Each fires once per approach — again after the position leaves the zone or the
116
117
  | edge treatment | `edges` | `data-edges="fade" \| "shadow"` (none for `none`) |
117
118
  | content hidden at an edge | scroll position (with `edges="fade"`), measured at most once per frame on scroll, on resize of the region or a child and when children are added; only the scroll axes; logical in RTL | `data-overflow-top`, `data-overflow-bottom`, `data-overflow-start`, `data-overflow-end` = `"true"`; `--edge-*` depths written only while they change (within the last fade depth of an edge, `--scroll-fade-depth`), on non-inherited properties |
118
119
  | locked | `lock` | `data-lock`, `overflow: hidden` |
119
- | snapping | `snap` | `data-snap="proximity" \| "mandatory"`, `scroll-snap-type: <axis> <strictness>`; `scroll-snap-align: start` on the children; off while a Dnd list inside carries an item (`data-dnd-carrying`) |
120
+ | snapping | `snap` | `data-snap="proximity" \| "mandatory"`; `scroll-snap-align: start` on the children marks the rest points (no `scroll-snap-type`); no settling while a Dnd list inside carries an item (`data-dnd-carrying`) |
120
121
  | kit anchoring | `anchor="end"` or `onReachStart` | `data-anchor="end" \| "start"`, `overflow-anchor: none`: the kit keeps the visible entry in place (or the end, while pinned) before paint, the same in every browser |
121
122
  | pinned to the end | `anchor="end"` and the position within 4 px of the end | content changes scroll to the new end at once (high-frequency: no animation) |
122
123
  | loading at an edge | a pending promise from `onReachStart` / `onReachEnd` | `aria-busy="true"` |
@@ -176,6 +177,8 @@ No `labels`.
176
177
  - `edges="fade"` on a region that paints its own fill or shadow → the mask dissolves them; use `edges="shadow"`.
177
178
  - A hand-made edge auto-scroll loop for a drag → `createEdgeAutoScroll` from `src/internal/edgeAutoScroll`.
178
179
  - `snap` together with `anchor="end"` → snapping fights the pin to the end.
180
+ - `scroll-snap-type` on a region or its host → `snap`: the browser's snapping damps a trackpad's momentum and pulls a scroll near the end back.
181
+ - `snap="mandatory"` on a strip of children narrower than the view (a wide board) → their rest points merge at the end; snap only where each child fills most of the view, or use `snap`.
179
182
  - Wrapping a Modal body or Dropdown panel in another ScrollContainer → they already scroll.
180
183
  - `scrollTop = scrollHeight` in an effect after every message → `anchor="end"` (it also leaves a reader who scrolled up alone).
181
184
  - `flex-direction: column-reverse` to keep a chat at the bottom → it reverses the reading and Tab order; use `anchor="end"`.
@@ -53,6 +53,7 @@ The root is a field root: `className`, `ref` and the native attributes land on t
53
53
  | `required` | `boolean` | `false` | Red `*` after the label and `aria-required` on the `radiogroup`. |
54
54
  | `optional` | `boolean` | `false` | Muted marker after the label (`labels.optional`). |
55
55
  | `hint` | `ReactNode` | — | Help text under the control (`aria-describedby`). Hidden while `error` is shown. |
56
+ | `hintTone` | `"neutral" \| "success" \| "warning" \| "danger"` | `"neutral"` | Status color of `hint` («Осталось 12 дней» in `warning`). The words carry the status, the color repeats it; an `error` replaces the hint and its tone. A validation error is `error`, never a `danger` hint. |
56
57
  | `error` | `ReactNode` | — | Error message in the hint slot; implies `invalid`. |
57
58
  | `invalid` | `boolean` | `false` | Danger inset ring, `aria-invalid` and `data-invalid` on the `radiogroup`; the control shakes once when an error arrives. |
58
59
  | `reserveSupportRow` | `boolean` | `false` | Always render the support row, so an appearing error does not shift the layout. |
@@ -15,7 +15,7 @@ export default function SegmentedControlInFormExample() {
15
15
 
16
16
  return (
17
17
  <form className={styles.form} noValidate onSubmit={submit}>
18
- <Input.Root label="Сумма, ₽" required>
18
+ <Input.Root label="Сумма" required>
19
19
  <Input.Wrapper>
20
20
  <Input.Field name="amount" inputMode="decimal" defaultValue="12 400" />
21
21
  <Input.InlineAffix side="end">₽</Input.InlineAffix>
@@ -11,12 +11,13 @@
11
11
  - A value out of thousands of records searched on the server (`search`, `onSearchChange`, `filter={false}`, `hasMore` + `onLoadMore`).
12
12
  - A few values from a short list shown as comma-separated text (`multiple`).
13
13
  - Options that need a picture, an avatar, a second line, a badge or a trailing value (rich options).
14
+ - A pick that belongs to a text field (an icon before a name): put the Select inside `Input.Wrapper` — it becomes the box's start segment, named by its `aria-label`.
14
15
 
15
16
  ## When not to use
16
17
  - 2–5 options that should all be visible → use [Radio](../radio/COMPONENT.md) or [SegmentedControl](../segmented-control/COMPONENT.md).
17
18
  - The OS picker on a mobile-first form → use [NativeSelect](../native-select/COMPONENT.md).
18
19
  - Many values shown as removable tags, or creating new values → use [TagSelect](../tag-select/COMPONENT.md).
19
- - Free text → use [Input](../input/COMPONENT.md).
20
+ - Free text, even with suggestions → use [Input](../input/COMPONENT.md) (`suggestions`).
20
21
  - A menu of actions (not a value) → use [Dropdown](../dropdown/COMPONENT.md).
21
22
  - Global search / command palette → use [CommandMenu](../command-menu/COMPONENT.md).
22
23
  - Dates → use [Datepicker](../datepicker/COMPONENT.md).
@@ -60,7 +61,7 @@ an icon) goes inside `Select.ItemMeta`.
60
61
  <!-- Generated from api.ts by `bun run docs:build`. Edit api.ts, not this section. -->
61
62
 
62
63
  ### Select.Root
63
- `ref` → `HTMLDivElement`. The field frame (label row · control · support row) holding the value, the open state and the search query.
64
+ `ref` → `HTMLDivElement`. The field frame (label row · control · support row) holding the value, the open state and the search query. Inside `Input.Wrapper` it is the box's start segment instead: no frame, the trigger named by `aria-label` and the value.
64
65
 
65
66
  | Prop | Type | Default | Description |
66
67
  |---|---|---|---|
@@ -75,6 +76,7 @@ an icon) goes inside `Select.ItemMeta`.
75
76
  | `closeOnOutsideClick` | `boolean` | `true` | A press outside the list and its trigger closes it; focus follows the pointer. |
76
77
  | `label` | `ReactNode` | — | Field label above; names the trigger. |
77
78
  | `hint` | `ReactNode` | — | Support text under the field; linked by `aria-describedby`. |
79
+ | `hintTone` | `"neutral" \| "success" \| "warning" \| "danger"` | `"neutral"` | Status color of `hint` («Осталось 12 дней» in `warning`). The words carry the status, the color repeats it; an `error` replaces the hint and its tone. A validation error is `error`, never a `danger` hint. |
78
80
  | `error` | `ReactNode` | — | Error message; replaces the hint and implies `invalid`. |
79
81
  | `required` | `boolean` | `false` | Red `*` after the label and `aria-required` on the trigger. |
80
82
  | `optional` | `boolean` | — | Muted `labels.optional` after the label. |
@@ -224,6 +226,7 @@ No `variant` or `tone`. The trigger is the field look (fill, inset control borde
224
226
  | searching | typing in the search | panel `data-searching="true"`; groups without matches and separators hide; the match in an option's title, description and plain text is a `<mark>` in `accent-text` (not in the trigger); the query clears when the list closes (`onSearchChange("")`) |
225
227
  | nothing to show | no option matches (and not loading) | a compact EmptyPage with `role="status"`: `labels.empty`, plus `labels.emptyHint` while a query is typed; a `Select.Action` stays under it, highlighted |
226
228
  | sheet | viewport below 640px | a scrim and a full-width bottom sheet with an `aria-hidden` grab handle around the panel; the sheet carries `data-state`, the panel keeps its role and ref; page scroll locked; a swipe down from the handle closes it |
229
+ | segment | inside `Input.Wrapper` | no frame (label, hint, error, support row): the root is `data-field-segment`, the trigger `data-segment="true"` — a tinted section flush with the box's start edge, a stronger fill on hover and while open, an inset focus ring; named «`aria-label`: value» |
227
230
  | option highlighted / selected / disabled | keyboard and pointer / value / `disabled` | `data-highlighted`, `data-selected` + `aria-selected`, `data-disabled` + `aria-disabled`; highlight is a fill only |
228
231
 
229
232
  ## Layout & spacing
@@ -350,8 +353,9 @@ No `variant` or `tone`. The trigger is the field look (fill, inset control borde
350
353
  - `<ClientAvatar />` or `<RoleBadge />` (your own component) inside an item → the item reads parts by element type and puts an unknown component in the text column; call the helper as a function (`{clientAvatar(client)}`) so `Avatar.Root` / `Badge.Root` is the direct child.
351
354
  - A custom trailing element (a Kbd, an icon with a price) as a bare child → wrap it in `Select.ItemMeta`.
352
355
  - A «Новый клиент» row faked as a `Select.Item` with a sentinel value, or a button under the field → use `Select.Action`: never filtered, reached by the arrows, never a value.
356
+ - An icon-only Select set beside an Input for one value (an icon + a name) → put it inside `Input.Wrapper` with an `aria-label`; `label`, `hint` and `error` belong to the Input there.
353
357
  - Saving the choice in `onValueChange` and resetting the value by hand on failure → return the promise; the Select shows the value, waits and rolls back by itself.
354
358
 
355
359
  ## Related
356
- - **Built from:** [ScrollContainer](../scroll-container/COMPONENT.md) (list), [Checkbox](../checkbox/COMPONENT.md) (`Checkbox.Indicator` in `multiple`), [Spinner](../spinner/COMPONENT.md) (`loading` and saving in the trigger), [Skeleton](../skeleton/COMPONENT.md) (loading rows), [EmptyPage](../empty-page/COMPONENT.md) (empty state, load error), [Button](../button/COMPONENT.md) (retry), [Divider](../divider/COMPONENT.md) (`Separator`), [Thumbnail](../thumbnail/COMPONENT.md) and [Avatar](../avatar/COMPONENT.md) (row media), [Badge](../badge/COMPONENT.md) (row badge), [VisuallyHidden](../visually-hidden/COMPONENT.md) (loading and save-failure announcements), `Icon` (chevron, clear, check, search, retry), [Label](../label/COMPONENT.md) and [Hint](../hint/COMPONENT.md) (field frame)
360
+ - **Built from:** [ScrollContainer](../scroll-container/COMPONENT.md) (list), [Checkbox](../checkbox/COMPONENT.md) (`Checkbox.Indicator` in `multiple`), [Spinner](../spinner/COMPONENT.md) (`loading` and saving in the trigger), [Skeleton](../skeleton/COMPONENT.md) (loading rows), [EmptyPage](../empty-page/COMPONENT.md) (empty state, load error), [Button](../button/COMPONENT.md) (retry), [Divider](../divider/COMPONENT.md) (`Separator`), [Thumbnail](../thumbnail/COMPONENT.md) and [Avatar](../avatar/COMPONENT.md) (row media), [Badge](../badge/COMPONENT.md) (row badge), [VisuallyHidden](../visually-hidden/COMPONENT.md) (loading and save-failure announcements), `Icon` (chevron, clear, check, search, retry), [Label](../label/COMPONENT.md) and [Hint](../hint/COMPONENT.md) (field frame), [Input](../input/COMPONENT.md) (the start segment of `Input.Wrapper`)
357
361
  - **See also:** [NativeSelect](../native-select/COMPONENT.md), [TagSelect](../tag-select/COMPONENT.md), [Dropdown](../dropdown/COMPONENT.md), [Radio](../radio/COMPONENT.md), [SegmentedControl](../segmented-control/COMPONENT.md)
@@ -59,8 +59,9 @@ Slider field frame (FieldFrame): className, ref, rest
59
59
  | `required` | `boolean` | — | Red `*` after the label (`aria-hidden`); a range always has a value, so there is no native `required`. |
60
60
  | `optional` | `boolean` | — | Muted marker right after the label text (`labels.optional`). |
61
61
  | `hint` | `ReactNode` | — | Help text under the track (`aria-describedby`). Hidden while `error` is shown. |
62
+ | `hintTone` | `"neutral" \| "success" \| "warning" \| "danger"` | `"neutral"` | Status color of `hint` («Осталось 12 дней» in `warning`). The words carry the status, the color repeats it; an `error` replaces the hint and its tone. A validation error is `error`, never a `danger` hint. |
62
63
  | `error` | `ReactNode` | — | Error message in the hint slot; implies `invalid`. |
63
- | `invalid` | `boolean` | — | `aria-invalid` on the range input and a danger focus ring on the thumb. A non-empty `error` implies it. |
64
+ | `invalid` | `boolean` | — | `aria-invalid` on the range input, a danger fill (over any `tone`) and a danger focus ring on the thumb. A non-empty `error` implies it. |
64
65
  | `showValue` | `boolean` | `false` | Shows the current value at the end of the label row (tabular numbers, `aria-hidden` — the input announces it). |
65
66
  | `formatValue` | `(value: number) => string` | — | Formats the shown value and `aria-valuetext` (units, currency). |
66
67
  | `id` | `string` | — | Id of the range input (generated when omitted); hint id is `<id>-hint`, error id is `<id>-error`. |
@@ -121,10 +122,10 @@ Tone never carries meaning alone: the label names what the value means.
121
122
  |---|---|---|
122
123
  | default | — | `data-size`, `data-tone` (`data-orientation="vertical"` when upright); track `fill-strong`, tone pill up to the thumb centre, opaque thumb |
123
124
  | hover | pointer (fine pointers only) | light liquid glass: the thumb grows to 110%, turns translucent and slightly frosted |
124
- | invalid | `invalid` or a non-empty `error` | `data-invalid="true"` on the root, `aria-invalid` on the input; the error replaces the hint, danger focus ring; the control shakes once when an error arrives (`data-shake` on the frame) |
125
+ | invalid | `invalid` or a non-empty `error` | `data-invalid="true"` on the root, `aria-invalid` on the input; the error replaces the hint, danger fill over any `tone`, danger focus ring; the control shakes once when an error arrives (`data-shake` on the frame) |
125
126
  | pressed | dragging | clear glass: the thumb grows to 125%, the rounded end of the fill shows through |
126
127
  | focus-visible | keyboard | outer focus ring around the thumb |
127
- | disabled | `disabled` | `data-disabled="true"` on the root, native `disabled`; muted track and fill, flat thumb, `cursor: not-allowed` |
128
+ | disabled | `disabled` | `data-disabled="true"` on the root, native `disabled`; muted track and fill, a flat opaque thumb, `cursor: not-allowed` |
128
129
  | saving | `onCommit` returned a pending promise | `data-pending="true"` on the root, `aria-busy` on the input; the thumb quiets to 0.6 (`fast`, both ways); the slider stays usable — only the latest commit's answer counts |
129
130
  | refused | that promise rejected | the value goes back to the last saved one (`onValueChange` when controlled); `data-settling` glides the thumb and the fill there (`base`, emphasized) |
130
131