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
@@ -1,8 +1,19 @@
1
1
  /* Layout of the Label scenarios: semantic tokens only. */
2
2
 
3
- /* overview.tsx, structure.tsx: a label above what it names, at the m-tier label gap. */
3
+ /* structure.tsx: a label above what it names, at the m-tier label gap, in a 320 px field column —
4
+ the fields stack centred in the stage and share one start edge, as labels of one form do. */
4
5
  .field {
5
6
  display: grid;
6
7
  justify-items: start;
7
8
  gap: var(--prime-control-m-label-gap);
9
+ width: min(100%, calc(var(--prime-space-20) * 4));
10
+ }
11
+
12
+ /* overview.tsx: the same pair in a 320 px column — an embedded calendar measures its container
13
+ for its month, so the column gives it one. */
14
+ .calendarField {
15
+ display: grid;
16
+ justify-items: start;
17
+ gap: var(--prime-control-m-label-gap);
18
+ width: min(100%, calc(var(--prime-space-20) * 4));
8
19
  }
@@ -8,7 +8,7 @@ export default function LabelOverviewExample() {
8
8
  const labelId = React.useId();
9
9
 
10
10
  return (
11
- <div className={styles.field}>
11
+ <div className={styles.calendarField}>
12
12
  <Label.Root id={labelId}>Дата отгрузки</Label.Root>
13
13
  <Datepicker.Panel mode="single" role="group" aria-labelledby={labelId} />
14
14
  </div>
@@ -6,9 +6,10 @@
6
6
  > A selectable navigation list of rows: the master half of a list + detail screen (tickets, mail, records).
7
7
 
8
8
  ## When to use
9
- - The list side of a list + detail screen (`PageContent.Split` → `PageContent.Panel kind="list"`): tickets, letters, invoices worked through one by one; the open one is `current`.
9
+ - The list side of a list + detail screen (`Page.Split` → `Page.List`): tickets, letters, invoices worked through one by one; the open one is `current`.
10
10
  - A short column of records that each open something — a page (`href`, `asChild` with a router link) or a detail pane (`onClick`).
11
11
  - A short list the team puts in order (funnel stages, queues, priorities) — `onReorder`, a `value` per item.
12
+ - Rows with controls of their own beside the row that opens the record (a stage shown on the board, a ⋯ menu) — `List.ItemActions`.
12
13
 
13
14
  ## When not to use
14
15
  - App sections → use [Sidebar](../../layout/sidebar/COMPONENT.md) (wide) and [BottomNav](../../layout/bottom-nav/COMPONENT.md) (phone).
@@ -28,11 +29,12 @@ import { List } from "prime-ui-kit";
28
29
  List.Root <ul aria-label>; size (else the host tier) → row tier; onReorder → Dnd.Sortable <ul>
29
30
  └─ List.Item <li> with a full-width <button> | <a href> | asChild element; current, disabled
30
31
  │ value; with onReorder: Dnd.Handle (busy while saving) before the row element
31
- ├─ List.ItemIcon leading Avatar.Root / Icon (aria-hidden); after the text — a trailing glyph
32
+ ├─ List.ItemIcon leading Avatar.Root / Icon / Badge.Dot (aria-hidden); after the text — a trailing glyph
32
33
  ├─ List.ItemText primary line, truncates
33
34
  ├─ List.ItemDescription second line, muted, truncates
34
35
  ├─ List.ItemMeta trailing small text (time, date, amount)
35
- └─ List.ItemCount trailing Badge, one tier down
36
+ ├─ List.ItemCount trailing Badge, one tier down
37
+ └─ List.ItemActions the row's own controls (Switch, Dropdown): beside the row element, one tier down
36
38
  ```
37
39
 
38
40
  ## API
@@ -64,15 +66,15 @@ List.Root <ul aria-label>; size (else the host tier) → row t
64
66
  | `rel` | `string` | — | Relationship of the `<a>` (`href` only). |
65
67
  | `asChild` | `boolean` | `false` | Renders the single child (a router link) as the row; its children are the content. |
66
68
  | `disabled` | `boolean` | `false` | Muted and out of the Tab order: a disabled button, or `aria-disabled` and no navigation on a link. |
67
- | `children` | `ReactNode` | — | `List.ItemIcon`, `List.ItemText`, `List.ItemDescription`, `List.ItemMeta`, `List.ItemCount`; loose text becomes the text line. |
69
+ | `children` | `ReactNode` | — | `List.ItemIcon`, `List.ItemText`, `List.ItemDescription`, `List.ItemMeta`, `List.ItemCount`, `List.ItemActions`; loose text becomes the text line. |
68
70
  | `…rest` | `ButtonHTMLAttributes<HTMLButtonElement>` | — | `className` and native attributes of the row element (`target`, `rel` on a link). |
69
71
 
70
72
  ### List.ItemIcon
71
- `ref` → `HTMLSpanElement`. Leading `aria-hidden` slot: an `Avatar.Root` (without its own `size` it takes the row tier), or an `Icon`. After the text it is a trailing glyph.
73
+ `ref` → `HTMLSpanElement`. Leading `aria-hidden` slot: an `Avatar.Root` (without its own `size` it takes the row tier), an `Icon` or a colour `Badge.Dot` in an icon-wide box. After the text it is a trailing glyph.
72
74
 
73
75
  | Prop | Type | Default | Description |
74
76
  |---|---|---|---|
75
- | `children` | `ReactNode` | — (required) | An `Avatar.Root` or an `Icon`. |
77
+ | `children` | `ReactNode` | — (required) | An `Avatar.Root`, an `Icon`, or a `Badge.Dot` with `color` (a stage, a project): the large dot. |
76
78
  | `…rest` | `Omit<HTMLAttributes<HTMLSpanElement>, "children">` | — | `className` and the other `span` attributes. |
77
79
 
78
80
  ### List.ItemText
@@ -105,6 +107,13 @@ List.Root <ul aria-label>; size (else the host tier) → row t
105
107
  | `children` | `ReactNode` | — (required) | The number or a short status. |
106
108
  | `…rest` | `Omit<HTMLAttributes<HTMLSpanElement>, "children" \| "color">` | — | `className` and the other `span` attributes. |
107
109
 
110
+ ### List.ItemActions
111
+ `ref` → `HTMLDivElement`. The row's own controls (a `Switch`, a `Dropdown` with its icon `Button`) at its end, beside the row element and never inside it, one tier below the row.
112
+
113
+ | Prop | Type | Default | Description |
114
+ |---|---|---|---|
115
+ | `…rest` | `HTMLAttributes<HTMLDivElement>` | — | `children` (the controls, each named on its own), `className` and the other `div` attributes. |
116
+
108
117
  ## Variants
109
118
 
110
119
  ### size
@@ -139,17 +148,20 @@ A second line or an avatar makes a row taller than the one-line height; the vert
139
148
  | disabled | `disabled` | `disabled` on a button; `aria-disabled="true"`, no `href` on a link, `tabindex="-1"` on an `asChild` element; `data-disabled="true"`; disabled text; in a reorderable list the handle is disabled and the row holds its place |
140
149
  | reorderable | `onReorder` | `data-reorderable="true"` on the root (a `Dnd.Sortable` `<ul>`); each `<li>` is a sortable item (`data-dnd-item` = `value`) with a leading `Dnd.Handle`; drag by the handle (a touch hold on touch), Alt + ↑ / ↓ from the handle or the row; a lifted row leaves a dashed gap in the row's radius, its neighbours glide, the copy (handle and row, in the row's padding and radius) follows the pointer and sets down in its new place without a jump |
141
150
  | saving a move | `onReorder` returned a pending promise | the row stays in its new place, `aria-busy="true"`, the handle is busy (Dnd: a spinner in the disabled grip), the row content dims to 0.6 (`--prime-motion-fade-fast` both ways); a rejection glides the row back |
151
+ | own controls | `List.ItemActions` in the item | the row element and the controls stand in one frame that takes the hover, press and current fills for both; the element itself stays clear |
142
152
  | rows come and go | the data adds or takes out a `List.Item` (`value`, else its key) | a new row rises in once (`enterMotion`), a removed one closes up in place (`listPresence`); the first render stays still |
143
153
 
144
154
  Root attributes: `data-size`, `role="list"` (the list style reset would drop the list semantics in WebKit). The fill changes on `background-color` with `--prime-motion-fade-xfast` both ways (a fade: reduced motion keeps it).
145
155
 
146
156
  ## Layout & spacing
147
157
  - The root fills its container (`width: 100%`); rows are 4px apart, each row a full-width button with the tier radius and field padding.
148
- - Put the list on a surface: a `Card.Root` pane in `PageContent.Panel kind="list"`, with a `ScrollContainer` around it when it is long — the list never scrolls by itself.
158
+ - Put the list on a surface: a `Card.Root` pane in `Page.List`, with a `ScrollContainer` around it when it is long — the list never scrolls by itself.
149
159
  - Row: leading icon · body (text over description) · trail. Beside two lines the trail stacks — meta on top, count below; beside one line they sit in a row.
150
160
  - Text and description truncate with an ellipsis; give a long `List.ItemText` a `title` with the full text.
151
161
  - On a coarse pointer a row is at least the touch target (44px).
152
162
  - Reorderable (`onReorder`): an `xs` handle box sits before each row, 4px from it; the row keeps its own padding and fill.
163
+ - `List.ItemActions`: the controls one tier below the row, 4px apart, as far from the row's end as from its top and bottom.
164
+ - A colour dot in `List.ItemIcon` is the large `Badge.Dot` (8px) centred in an icon-wide box, so the text lines up with the rows that carry icons.
153
165
 
154
166
  ## Accessibility
155
167
 
@@ -169,6 +181,7 @@ Root attributes: `data-size`, `role="list"` (the list style reset would drop the
169
181
  - The open record: `aria-current="true"` on a button (a selection inside the screen), `aria-current="page"` on a link (`href`, `asChild`) — the link points at the current URL. A router link may set it itself.
170
182
  - The row's name is its text, description, meta and count, in that order; the leading icon or avatar is `aria-hidden` — the text names the row.
171
183
  - Arrow keys do not move between rows: rows are ordinary Tab stops, as in the Sidebar.
184
+ - `List.ItemActions` stand beside the row element, never inside it: the row's name stays its text, and Tab goes from the row to its controls.
172
185
  - With `onReorder` each row gets a handle named «Переместить {label}» (`labels.reorderItem`, `{label}` is the row's text line) and `aria-keyshortcuts`; the new place is announced politely («Новый лид: позиция 2 из 5»), a row being saved is `aria-busy`.
173
186
 
174
187
  ### Labels
@@ -184,10 +197,11 @@ Root attributes: `data-size`, `role="list"` (the list style reset would drop the
184
197
  | [overview.tsx](examples/overview.tsx) | A support ticket queue with the client, the last update and the open count; a click opens a ticket and makes it the current row — `current`, `onClick`. |
185
198
  | [sizes.tsx](examples/sizes.tsx) | Every size tier: row height, text, icon and count follow the tier — `size`. |
186
199
  | [states.tsx](examples/states.tsx) | The open record, a regular row and an unavailable one — `current`, `disabled`. |
187
- | [with-icon.tsx](examples/with-icon.tsx) | Leading avatars of clients and icons of queues; an avatar takes the row tier — `List.ItemIcon`. |
200
+ | [with-icon.tsx](examples/with-icon.tsx) | Leading avatars of clients, icons of queues and colour dots of projects; an avatar takes the row tier, a dot stands in an icon-wide box — `List.ItemIcon`, `Badge.Dot`. |
188
201
  | [overflow.tsx](examples/overflow.tsx) | A long inbox in a pane of a fixed height: the list scrolls in a ScrollContainer and long names and previews truncate — `List.ItemText`, `List.ItemDescription`. |
189
202
  | [as-link.tsx](examples/as-link.tsx) | Rows as links to the invoice pages: a plain link, or your router link through the slot — `href`, `asChild`. |
190
203
  | [reorder.tsx](examples/reorder.tsx) | Funnel stages in the team's order: a stage moves by its handle or Alt+arrows and is saved on the server — `onReorder`, `value`. |
204
+ | [row-controls.tsx](examples/row-controls.tsx) | Funnel stages with their own controls: a colour dot names the stage's hue, a switch shows it on the board and a menu edits it, all beside the row that opens the stage — `List.ItemActions`, `Badge.Dot`. |
191
205
 
192
206
  ## Mistakes
193
207
  - Rows hand-drawn from `Button.Root variant="ghost"` with a `soft` current → `List.Item current`.
@@ -197,7 +211,9 @@ Root attributes: `data-size`, `role="list"` (the list style reset would drop the
197
211
  - A long list without a scroller → wrap it in `ScrollContainer` inside the pane.
198
212
  - Up / down buttons on rows or a hand-made `Dnd.Sortable` of rows to order them → `List.Root onReorder` with a `value` on every item.
199
213
  - `onReorder` that rolls the order back itself on an error → return the promise; a rejection moves the row back.
214
+ - A Switch or a menu button put inside a row, or a row rebuilt as a `div` to hold one → `List.ItemActions` beside the row element.
215
+ - A hollow `Icon` circle or a hand-drawn dot as a stage colour → `Badge.Dot color` in `List.ItemIcon`.
200
216
 
201
217
  ## Related
202
- - **Built from:** [Badge](../badge/COMPONENT.md) (`List.ItemCount`), [Avatar](../avatar/COMPONENT.md) (`List.ItemIcon` gives an avatar the row tier), [Dnd](../dnd/COMPONENT.md) (`onReorder`: `Dnd.Sortable`, the busy `Dnd.Handle`)
203
- - **See also:** [PageContent](../page-content/COMPONENT.md), [Sidebar](../../layout/sidebar/COMPONENT.md), [Tabs](../tabs/COMPONENT.md), [DataTable](../data-table/COMPONENT.md), [Card](../card/COMPONENT.md)
218
+ - **Built from:** [Badge](../badge/COMPONENT.md) (`List.ItemCount`; `Badge.Dot` in `List.ItemIcon`), [Avatar](../avatar/COMPONENT.md) (`List.ItemIcon` gives an avatar the row tier), [Dnd](../dnd/COMPONENT.md) (`onReorder`: `Dnd.Sortable`, the busy `Dnd.Handle`)
219
+ - **See also:** [Page](../../layout/page/COMPONENT.md), [Sidebar](../../layout/sidebar/COMPONENT.md), [Tabs](../tabs/COMPONENT.md), [DataTable](../data-table/COMPONENT.md), [Card](../card/COMPONENT.md)
@@ -0,0 +1,80 @@
1
+ /** Funnel stages with their own controls: a colour dot names the stage's hue, a switch shows it on the board and a menu edits it, all beside the row that opens the stage — `List.ItemActions`, `Badge.Dot`. */
2
+ import { Badge, Button, Card, Dropdown, Icon, List, type PaletteColor, Switch } from "prime-ui-kit";
3
+ import * as React from "react";
4
+
5
+ import styles from "./examples.module.css";
6
+
7
+ type Stage = { id: string; name: string; color: PaletteColor; deals: number; shown: boolean };
8
+
9
+ const STAGES: Stage[] = [
10
+ { id: "lead", name: "Новый лид", color: "blue", deals: 42, shown: true },
11
+ { id: "qualified", name: "Квалификация", color: "purple", deals: 18, shown: true },
12
+ { id: "proposal", name: "Коммерческое предложение", color: "orange", deals: 11, shown: true },
13
+ { id: "paused", name: "Отложено", color: "gray", deals: 7, shown: false },
14
+ ];
15
+
16
+ export default function ListRowControlsExample() {
17
+ const [stages, setStages] = React.useState(STAGES);
18
+ const [current, setCurrent] = React.useState("lead");
19
+
20
+ const patch = (id: string, next: Partial<Stage>) =>
21
+ setStages((list) => list.map((stage) => (stage.id === id ? { ...stage, ...next } : stage)));
22
+
23
+ return (
24
+ <Card.Root className={styles.pane}>
25
+ <Card.Body>
26
+ <List.Root aria-label="Этапы воронки">
27
+ {stages.map((stage) => (
28
+ <List.Item
29
+ key={stage.id}
30
+ value={stage.id}
31
+ current={current === stage.id}
32
+ onClick={() => setCurrent(stage.id)}
33
+ >
34
+ <List.ItemIcon>
35
+ <Badge.Dot color={stage.color} />
36
+ </List.ItemIcon>
37
+ <List.ItemText>{stage.name}</List.ItemText>
38
+ <List.ItemCount>{stage.deals}</List.ItemCount>
39
+ <List.ItemActions>
40
+ <Switch.Root
41
+ aria-label={`Показывать «${stage.name}» на доске`}
42
+ checked={stage.shown}
43
+ onCheckedChange={(shown) => patch(stage.id, { shown })}
44
+ />
45
+ <Dropdown.Root>
46
+ <Dropdown.Trigger>
47
+ <Button.Root
48
+ variant="ghost"
49
+ tone="neutral"
50
+ aria-label={`Действия с этапом «${stage.name}»`}
51
+ >
52
+ <Button.Icon>
53
+ <Icon name="action.more" />
54
+ </Button.Icon>
55
+ </Button.Root>
56
+ </Dropdown.Trigger>
57
+ <Dropdown.Content>
58
+ <Dropdown.Item onSelect={() => setCurrent(stage.id)}>Открыть</Dropdown.Item>
59
+ <Dropdown.Item onSelect={() => patch(stage.id, { color: "green" })}>
60
+ Отметить зелёным
61
+ </Dropdown.Item>
62
+ <Dropdown.Separator />
63
+ <Dropdown.Item
64
+ tone="danger"
65
+ onSelect={() =>
66
+ setStages((list) => list.filter((item) => item.id !== stage.id))
67
+ }
68
+ >
69
+ Удалить этап
70
+ </Dropdown.Item>
71
+ </Dropdown.Content>
72
+ </Dropdown.Root>
73
+ </List.ItemActions>
74
+ </List.Item>
75
+ ))}
76
+ </List.Root>
77
+ </Card.Body>
78
+ </Card.Root>
79
+ );
80
+ }
@@ -1,5 +1,5 @@
1
- /** Leading avatars of clients and icons of queues; an avatar takes the row tier — `List.ItemIcon`. */
2
- import { Avatar, Icon, List, Typography } from "prime-ui-kit";
1
+ /** Leading avatars of clients, icons of queues and colour dots of projects; an avatar takes the row tier, a dot stands in an icon-wide box — `List.ItemIcon`, `Badge.Dot`. */
2
+ import { Avatar, Badge, Icon, List, Typography } from "prime-ui-kit";
3
3
 
4
4
  const CLIENTS = [
5
5
  { id: "belova", name: "Ирина Белова", company: "ООО «Гранит»", initials: "ИБ", color: "blue" },
@@ -7,6 +7,12 @@ const CLIENTS = [
7
7
  { id: "kozlov", name: "Сергей Козлов", company: "ИП Козлов", initials: "СК", color: "orange" },
8
8
  ] as const;
9
9
 
10
+ const PROJECTS = [
11
+ { id: "crm", name: "Внедрение CRM", color: "purple" },
12
+ { id: "portal", name: "Клиентский портал", color: "teal" },
13
+ { id: "billing", name: "Биллинг", color: "orange" },
14
+ ] as const;
15
+
10
16
  export default function ListWithIconExample() {
11
17
  return (
12
18
  <div>
@@ -56,6 +62,21 @@ export default function ListWithIconExample() {
56
62
  Icon
57
63
  </Typography>
58
64
  </div>
65
+ <div>
66
+ <List.Root aria-label="Проекты">
67
+ {PROJECTS.map((project, index) => (
68
+ <List.Item key={project.id} current={index === 0}>
69
+ <List.ItemIcon>
70
+ <Badge.Dot color={project.color} />
71
+ </List.ItemIcon>
72
+ <List.ItemText>{project.name}</List.ItemText>
73
+ </List.Item>
74
+ ))}
75
+ </List.Root>
76
+ <Typography as="span" variant="caption" tone="muted">
77
+ Badge.Dot
78
+ </Typography>
79
+ </div>
59
80
  </div>
60
81
  </div>
61
82
  );
@@ -34,7 +34,7 @@ LoginForm.Root width cap; a Card inside: card fill, radius,
34
34
  │ └─ LoginForm.Actions primary button + ghost back action
35
35
  └─ LoginForm.Footer «Нет аккаунта? <LinkButton>»
36
36
  ```
37
- Every part is optional except `Root`, `Title` and `Form`. Fields, buttons, dividers, banners and links are the regular kit components; LoginForm owns only the layout and the rhythm.
37
+ Every part is optional except `Root`, `Title` and `Form`. Fields, buttons, dividers and links are the regular kit components; LoginForm owns only the layout and the rhythm.
38
38
 
39
39
  ## API
40
40
 
@@ -149,8 +149,8 @@ Every part is optional except `Root`, `Title` and `Form`. Fields, buttons, divid
149
149
  | `flat` | card fill, no shadow | inside a Modal or any other surface | `false` |
150
150
 
151
151
  **Combinations**
152
- - Recommended: one `size` on Root only (fields and buttons follow it); `hint` / `error` on fields for validation; a danger [Banner](../banner/COMPONENT.md) at the top of `Form` for server errors.
153
- - Avoid: more than one primary button; provider buttons in `solid` (they compete with the submit); a Card around LoginForm.
152
+ - Recommended: one `size` on Root only (fields and buttons follow it); `hint` / `error` on fields for validation; a refused sign-in as `invalid` on the fields it concerns plus a [VisuallyHidden](../visually-hidden/COMPONENT.md) live region with the reason.
153
+ - Avoid: a [Banner](../banner/COMPONENT.md) in the form; more than one primary button; provider buttons in `solid` (they compete with the submit); a Card around LoginForm.
154
154
 
155
155
  ## States
156
156
  LoginForm has no state of its own. Compose them:
@@ -159,7 +159,7 @@ LoginForm has no state of its own. Compose them:
159
159
  |---|---|---|
160
160
  | submitting | `loading` on the submit Button; the fields in a `Fieldset disabled`, the submit Button outside it | `aria-busy` on the button; native `disabled` on the `<fieldset>`, the fields in their disabled look |
161
161
  | field error | `error` / `invalid` on `Input.Root`, `error` on `DigitInput` | `aria-invalid`, the error under the field |
162
- | server error | `Banner.Root tone="danger" role="alert"` as the first child of `LoginForm.Form` | `role="alert"` |
162
+ | refused sign-in | `invalid` on the fields it concerns (they shake once); `VisuallyHidden live="assertive"`, mounted from the start in `LoginForm.Form`, gets the reason | `aria-invalid` on the fields; `role="alert"` on the hidden region |
163
163
 
164
164
  Root carries `data-size`, `data-align` and `data-flat`.
165
165
 
@@ -185,7 +185,7 @@ Root carries `data-size`, `data-align` and `data-flat`.
185
185
  - The logo is decorative; with an `aria-label` it is the product mark image (`role="img"`).
186
186
  - Give `LoginForm.Form` an `aria-label` (or `aria-labelledby` pointing to the title id) so the form is a landmark.
187
187
  - Fields use `autoComplete` (`email`, `current-password`, `new-password`, `one-time-code`) so password managers and OTP autofill work.
188
- - Server errors in a Banner need `role="alert"`; field errors come from the fields (`aria-invalid`, described by the error).
188
+ - Field errors come from the fields (`aria-invalid`, described by the error). A refused sign-in has no Banner: the fields it concerns take `invalid` and an always-mounted `VisuallyHidden live="assertive"` says why.
189
189
 
190
190
  ### Labels
191
191
  <!-- Generated from api.ts by `bun run docs:build`. Edit api.ts, not this section. -->
@@ -202,16 +202,17 @@ No `labels`.
202
202
  | [forgot-password.tsx](examples/forgot-password.tsx) | Password reset request: one field, the primary action and a quiet way back — `LoginForm.Actions`. |
203
203
  | [reset-password.tsx](examples/reset-password.tsx) | A new password after the e-mail link: a strength meter on the first field and a mismatch error under the second one — `strength`, `error`. |
204
204
  | [verification-code.tsx](examples/verification-code.tsx) | The second step with a one-time code: a rejected code shows its error under the cells, resend is a quiet action — `DigitInput`, `LoginForm.Actions`. |
205
- | [states.tsx](examples/states.tsx) | The submit cycle: the button is busy while the request runs, a failed request shows a danger Banner and marks the password — `loading`, `invalid`. |
205
+ | [states.tsx](examples/states.tsx) | The submit cycle: the button is busy while the request runs, a refused sign-in marks both fields, which shake once, and a hidden live region says why — `loading`, `invalid`, `VisuallyHidden`. |
206
206
  | [narrow.tsx](examples/narrow.tsx) | On a phone-width screen the card keeps its padding, the header wraps and the buttons stay full width — `LoginForm.Form`. |
207
207
 
208
208
  ## Mistakes
209
209
  - A separate block of your own for provider buttons → put them in `LoginForm.Actions`.
210
210
  - `disabled` on every field while the request runs → one [Fieldset](../fieldset/COMPONENT.md) `disabled` around the fields; keep the submit Button outside it so it shows `loading`.
211
+ - A danger Banner above the fields for a refused sign-in → `invalid` on the fields and the reason in a `VisuallyHidden live="assertive"`; a sign-in or sign-up form has no banners.
211
212
  - A placeholder instead of a field label → pass `label` to the field.
212
213
  - A Card around LoginForm → the root already is the card; use `flat` inside another surface.
213
214
  - Repeating the card `size` on every field and button → set it once on Root; fields and buttons follow it.
214
215
 
215
216
  ## Related
216
217
  - **Built from:** [Card](../card/COMPONENT.md) (the surface), [Typography](../typography/COMPONENT.md) (`Title`, `Description`, `Footer`), the icon tile (`iconBox` `.tile`, the `start` logo)
217
- - **See also:** [Input](../input/COMPONENT.md), [Fieldset](../fieldset/COMPONENT.md) (disables the fields while signing in), [Button](../button/COMPONENT.md), [LinkButton](../link-button/COMPONENT.md), [Divider](../divider/COMPONENT.md), [DigitInput](../digit-input/COMPONENT.md), [Banner](../banner/COMPONENT.md), [Modal](../modal/COMPONENT.md)
218
+ - **See also:** [Input](../input/COMPONENT.md), [Fieldset](../fieldset/COMPONENT.md) (disables the fields while signing in), [Button](../button/COMPONENT.md), [LinkButton](../link-button/COMPONENT.md), [Divider](../divider/COMPONENT.md), [DigitInput](../digit-input/COMPONENT.md), [VisuallyHidden](../visually-hidden/COMPONENT.md), [Modal](../modal/COMPONENT.md)
@@ -1,5 +1,5 @@
1
- /** The submit cycle: the button is busy while the request runs, a failed request shows a danger Banner and marks the password — `loading`, `invalid`. */
2
- import { Banner, Button, Fieldset, Icon, Input, LoginForm } from "prime-ui-kit";
1
+ /** The submit cycle: the button is busy while the request runs, a refused sign-in marks both fields, which shake once, and a hidden live region says why — `loading`, `invalid`, `VisuallyHidden`. */
2
+ import { Button, Fieldset, Icon, Input, LoginForm, VisuallyHidden } from "prime-ui-kit";
3
3
  import * as React from "react";
4
4
 
5
5
  export default function LoginFormStatesExample() {
@@ -30,20 +30,18 @@ export default function LoginFormStatesExample() {
30
30
  }, 1200);
31
31
  }}
32
32
  >
33
- {failed ? (
34
- <Banner.Root tone="danger" role="alert">
35
- <Banner.Content>
36
- <Banner.Icon>
37
- <Icon name="status.danger" />
38
- </Banner.Icon>
39
- <Banner.Title>Неверный email или пароль</Banner.Title>
40
- </Banner.Content>
41
- </Banner.Root>
42
- ) : null}
33
+ <VisuallyHidden live="assertive">
34
+ {failed ? "Неверный email или пароль" : ""}
35
+ </VisuallyHidden>
43
36
  <Fieldset disabled={pending}>
44
- <Input.Root label="Email" required>
37
+ <Input.Root label="Email" required invalid={failed}>
45
38
  <Input.Wrapper>
46
- <Input.Field type="email" autoComplete="email" placeholder="name@company.ru" />
39
+ <Input.Field
40
+ type="email"
41
+ autoComplete="email"
42
+ placeholder="name@company.ru"
43
+ onValueChange={() => setFailed(false)}
44
+ />
47
45
  </Input.Wrapper>
48
46
  </Input.Root>
49
47
  <Input.Root label="Пароль" required invalid={failed}>
@@ -1,5 +1,5 @@
1
1
  /** The parent owns the page: a finding opens its photo, and paging in the viewer moves the mark along the list — `index`, `onIndexChange`. */
2
- import { Button, MediaViewer, type MediaViewerItem } from "prime-ui-kit";
2
+ import { List, MediaViewer, type MediaViewerItem } from "prime-ui-kit";
3
3
  import * as React from "react";
4
4
 
5
5
  import styles from "./examples.module.css";
@@ -26,21 +26,21 @@ export default function MediaViewerControlledExample() {
26
26
  return (
27
27
  <>
28
28
  <div className={styles.findings}>
29
- {FINDINGS.map(([id, title], at) => (
30
- <Button.Root
31
- key={id}
32
- variant={at === index ? "soft" : "ghost"}
33
- tone="neutral"
34
- fullWidth
35
- aria-current={at === index ? "true" : undefined}
36
- onClick={() => {
37
- setIndex(at);
38
- setOpen(true);
39
- }}
40
- >
41
- {title}
42
- </Button.Root>
43
- ))}
29
+ <List.Root aria-label="Замечания проверки">
30
+ {FINDINGS.map(([id, title], at) => (
31
+ <List.Item
32
+ key={id}
33
+ value={id}
34
+ current={at === index}
35
+ onClick={() => {
36
+ setIndex(at);
37
+ setOpen(true);
38
+ }}
39
+ >
40
+ <List.ItemText>{title}</List.ItemText>
41
+ </List.Item>
42
+ ))}
43
+ </List.Root>
44
44
  </div>
45
45
  <MediaViewer
46
46
  items={PHOTOS}
@@ -8,9 +8,7 @@
8
8
  inline-size: min(100%, var(--prime-layout-form-width-m));
9
9
  }
10
10
 
11
- /* controlled.tsx: the list of findings beside the photos. */
11
+ /* controlled.tsx: the column of the list of findings beside the photos. */
12
12
  .findings {
13
- display: grid;
14
- gap: var(--prime-space-2);
15
13
  inline-size: min(100%, var(--prime-layout-form-width-s));
16
14
  }
@@ -8,7 +8,8 @@
8
8
  ## When to use
9
9
  - A message of any kind: text with formatting, a reply, a forwarded message, reactions, photos and albums (`Message.Media`, a `Gallery`), a round video message (`VideoNote` inside), a voice message (`VoicePlayer` inside), a file, a location, a contact, a link preview.
10
10
  - The rows of a conversation in [Chat](../chat/COMPONENT.md) (`Chat.Messages`): the list, dates, search, selection and jumps live there; the message is one row.
11
- - A message on its own: a quoted reply in a ticket, the last message in a card, a preview of what will be sent.
11
+ - A message on its own: a quoted reply in a ticket, the last message in a card, a preview of what will be sent (`preview` — a bot's welcome message on its settings page).
12
+ - A sticker (`Message.Sticker`): a webp or gif by `src`, or your own Lottie / video player as children.
12
13
  - «Печатает…» (`Message.Typing`) as the last row of a list.
13
14
 
14
15
  ## When not to use
@@ -17,6 +18,7 @@
17
18
  - A feed of events with a time axis (an order history, an audit log) → [Timeline](../timeline/COMPONENT.md).
18
19
  - One system message on a page (saved, failed) → [Banner](../banner/COMPONENT.md) or a [Notification](../notification/COMPONENT.md).
19
20
  - Photos outside a message → [Gallery](../gallery/COMPONENT.md); a recording outside a chat → [VoicePlayer](../voice-player/COMPONENT.md).
21
+ - Formatted text outside a message, with no bubble → [RichText](../rich-text/COMPONENT.md).
20
22
 
21
23
  ## Import
22
24
  ```tsx
@@ -35,7 +37,8 @@ Message.Root role="article" row «{author}, {time}» (an op
35
37
  │ ├─ Message.Forwarded «Переслано от …»
36
38
  │ ├─ Message.Reply quote of the answered message (button with target / onClick)
37
39
  │ ├─ content Message.Text · Message.Media (+ caption Text) · VoicePlayer · Message.File ·
38
- │ │ Message.Location · Message.Contact · Message.LinkPreview · VideoNote
40
+ │ │ Message.Location · Message.Contact · Message.LinkPreview · VideoNote ·
41
+ │ │ Message.Sticker
39
42
  │ │ (a voice message or a circle may open its transcript under it)
40
43
  │ ├─ Message.Reactions a row held closed in every message; chips closing a bubble
41
44
  │ │ (under a picture or a circle), the meta's spacer at its end
@@ -52,9 +55,9 @@ The part that ends a bubble closes its last line with the meta's spacer — an i
52
55
 
53
56
  In a list (`Chat.Messages`) a message reads the list through `internal/messageList`: its place in a run (`position`) and the chat's kind decide the author's header (first of a run in a group chat) and the avatar (last of a run); the list registers it for new-message entry and read receipts, selects it, jumps to it and holds its size changes still. On its own a message given an author or an avatar does the same by its `position`: the header on `single` / `first`, the avatar (and the gutter) on `single` / `last`.
54
57
 
55
- Content parts in short: `Message.Media` — a [Gallery](../gallery/COMPONENT.md) the message shapes (the messenger album layout from the items' ratios, every box final before load, the shared transfer disk over a tile, the meta overlay; an album's gaps stand on the incoming surface in both directions). `VideoNote` and `VoicePlayer` are components of their own that declare themselves parts (the round shell, and a fill bubble) and carry the same transfer props as `Message.File`. `Message.File` — a round format tile (or the preview) that is also its one action (download, cancel inside the progress ring, retry), the name, and the size line under it ending with the spacer. `Message.Location` — the map edge to edge with an accent pin (breathing when `live`), the place and the address ending with the spacer. `Message.Text` renders the Markdown subset the Composer writes — **bold**, _italic_, ~~strike~~, `code`, fenced code, Markdown links, bare URLs, `> ` quotes — as elements; links take only http(s), mailto and tel addresses (anything else stays text) and open in a new tab. `Message.Menu` holds the `Dropdown.Item`s you write (Ответить, Скопировать, Закрепить, Переслать, Пожаловаться, Удалить with `tone="danger"`); in a chat with a selection the kit appends a separator and «Выбрать».
58
+ Content parts in short: `Message.Media` — a [Gallery](../gallery/COMPONENT.md) the message shapes (the messenger album layout from the items' ratios, every box final before load, the shared transfer disk over a tile, the meta overlay; an album's gaps stand on the incoming surface in both directions). `VideoNote` and `VoicePlayer` are components of their own that declare themselves parts (the round shell, and a fill bubble) and carry the same transfer props as `Message.File`. `Message.File` — a round format tile (or the preview) that is also its one action (download, cancel inside the progress ring, retry), the name, and the size line under it ending with the spacer. `Message.Location` — the map edge to edge with an accent pin (breathing when `live`), the place and the address ending with the spacer. `Message.Sticker` — a square picture with no bubble (`media` shell, the meta on its pill): the kit draws a webp, gif or apng from `src`; a Lottie (.tgs) or video sticker is your player as children (the kit has no runtime dependencies), with `loading` while it prepares. `Message.Text` renders the Markdown subset the Composer writes — **bold**, _italic_, ~~strike~~, `code`, fenced code, Markdown links, bare URLs, `> ` quotes — as elements; links take only http(s), mailto and tel addresses (anything else stays text) and open in a new tab. `Message.Menu` holds the `Dropdown.Item`s you write (Ответить, Скопировать, Закрепить, Переслать, Пожаловаться, Удалить with `tone="danger"`); in a chat with a selection the kit appends a separator and «Выбрать».
56
59
 
57
- `formatMessageTime(date)` gives «09:05», the default `formatTime`. `hueOf(id)` gives a palette hue stable per id for `Message.Author color` and the author's `Avatar`.
60
+ `formatMessageTime(date, timeZone?)` gives «09:05», the default `formatTime`; the time is read in `timeZone`, else the list's (`Chat.Messages timeZone`), else the browser's zone. `hueOf(id)` gives a palette hue stable per id for `Message.Author color` and the author's `Avatar`.
58
61
 
59
62
  ## API
60
63
 
@@ -68,9 +71,11 @@ Content parts in short: `Message.Media` — a [Gallery](../gallery/COMPONENT.md)
68
71
  | `direction` | `"incoming" \| "outgoing"` | `"incoming"` | `incoming` — on the start side, a surface one step off the chat; `outgoing` — on the end side, in the accent hue (`--prime-color-message-outgoing-*`), everything inside recolors with it. |
69
72
  | `position` | `"single" \| "first" \| "middle" \| "last"` | `"single"` | The place in a run of one author (`Chat.Messages items` sets it): `single` and `last` end a run with the tail (and a group chat's avatar); `single` and `first` show the author's header. |
70
73
  | `time` | `Date \| string` | — | When it was sent: a `Date` shown with `formatTime` (and put in `<time dateTime>`), or the text to show. |
71
- | `formatTime` | `(date: Date) => string` | «09:05» | Display of a `Date` time. |
74
+ | `timeZone` | `string` | the list's `timeZone`, else the browser's zone | The IANA zone the time is read in (`"Asia/Vladivostok"`): a profile's zone, not the browser's. |
75
+ | `formatTime` | `(date: Date, timeZone?: string) => string` | «09:05» | Display of a `Date` time; gets the `timeZone` in force. |
72
76
  | `edited` | `boolean` | `false` | The text was edited: `labels.edited` before the time. |
73
77
  | `status` | `"sending" \| "sent" \| "read" \| "failed"` | — | Delivery of an outgoing message: a clock, one check, two checks (accent), or a danger mark; the glyphs cross-fade from one state to the next. Named for assistive tech by `labels`. |
78
+ | `preview` | `boolean` | `false` | A picture of the message outside a chat (a bot's settings): no menu, reactions, retry or row focus, `Message.Actions` inert; links and players still work. |
74
79
  | `onRetry` | `() => void \| Promise<void>` | — | Sends a failed message again: a ghost danger button beside the bubble. A returned promise shows `sending` until it settles; a rejection leaves it failed. |
75
80
  | `onReactionToggle` | `(emoji: string) => void \| Promise<unknown>` | — | Puts or takes back the reader's reaction (a chip, a double tap, `L`, the reaction bar). Shown at once; a returned promise keeps it pending, a rejection drops it back. Without it reactions are read-only. |
76
81
  | `value` | `string` | — | The message id for selection, jumps, read receipts, search, pins and `Message.Reply target` (`Chat.Messages items` sets the item's key). Keep it when the server confirms a sent message. |
@@ -206,6 +211,16 @@ Content parts in short: `Message.Media` — a [Gallery](../gallery/COMPONENT.md)
206
211
  | `image` | `string` | — | The page's picture, full width under the text. |
207
212
  | `…rest` | `Omit<HTMLAttributes<HTMLElement>, "title">` | — | `className` and the other attributes of the link. |
208
213
 
214
+ ### Message.Sticker
215
+ `ref` → `HTMLDivElement` (`role="img"`). A sticker: a square picture with no bubble, the meta on a pill over its corner; a `Skeleton` holds the box until it is ready.
216
+
217
+ | Prop | Type | Default | Description |
218
+ |---|---|---|---|
219
+ | `aria-label` | `string` | — (required) | The sticker's name («Стикер «Класс»», or its emoji); shown in its box when `src` fails. |
220
+ | `src` | `string` | — | A still or animated picture (webp, gif, apng), decoded before it shows. Without it the children are the sticker. |
221
+ | `loading` | `boolean` | `false` | Your player in the children is not ready yet: the `Skeleton` stays over the box. |
222
+ | `…rest` | `Omit<HTMLAttributes<HTMLDivElement>, "role" \| "aria-label">` | — | `children` — your player for a Lottie (.tgs) or a video sticker, sized to the box; `className`. |
223
+
209
224
  ### Message.Reactions
210
225
  `ref` → `HTMLDivElement`. Reaction chips at the bottom of a bubble, or under a picture or a circle: a `role="group"` of toggle chips — the emoji, then who reacted (`users`) or the count. A press goes to `Message.Root onReactionToggle`.
211
226
 
@@ -250,7 +265,7 @@ Decided by the content parts, not a prop (`data-shell` on the bubble): a circle
250
265
  | Value | Looks like | Use when | Default |
251
266
  |---|---|---|---|
252
267
  | `bubble` | fill (surface or accent), padding, the meta in the bottom-end corner over the last line's reserve | text, voice, file, contact, location, link preview, a picture **with** a caption | yes |
253
- | `media` | the picture itself, clipped to the radius — no backing, no padding; the meta on a dark pill over its bottom-end corner; reactions in a row of their own **under** it, on the message's side (chips in their own fill); an album's gaps show the incoming surface in both directions, never the outgoing fill | a photo, a video or an album **without** a caption | |
268
+ | `media` | the picture itself, clipped to the radius — no backing, no padding; the meta on a dark pill over its bottom-end corner; reactions in a row of their own **under** it, on the message's side (chips in their own fill); an album's gaps show the incoming surface in both directions, never the outgoing fill | a photo, a video or an album **without** a caption; a sticker | |
254
269
  | `round` | `VideoNote`: a circle standing on the chat — no backing in either direction; the duration and the meta float on their own pills over its bottom; reactions under it as for `media` | a round video message | |
255
270
 
256
271
  With a caption a picture sits at the top of a normal bubble, edge to edge, and its reactions stay inside it, under the caption. The row of reactions is held closed in every message and opens with the first reaction (see States).
@@ -294,6 +309,8 @@ The fill moves between the two in a color transition (`fast`, both ways); the av
294
309
  | Prop | Effect |
295
310
  |---|---|
296
311
  | `edited` | «изменено» before the time |
312
+ | `preview` | a picture of the message outside a chat: no menu, reaction bar, reactions toggle, retry or row focus; `Message.Actions` rows `inert` (seen, never pressed); links, players and spoilers still work |
313
+ | `Message.Sticker loading` | the Skeleton stays over the sticker's box while your player prepares |
297
314
  | `Message.Location live` | a breathing pin and a «Трансляция» badge |
298
315
  | `Message.Text plain` | a string without Markdown |
299
316
  | `Message.Typing open` | the typing bubble shows; off, it leaves closing its height |
@@ -313,6 +330,8 @@ The list-level settings a message reads — the group chat's author header and a
313
330
  | retrying | `onRetry` returns a promise | `sending` ticks and a `loading` retry button until it settles |
314
331
  | inline keyboard | `Message.Actions` children | `data-actions` on the message column: the rows under the bubble, the bubble at least as wide as them, no tail |
315
332
  | failed | `status="failed"` | `data-failed` on the row; danger mark, retry button |
333
+ | preview | `preview` | `data-preview` on the row, no `tabindex`; `inert` on every `Message.Actions` row |
334
+ | sticker loading | `Message.Sticker` until its `src` is decoded, or while `loading` | `data-status="loading"`, `aria-busy`: a `Skeleton` covers the box, then fades out over the picture (`fade-base`); a `src` that fails shows the sticker's name, `data-status="error"` |
316
335
  | reaction toggled | a chip, a double tap, `L`, the reaction bar | the chip changes in place (never remounts) in the same frame: the fill is a color transition (`fast`); a reactor who joins fades and scales in from 0.9 while the stack widens (its width follows its circles), one who leaves the reverse; a count that only changes value rolls its digits and the chip does not move — its width follows the number of digits (tabular) and moves (`fast`) only when that changes; the reader (`Chat.Messages reader`) joins or leaves the avatar stack; while a returned promise runs `aria-busy`, `data-pending` — update `items` before it resolves; a rejection drops it back. Without `onReactionToggle` the chips are read-only and there is no reaction bar |
317
336
  | size change | a reaction row that opens or closes, a chip that comes or goes, a transcript, an edit, an upload state | one stroke (`bubbleMorph`, `--prime-message-morph-duration` 300 ms): the new layout is laid out at once, in the same frame, and the bubble's visible box glides from the old rectangle to the new one — width and height together, one `clip-path: inset(… round …)` animation on the compositor, the fill a layer under the content that reaches over both boxes. Every part that moved (the text, the meta, the cards, the chips, the tail, the retry) glides from where it was by a `transform` on the same clock; a part that came fades (a chip also scales from 0.9) in where it stands once the box has room for it; a part that went fades out where it stood, out of flow. A change mid-flight retargets from what is on screen; a commit that moves nothing touches nothing. The meta and the tail stay put on a reaction: the message grows upward, the chat scrolling by the change in the same frame while the rows above glide as one block on the same clock (the rows below never move). A disclosed block (a transcript) fades over the whole stroke while the box opens or closes over it. The text glides straight with the bubble's top-start corner, keeping its padding all the way. Nothing travels across text: a meta that stays while text passes through its place dips — it fades out at the same spot before the text reaches it and back once the text has left — and a meta that changes line (a transcript's last line ↔ the player row) cross-fades — out at its old place in the first 40 % of the stroke, in at its new place in the last 40 %. Easing `standard`. Reduced motion: instant (the scroll still keeps the view) |
318
337
  | new reaction | an emoji not on the message yet (the reader's or anyone's) | part of the size change: its room is there at once and the chip fades and scales in from 0.9 where it stands, on the bubble's clock, once the parts moving away have left its place. Never on the first render of a message: opening a chat or loading history plays nothing |
@@ -337,7 +356,7 @@ The list-level settings a message reads — the group chat's author header and a
337
356
  - **The author's header** (a group chat, the first of a run): one line `body-s` — the name semibold in the author's hue, an `xs` icon, the tag muted after them; the name ellipsizes first, then the tag. The bubble hugs the whole line, so a long name or tag widens it up to its cap. Over a picture or a circle without a caption it stands on the media pill at `space-2` from the top-start corner, in the pill's colors.
338
357
  - **A bubble hugs its text** (`bubbleHug`): a bubble of text — text, author, reply, forwarded, reactions — is as wide as its widest laid-out line plus the padding, never the width its lines wrapped in, and never wider than the cap; the meta's room counts on the last line only, where it sits, the reactions row as one line of chips with the meta after them, and the author's header at its full width (`data-message-fit="row"`, an ellipsized name counted whole). Quote and code blocks stretch to the bubble's width; long code lines wrap. Plain wrapping, never `pretty`. The width is measured once per text and row width — cleared, measured and written in one pass in the commit that changed the text, before paint, so a size change's morph runs to the hugged width — and cached by both: a row the window renders again takes its width with nothing measured. Row widths come from one shared `ResizeObserver`, batched per frame; hover, the menu, the reaction bar and selection never measure; a morph reads boxes only, never the hug width; fonts that finish loading measure once more. A bubble with any other part (a card, a player, a picture) keeps the width its parts give it.
339
358
  - No minimum width beyond the corners: «Ок 10:16» is a compact pill — the text, the meta on the same line and the padding. With reactions the meta moves to the end of the row's last line and the text gives its room back.
340
- - Fixed kinds stay one width: a file, a contact and a location are `--prime-message-card-width` (16rem, at most 75% of the chat), a voice message is the player's width, a round video is the VideoNote circle (268, at most the row), a link preview the media width (360) or what the row allows.
359
+ - Fixed kinds stay one width: a file, a contact and a location are `--prime-message-card-width` (16rem, at most 75% of the chat), a voice message is the player's width, a round video is the VideoNote circle (268, at most the row), a sticker the square `--prime-message-sticker` (160, at most 85% of the row), a link preview the media width (360) or what the row allows.
341
360
  - Embedded blocks (a link preview, a reply quote, a forwarded header, the cards) span the bubble's content width; long unbreakable text (URLs) wraps instead of widening the bubble.
342
361
  - Pictures follow the album layout of their Gallery, at most `--prime-gallery-max-size` (360) wide and tall and within 85% of the row; a bubble with a picture or a card is exactly that part's width and a caption wraps under it.
343
362
  - A file's name stands on one line without the extension its format tile shows; the full name is its tooltip and the download label. The tile downloads by an `href` link, or with `transfer="remote"` through `onDownload` in the app.
@@ -488,6 +507,8 @@ The list-level settings a message reads — the group chat's author header and a
488
507
  | [contact.tsx](examples/contact.tsx) | A shared contact: initials or a photo, name and phone, with the actions to write or save — `Message.Contact`, `phone`. |
489
508
  | [link-preview.tsx](examples/link-preview.tsx) | A message with a link and the card of the page under it: site, title, description and picture — `Message.LinkPreview`, `site`, `image`. |
490
509
  | [bot-actions.tsx](examples/bot-actions.tsx) | A bot's message with an inline keyboard: rows of buttons under the bubble at its width, sharing each row equally, one of them a link — `Message.Actions`, `asChild`. |
510
+ | [sticker.tsx](examples/sticker.tsx) | 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`. |
511
+ | [preview.tsx](examples/preview.tsx) | A bot's welcome message as its settings page shows it: the same bubble with its keyboard, nothing in it pressed or opened, the time in the zone of the profile — `preview`, `timeZone`. |
491
512
  | [narrow.tsx](examples/narrow.tsx) | At phone width bubbles take up to 85% of the chat, long words and links wrap inside, an album keeps its rows — `Message.Root`, `Message.Media`. |
492
513
 
493
514
  ## Mistakes
@@ -513,5 +534,5 @@ The list-level settings a message reads — the group chat's author header and a
513
534
  - A bot's buttons placed inside `Message.Text`, or a row of buttons of your own under a message → `Message.Actions` with `Button.Root` children: one row per part, at the message's width.
514
535
 
515
536
  ## Related
516
- - **Built from:** [Dropdown](../dropdown/COMPONENT.md) (`Message.Menu`), [ScrollContainer](../scroll-container/COMPONENT.md) (the floating panel of the reaction bar), [Gallery](../gallery/COMPONENT.md) (`Message.Media`), [Avatar](../avatar/COMPONENT.md) (`Avatar.Group` + `Avatar.Overflow` in reaction chips), [Badge](../badge/COMPONENT.md) (the «Трансляция» mark of a live location), [Thumbnail](../thumbnail/COMPONENT.md) (the map, the link preview picture, a file's preview), [Button](../button/COMPONENT.md) (retry, the transfer disk, `shape="circle"`, the buttons of `Message.Actions`), [Checkbox](../checkbox/COMPONENT.md) (`Checkbox.Indicator` in selection mode), [Spinner](../spinner/COMPONENT.md) (pending transfers and transcripts), Icon (status ticks, file glyphs, `action.forward`, `action.refresh`); `internal/messagePart` (the contract of content parts), `internal/messageList` (the contract with a chat's list), `internal/palette` (`hueOf`), `internal/Disclosure` (the reactions row, transcripts), `bubbleMorph` (every size change as one stroke), `bubbleHug` (a bubble of text as wide as its widest line), `internal/transferDisk` (the transfer of a file), `internal/mediaPill` (the meta, the author's pill), `internal/HighlightMatch` (search marks), `internal/richText` (Markdown), [VisuallyHidden](../visually-hidden/COMPONENT.md)
517
- - **See also:** [Chat](../chat/COMPONENT.md) — the conversation the messages stand in; [Gallery](../gallery/COMPONENT.md) — the album of `Message.Media`; [VideoNote](../video-note/COMPONENT.md) — the round video message; [VoicePlayer](../voice-player/COMPONENT.md) — the content of a voice message; [Composer](../composer/COMPONENT.md) — the input under the list; [Timeline](../timeline/COMPONENT.md)
537
+ - **Built from:** [Dropdown](../dropdown/COMPONENT.md) (`Message.Menu`), [ScrollContainer](../scroll-container/COMPONENT.md) (the floating panel of the reaction bar), [Gallery](../gallery/COMPONENT.md) (`Message.Media`), [Avatar](../avatar/COMPONENT.md) (`Avatar.Group` + `Avatar.Overflow` in reaction chips), [Badge](../badge/COMPONENT.md) (the «Трансляция» mark of a live location), [Thumbnail](../thumbnail/COMPONENT.md) (the map, the link preview picture, a file's preview), [Button](../button/COMPONENT.md) (retry, the transfer disk, `shape="circle"`, the buttons of `Message.Actions`), [Checkbox](../checkbox/COMPONENT.md) (`Checkbox.Indicator` in selection mode), [Spinner](../spinner/COMPONENT.md) (pending transfers and transcripts), [Skeleton](../skeleton/COMPONENT.md) (a sticker while it loads), Icon (status ticks, file glyphs, `action.forward`, `action.refresh`); `internal/messagePart` (the contract of content parts), `internal/messageList` (the contract with a chat's list), `internal/palette` (`hueOf`), `internal/Disclosure` (the reactions row, transcripts), `bubbleMorph` (every size change as one stroke), `bubbleHug` (a bubble of text as wide as its widest line), `internal/transferDisk` (the transfer of a file), `internal/mediaPill` (the meta, the author's pill), `internal/HighlightMatch` (search marks), `internal/richText` (Markdown), [VisuallyHidden](../visually-hidden/COMPONENT.md)
538
+ - **See also:** [Chat](../chat/COMPONENT.md) — the conversation the messages stand in; [Gallery](../gallery/COMPONENT.md) — the album of `Message.Media`; [VideoNote](../video-note/COMPONENT.md) — the round video message; [VoicePlayer](../voice-player/COMPONENT.md) — the content of a voice message; [Composer](../composer/COMPONENT.md) — the input under the list; [RichText](../rich-text/COMPONENT.md) — the text of `Message.Text` outside a message; [Timeline](../timeline/COMPONENT.md)
@@ -0,0 +1,28 @@
1
+ /** A bot's welcome message as its settings page shows it: the same bubble with its keyboard, nothing in it pressed or opened, the time in the zone of the profile — `preview`, `timeZone`. */
2
+ import { Button, Message } from "prime-ui-kit";
3
+
4
+ import styles from "./examples.module.css";
5
+
6
+ const SENT = new Date(Date.UTC(2026, 9, 14, 23, 30));
7
+
8
+ export default function MessagePreviewExample() {
9
+ return (
10
+ <div className={styles.thread}>
11
+ <Message.Root preview time={SENT} timeZone="Asia/Vladivostok">
12
+ <Message.Text>
13
+ {
14
+ "**Здравствуйте!** Я бот склада «Прайм»: подскажу статус заказа и пришлю счёт. Выберите, с чего начать."
15
+ }
16
+ </Message.Text>
17
+ <Message.Actions>
18
+ <Button.Root variant="soft" tone="neutral">
19
+ Статус заказа
20
+ </Button.Root>
21
+ <Button.Root variant="soft" tone="neutral">
22
+ Прислать счёт
23
+ </Button.Root>
24
+ </Message.Actions>
25
+ </Message.Root>
26
+ </div>
27
+ );
28
+ }