prime-ui-kit 0.17.0 → 0.19.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 (286) hide show
  1. package/README.md +2 -1
  2. package/dist/chunks/{chunk-PRP4B6OG.js → chunk-IVS3J7AS.js} +1 -1
  3. package/dist/chunks/{chunk-2ODXLPW3.js → chunk-QFHE5GKW.js} +1 -0
  4. package/dist/chunks/{chunk-7WWZYGRC.js → chunk-RZNGLELR.js} +4497 -3896
  5. package/dist/chunks/{chunk-A4WE3UNC.js → chunk-WYCTXD63.js} +18399 -17624
  6. package/dist/chunks/{chunk-SVFWPLNW.js → chunk-ZTZ2ML2B.js} +14 -3
  7. package/dist/color-picker.js +3 -3
  8. package/dist/components/badge/Badge.d.ts +17 -0
  9. package/dist/components/breadcrumb/Breadcrumb.d.ts +11 -2
  10. package/dist/components/button/Button.d.ts +1 -1
  11. package/dist/components/button-group/ButtonGroup.d.ts +1 -1
  12. package/dist/components/card/Card.d.ts +8 -4
  13. package/dist/components/chat/Chat.d.ts +3 -3
  14. package/dist/components/chat/MessageList.d.ts +5 -1
  15. package/dist/components/chat/groupMessages.d.ts +12 -4
  16. package/dist/components/chat-list/ChatList.d.ts +18 -9
  17. package/dist/components/chat-list/formatChatTime.d.ts +3 -3
  18. package/dist/components/checkbox/Checkbox.d.ts +6 -1
  19. package/dist/components/color-field/ColorField.d.ts +1 -1
  20. package/dist/components/color-picker/ColorPicker.d.ts +6 -1
  21. package/dist/components/color-picker/ColorPresets.d.ts +9 -1
  22. package/dist/components/crossfade/Crossfade.d.ts +1 -1
  23. package/dist/components/data-table/ColumnsMenu.d.ts +16 -20
  24. package/dist/components/data-table/DataTable.d.ts +16 -11
  25. package/dist/components/data-table/Head.d.ts +10 -1
  26. package/dist/components/data-table/Row.d.ts +7 -1
  27. package/dist/components/data-table/StateRows.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 +24 -12
  32. package/dist/components/hint/Hint.d.ts +8 -2
  33. package/dist/components/index.d.ts +7 -4
  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 +8 -9
  37. package/dist/components/list/List.d.ts +25 -6
  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/radio/Radio.d.ts +11 -2
  44. package/dist/components/rich-text/RichText.d.ts +23 -0
  45. package/dist/components/scroll-container/ScrollContainer.d.ts +1 -1
  46. package/dist/components/scroll-container/scrollGlide.d.ts +26 -0
  47. package/dist/components/scroll-container/useScrollMotion.d.ts +25 -0
  48. package/dist/components/segmented-control/SegmentedControl.d.ts +1 -1
  49. package/dist/components/select/selectContext.d.ts +7 -0
  50. package/dist/components/slider/Slider.d.ts +1 -1
  51. package/dist/components/switch/Switch.d.ts +6 -1
  52. package/dist/components/tag-select/TagSelect.d.ts +1 -1
  53. package/dist/components/textarea/Textarea.d.ts +6 -1
  54. package/dist/components/timeline/Timeline.d.ts +1 -1
  55. package/dist/icon-set.js +2 -2
  56. package/dist/index.css +1 -1
  57. package/dist/index.js +5 -3
  58. package/dist/internal/ChoiceField.d.ts +3 -1
  59. package/dist/internal/FieldFrame.d.ts +8 -2
  60. package/dist/internal/fieldCell.d.ts +7 -1
  61. package/dist/internal/formatClock.d.ts +23 -2
  62. package/dist/internal/leaveGuard.d.ts +27 -0
  63. package/dist/internal/messageList.d.ts +2 -0
  64. package/dist/internal/overlay/DialogGuard.d.ts +3 -2
  65. package/dist/internal/overlay/DialogParts.d.ts +40 -6
  66. package/dist/internal/swatch.d.ts +5 -0
  67. package/dist/internal/tokenDefaults.d.ts +1 -0
  68. package/dist/layout/index.d.ts +1 -1
  69. package/dist/layout/page/Page.d.ts +48 -15
  70. package/dist/skill/anti-slop.md +28 -0
  71. package/dist/skill/api-contract.md +14 -7
  72. package/dist/skill/cheatsheet.md +28 -9
  73. package/dist/skill/checklist.md +9 -0
  74. package/dist/skill/choosing.md +25 -12
  75. package/dist/skill/components.md +1 -0
  76. package/dist/skill/composition.md +88 -16
  77. package/dist/skill/layouts.md +6 -4
  78. package/dist/skill/reference/components/badge/COMPONENT.md +14 -1
  79. package/dist/skill/reference/components/badge/examples/examples.module.css +7 -0
  80. package/dist/skill/reference/components/badge/examples/tag-row.tsx +34 -0
  81. package/dist/skill/reference/components/breadcrumb/COMPONENT.md +9 -4
  82. package/dist/skill/reference/components/breadcrumb/examples/router.tsx +17 -0
  83. package/dist/skill/reference/components/button/COMPONENT.md +1 -1
  84. package/dist/skill/reference/components/button-group/COMPONENT.md +1 -0
  85. package/dist/skill/reference/components/card/COMPONENT.md +7 -1
  86. package/dist/skill/reference/components/card/examples/states.tsx +59 -0
  87. package/dist/skill/reference/components/chat/COMPONENT.md +4 -1
  88. package/dist/skill/reference/components/chat/examples/time-zone.tsx +83 -0
  89. package/dist/skill/reference/components/chat-list/COMPONENT.md +12 -6
  90. package/dist/skill/reference/components/chat-list/examples/links.tsx +1 -1
  91. package/dist/skill/reference/components/chat-list/examples/router.tsx +63 -0
  92. package/dist/skill/reference/components/checkbox/COMPONENT.md +1 -0
  93. package/dist/skill/reference/components/color-field/COMPONENT.md +2 -1
  94. package/dist/skill/reference/components/color-picker/COMPONENT.md +14 -5
  95. package/dist/skill/reference/components/color-picker/examples/presets-custom.tsx +31 -0
  96. package/dist/skill/reference/components/color-swatches/COMPONENT.md +1 -0
  97. package/dist/skill/reference/components/confirm-dialog/COMPONENT.md +1 -1
  98. package/dist/skill/reference/components/crossfade/COMPONENT.md +1 -1
  99. package/dist/skill/reference/components/data-table/COMPONENT.md +46 -41
  100. package/dist/skill/reference/components/data-table/examples/actions-column.tsx +154 -0
  101. package/dist/skill/reference/components/data-table/examples/columns-visibility.tsx +3 -12
  102. package/dist/skill/reference/components/data-table/examples/controlled.tsx +1 -1
  103. package/dist/skill/reference/components/data-table/examples/narrow.tsx +4 -11
  104. package/dist/skill/reference/components/data-table/examples/numeric.tsx +9 -2
  105. package/dist/skill/reference/components/data-table/examples/row-link.tsx +18 -22
  106. package/dist/skill/reference/components/data-table/examples/screen.tsx +12 -1
  107. package/dist/skill/reference/components/data-table/examples/toolbar.tsx +26 -32
  108. package/dist/skill/reference/components/datepicker/COMPONENT.md +3 -1
  109. package/dist/skill/reference/components/datepicker/examples/deadline.tsx +33 -0
  110. package/dist/skill/reference/components/digit-input/COMPONENT.md +1 -0
  111. package/dist/skill/reference/components/dnd/COMPONENT.md +4 -3
  112. package/dist/skill/reference/components/dnd/examples/examples.module.css +4 -3
  113. package/dist/skill/reference/components/dnd/examples/handle.tsx +5 -5
  114. package/dist/skill/reference/components/dnd/examples/locked.tsx +1 -1
  115. package/dist/skill/reference/components/dnd/examples/table.tsx +6 -6
  116. package/dist/skill/reference/components/drawer/COMPONENT.md +38 -9
  117. package/dist/skill/reference/components/drawer/examples/client-card.tsx +32 -8
  118. package/dist/skill/reference/components/drawer/examples/header-actions.tsx +1 -1
  119. package/dist/skill/reference/components/drawer/examples/loading.tsx +58 -0
  120. package/dist/skill/reference/components/field-list/COMPONENT.md +40 -24
  121. package/dist/skill/reference/components/field-list/examples/base-row.tsx +2 -1
  122. package/dist/skill/reference/components/field-list/examples/locked.tsx +11 -11
  123. package/dist/skill/reference/components/field-list/examples/reorder.tsx +1 -1
  124. package/dist/skill/reference/components/field-list/examples/saving.tsx +83 -0
  125. package/dist/skill/reference/components/field-list/examples/screen.module.css +1 -1
  126. package/dist/skill/reference/components/field-list/examples/screen.tsx +168 -162
  127. package/dist/skill/reference/components/field-list/examples/totals.tsx +83 -0
  128. package/dist/skill/reference/components/file-upload/COMPONENT.md +1 -0
  129. package/dist/skill/reference/components/hint/COMPONENT.md +16 -2
  130. package/dist/skill/reference/components/hint/examples/variants.tsx +48 -0
  131. package/dist/skill/reference/components/input/COMPONENT.md +39 -9
  132. package/dist/skill/reference/components/input/examples/affixes.tsx +4 -2
  133. package/dist/skill/reference/components/input/examples/dismiss.tsx +29 -0
  134. package/dist/skill/reference/components/input/examples/suggestions.tsx +26 -0
  135. package/dist/skill/reference/components/input/examples/time.tsx +24 -0
  136. package/dist/skill/reference/components/input/examples/with-select.tsx +44 -0
  137. package/dist/skill/reference/components/kanban/COMPONENT.md +12 -8
  138. package/dist/skill/reference/components/kanban/examples/columns.tsx +4 -2
  139. package/dist/skill/reference/components/kanban/examples/states.tsx +7 -5
  140. package/dist/skill/reference/components/list/COMPONENT.md +39 -13
  141. package/dist/skill/reference/components/list/examples/reorder.tsx +42 -7
  142. package/dist/skill/reference/components/list/examples/row-controls.tsx +80 -0
  143. package/dist/skill/reference/components/list/examples/with-icon.tsx +23 -2
  144. package/dist/skill/reference/components/login-form/COMPONENT.md +8 -7
  145. package/dist/skill/reference/components/login-form/examples/states.tsx +12 -14
  146. package/dist/skill/reference/components/message/COMPONENT.md +30 -9
  147. package/dist/skill/reference/components/message/examples/preview.tsx +28 -0
  148. package/dist/skill/reference/components/message/examples/sticker.tsx +35 -0
  149. package/dist/skill/reference/components/modal/COMPONENT.md +35 -10
  150. package/dist/skill/reference/components/modal/examples/long-content.tsx +37 -18
  151. package/dist/skill/reference/components/native-select/COMPONENT.md +1 -0
  152. package/dist/skill/reference/components/notification/COMPONENT.md +1 -1
  153. package/dist/skill/reference/components/radio/COMPONENT.md +2 -0
  154. package/dist/skill/reference/components/rich-text/COMPONENT.md +93 -0
  155. package/dist/skill/reference/components/rich-text/examples/overview.tsx +19 -0
  156. package/dist/skill/reference/components/scroll-container/COMPONENT.md +8 -5
  157. package/dist/skill/reference/components/segmented-control/COMPONENT.md +4 -2
  158. package/dist/skill/reference/components/segmented-control/examples/in-form.tsx +1 -1
  159. package/dist/skill/reference/components/select/COMPONENT.md +7 -3
  160. package/dist/skill/reference/components/sheet/COMPONENT.md +18 -7
  161. package/dist/skill/reference/components/slider/COMPONENT.md +1 -0
  162. package/dist/skill/reference/components/slider/examples/controlled.tsx +1 -1
  163. package/dist/skill/reference/components/switch/COMPONENT.md +1 -0
  164. package/dist/skill/reference/components/tag-select/COMPONENT.md +1 -0
  165. package/dist/skill/reference/components/textarea/COMPONENT.md +1 -0
  166. package/dist/skill/reference/components/timeline/COMPONENT.md +3 -3
  167. package/dist/skill/reference/components/timeline/examples/structure.tsx +2 -1
  168. package/dist/skill/reference/layout/app-shell/COMPONENT.md +2 -2
  169. package/dist/skill/reference/layout/bottom-nav/COMPONENT.md +1 -0
  170. package/dist/skill/reference/layout/page/COMPONENT.md +42 -20
  171. package/dist/skill/reference/layout/page/examples/examples.module.css +7 -0
  172. package/dist/skill/reference/layout/page/examples/guard.tsx +87 -0
  173. package/dist/skill/reference/layout/page/examples/loading.tsx +57 -0
  174. package/dist/skill/reference/layout/page/examples/screen.module.css +1 -1
  175. package/dist/skill/reference/layout/page/examples/screen.tsx +93 -104
  176. package/dist/skill/reference/layout/page/examples/sections.tsx +2 -15
  177. package/dist/skill/reference/layout/sidebar/COMPONENT.md +1 -0
  178. package/dist/skill/responsive.md +19 -12
  179. package/dist/skill/ux.md +5 -3
  180. package/dist/tokens/semantic.d.ts +3 -1
  181. package/dist/tokens/themes/dark.d.ts +1 -1
  182. package/package.json +2 -2
  183. package/src/components/badge/COMPONENT.md +14 -1
  184. package/src/components/badge/examples/examples.module.css +7 -0
  185. package/src/components/badge/examples/tag-row.tsx +34 -0
  186. package/src/components/breadcrumb/COMPONENT.md +9 -4
  187. package/src/components/breadcrumb/examples/router.tsx +17 -0
  188. package/src/components/button/COMPONENT.md +1 -1
  189. package/src/components/button-group/COMPONENT.md +1 -0
  190. package/src/components/card/COMPONENT.md +7 -1
  191. package/src/components/card/examples/states.tsx +59 -0
  192. package/src/components/chat/COMPONENT.md +4 -1
  193. package/src/components/chat/examples/time-zone.tsx +83 -0
  194. package/src/components/chat-list/COMPONENT.md +12 -6
  195. package/src/components/chat-list/examples/links.tsx +1 -1
  196. package/src/components/chat-list/examples/router.tsx +63 -0
  197. package/src/components/checkbox/COMPONENT.md +1 -0
  198. package/src/components/color-field/COMPONENT.md +2 -1
  199. package/src/components/color-picker/COMPONENT.md +14 -5
  200. package/src/components/color-picker/examples/presets-custom.tsx +31 -0
  201. package/src/components/color-swatches/COMPONENT.md +1 -0
  202. package/src/components/confirm-dialog/COMPONENT.md +1 -1
  203. package/src/components/crossfade/COMPONENT.md +1 -1
  204. package/src/components/data-table/COMPONENT.md +46 -41
  205. package/src/components/data-table/examples/actions-column.tsx +154 -0
  206. package/src/components/data-table/examples/columns-visibility.tsx +3 -12
  207. package/src/components/data-table/examples/controlled.tsx +1 -1
  208. package/src/components/data-table/examples/narrow.tsx +4 -11
  209. package/src/components/data-table/examples/numeric.tsx +9 -2
  210. package/src/components/data-table/examples/row-link.tsx +18 -22
  211. package/src/components/data-table/examples/screen.tsx +12 -1
  212. package/src/components/data-table/examples/toolbar.tsx +26 -32
  213. package/src/components/datepicker/COMPONENT.md +3 -1
  214. package/src/components/datepicker/examples/deadline.tsx +33 -0
  215. package/src/components/digit-input/COMPONENT.md +1 -0
  216. package/src/components/dnd/COMPONENT.md +4 -3
  217. package/src/components/dnd/examples/examples.module.css +4 -3
  218. package/src/components/dnd/examples/handle.tsx +5 -5
  219. package/src/components/dnd/examples/locked.tsx +1 -1
  220. package/src/components/dnd/examples/table.tsx +6 -6
  221. package/src/components/drawer/COMPONENT.md +38 -9
  222. package/src/components/drawer/examples/client-card.tsx +32 -8
  223. package/src/components/drawer/examples/header-actions.tsx +1 -1
  224. package/src/components/drawer/examples/loading.tsx +58 -0
  225. package/src/components/field-list/COMPONENT.md +40 -24
  226. package/src/components/field-list/examples/base-row.tsx +2 -1
  227. package/src/components/field-list/examples/locked.tsx +11 -11
  228. package/src/components/field-list/examples/reorder.tsx +1 -1
  229. package/src/components/field-list/examples/saving.tsx +83 -0
  230. package/src/components/field-list/examples/screen.module.css +1 -1
  231. package/src/components/field-list/examples/screen.tsx +168 -162
  232. package/src/components/field-list/examples/totals.tsx +83 -0
  233. package/src/components/file-upload/COMPONENT.md +1 -0
  234. package/src/components/hint/COMPONENT.md +16 -2
  235. package/src/components/hint/examples/variants.tsx +48 -0
  236. package/src/components/input/COMPONENT.md +39 -9
  237. package/src/components/input/examples/affixes.tsx +4 -2
  238. package/src/components/input/examples/dismiss.tsx +29 -0
  239. package/src/components/input/examples/suggestions.tsx +26 -0
  240. package/src/components/input/examples/time.tsx +24 -0
  241. package/src/components/input/examples/with-select.tsx +44 -0
  242. package/src/components/kanban/COMPONENT.md +12 -8
  243. package/src/components/kanban/examples/columns.tsx +4 -2
  244. package/src/components/kanban/examples/states.tsx +7 -5
  245. package/src/components/list/COMPONENT.md +39 -13
  246. package/src/components/list/examples/reorder.tsx +42 -7
  247. package/src/components/list/examples/row-controls.tsx +80 -0
  248. package/src/components/list/examples/with-icon.tsx +23 -2
  249. package/src/components/login-form/COMPONENT.md +8 -7
  250. package/src/components/login-form/examples/states.tsx +12 -14
  251. package/src/components/message/COMPONENT.md +30 -9
  252. package/src/components/message/examples/preview.tsx +28 -0
  253. package/src/components/message/examples/sticker.tsx +35 -0
  254. package/src/components/modal/COMPONENT.md +35 -10
  255. package/src/components/modal/examples/long-content.tsx +37 -18
  256. package/src/components/native-select/COMPONENT.md +1 -0
  257. package/src/components/notification/COMPONENT.md +1 -1
  258. package/src/components/radio/COMPONENT.md +2 -0
  259. package/src/components/rich-text/COMPONENT.md +93 -0
  260. package/src/components/rich-text/examples/overview.tsx +19 -0
  261. package/src/components/scroll-container/COMPONENT.md +8 -5
  262. package/src/components/segmented-control/COMPONENT.md +4 -2
  263. package/src/components/segmented-control/examples/in-form.tsx +1 -1
  264. package/src/components/select/COMPONENT.md +7 -3
  265. package/src/components/sheet/COMPONENT.md +18 -7
  266. package/src/components/slider/COMPONENT.md +1 -0
  267. package/src/components/slider/examples/controlled.tsx +1 -1
  268. package/src/components/switch/COMPONENT.md +1 -0
  269. package/src/components/tag-select/COMPONENT.md +1 -0
  270. package/src/components/textarea/COMPONENT.md +1 -0
  271. package/src/components/timeline/COMPONENT.md +3 -3
  272. package/src/components/timeline/examples/structure.tsx +2 -1
  273. package/src/layout/app-shell/COMPONENT.md +2 -2
  274. package/src/layout/bottom-nav/COMPONENT.md +1 -0
  275. package/src/layout/page/COMPONENT.md +42 -20
  276. package/src/layout/page/examples/examples.module.css +7 -0
  277. package/src/layout/page/examples/guard.tsx +87 -0
  278. package/src/layout/page/examples/loading.tsx +57 -0
  279. package/src/layout/page/examples/screen.module.css +1 -1
  280. package/src/layout/page/examples/screen.tsx +93 -104
  281. package/src/layout/page/examples/sections.tsx +2 -15
  282. package/src/layout/sidebar/COMPONENT.md +1 -0
  283. package/src/styles/theme-dark.css +1 -1
  284. package/src/styles/theme-light.css +2 -1
  285. package/dist/components/data-table/context.d.ts +0 -14
  286. package/dist/components/scroll-container/useWheelToInline.d.ts +0 -10
@@ -7,14 +7,14 @@
7
7
 
8
8
  ## When to use
9
9
  - Lists of records with several attributes to compare: orders, invoices, users, campaigns.
10
- - Data that needs sorting, paging, bulk selection or a filter toolbar.
10
+ - Data that needs sorting, paging or bulk selection.
11
11
  - Thousands of records the server sorts and pages (`source="server"` + `rowCount`): the table shows the one page the server returned.
12
12
  - Rows that open a record: a page (`getRowHref`, a real link) or a drawer in place (`onRowClick`).
13
13
  - Rows grouped by a key with a header and totals per group (`getRowGroup`).
14
14
  - Records whose order is data the user sets: pipeline stages, a price list, priorities (`onReorder`).
15
15
  - Hierarchical rows (`getRowChildren`) or rows with a detail panel (`renderExpanded`).
16
16
  - Wide numeric reports with a sticky head and first column.
17
- - Wide records on narrow screens: let people choose the columns (`DataTable.ColumnsMenu`) instead of dropping them.
17
+ - Wide records on narrow screens: let people choose the columns (`columnsMenu`) instead of dropping them.
18
18
  - A log or a register that takes the rest of the page height (`scrollHeight="fill"`).
19
19
 
20
20
  ## When not to use
@@ -30,22 +30,22 @@
30
30
  ```tsx
31
31
  import { DataTable, type DataTableColumn } from "prime-ui-kit";
32
32
  ```
33
- Exported types: `DataTableColumn<Row>`, `DataTableProps<Row>`, `DataTableSortState`, `DataTableOrder`, `DataTableGroup<Row>`, `DataTableRowClickEvent`, `DataTableColumnsMenuProps`, `DataTableLabels`.
33
+ Exported types: `DataTableColumn<Row>`, `DataTableProps<Row>`, `DataTableSortState`, `DataTableOrder`, `DataTableGroup<Row>`, `DataTableRowClickEvent`, `DataTableLabels`.
34
34
 
35
35
  ## Anatomy
36
36
  ```
37
37
  DataTable card-fill block, radius 12, clips its content
38
- ├── toolbar optional panel above the table (search, filters, bulk actions)
39
- │ └── DataTable.ColumnsMenu the column chooser: a Button and a Dropdown of check items
38
+ ├── toolbar optional panel for several table controls (bulk actions, own search + filters)
40
39
  ├── scroll viewport ScrollContainer, both axes, in a frame that holds the edge shadows
41
40
  │ └── table
42
- │ ├── thead [handle] [select all] [toggle] head cells; sortable heads hold a button
41
+ │ ├── thead [handle] [select all] [toggle] head cells [column chooser]; sortable heads hold a button
42
+ │ │ columnsMenu: an icon Button + Dropdown in the row-actions head cell, else a trailing cell
43
43
  │ └── tbody rows · sub-rows · detail rows · skeleton / empty / error row
44
44
  │ (one per group) with getRowGroup: a <th scope="rowgroup"> header row, then its rows
45
45
  │ with onReorder: a Dnd.Sortable tbody, each row led by a Dnd.Handle
46
46
  └── footer range «Показано 1–5 из 23» · Pagination · infinite-scroll status
47
47
  ```
48
- Columns are data (`DataTableColumn<Row>[]`), not child parts. The one part, `DataTable.ColumnsMenu`, goes into `toolbar` and reads the table it sits in.
48
+ Columns are data (`DataTableColumn<Row>[]`), not child parts; the table has no parts. The column chooser is the `columnsMenu` flag: it lives in the header row, never in `toolbar`.
49
49
 
50
50
  ## API
51
51
 
@@ -57,9 +57,10 @@ Generic `DataTable<Row>`; `ref` → `HTMLDivElement`. A card-fill block with an
57
57
  | Prop | Type | Default | Description |
58
58
  |---|---|---|---|
59
59
  | `columns` | `DataTableColumn<Row>[]` | — (required) | Column definitions, see `DataTableColumn<Row>`. |
60
- | `hiddenColumns` | `string[]` | — | Ids of columns that are not rendered, controlled. A column with `hideable: false` stays. `DataTable.ColumnsMenu` in `toolbar` changes it. |
60
+ | `hiddenColumns` | `string[]` | — | Ids of columns that are not rendered, controlled. A column with `hideable: false` stays. The column chooser (`columnsMenu`) changes it. |
61
61
  | `defaultHiddenColumns` | `string[]` | `[]` | Initially hidden column ids, uncontrolled. |
62
- | `onHiddenColumnsChange` | `(hiddenColumns: string[]) => void` | — | The hidden ids changed (`DataTable.ColumnsMenu`). The kit stores nothing: keep the list (local storage, the user's settings) and pass it back to restore the choice. |
62
+ | `onHiddenColumnsChange` | `(hiddenColumns: string[]) => void` | — | The hidden ids changed (`columnsMenu`). The kit stores nothing: keep the list (local storage, the user's settings) and pass it back to restore the choice. |
63
+ | `columnsMenu` | `boolean` | `false` | The column chooser at the end of the header row: in the head cell of a trailing row-actions column (`hideHeader`), else in a cell of its own; sticks with `stickyLastColumn`. Needs `showHeader`. |
63
64
  | `rows` | `Row[]` | — (required) | Data; sorted in memory when a sort is set. With `source="server"` — the page (or the loaded batches) as the server returned it. |
64
65
  | `source` | `"client" \| "server"` | `"client"` | Who sorts and pages the rows. `client`: the table sorts `rows` and slices pages. `server`: `rows` is one page, already sorted; `sort` / `page` changes are the request, `rowCount` drives Pagination. |
65
66
  | `rowCount` | `number` | `rows.length` | Total rows on the server (`source="server"`): the page count and «Показано {from}–{to} из {total}». |
@@ -78,7 +79,7 @@ Generic `DataTable<Row>`; `ref` → `HTMLDivElement`. A card-fill block with an
78
79
  | `loadingRows` | `number` | `min(pageSize, 5)` | Number of skeleton rows. |
79
80
  | `empty` | `ReactNode` | `labels.empty` | Empty-state content: a string goes into a compact EmptyPage, a node (e.g. a full `EmptyPage`) is rendered as is. |
80
81
  | `loadError` | `ReactNode` | — | Load error: replaces the body with the message in `role="alert"`. |
81
- | `toolbar` | `ReactNode` | — | Panel above the table (search, filters, bulk actions); stacks below 30rem of table width. |
82
+ | `toolbar` | `ReactNode` | — | Panel above the table for several controls of the table itself (bulk actions on the selected rows, a table-local search with filters); stacks below 30rem of table width. |
82
83
  | `selectable` | `boolean` | `false` | Leading checkbox column with «select all», Shift range, press-and-drag and Space. |
83
84
  | `selected` | `Key[]` | — | Selected row ids, controlled. |
84
85
  | `defaultSelected` | `Key[]` | `[]` | Initially selected ids, uncontrolled. |
@@ -97,6 +98,7 @@ Generic `DataTable<Row>`; `ref` → `HTMLDivElement`. A card-fill block with an
97
98
  | `scrollHeight` | `number \| string \| "fill"` | `360` with `paging="infinite"`, else none | Max height of the scroll viewport (number = px); `"fill"` — the table takes the height of its flex / grid parent (or a sized block), the rows scroll inside, infinite paging follows it. |
98
99
  | `stickyHeader` | `boolean` | `false` | The head sticks while the body scrolls (with `scrollHeight`); on screens lower than 480px it scrolls with the rows. |
99
100
  | `stickyFirstColumn` | `boolean` | `false` | The first visible column (with the selection and toggle columns) sticks while scrolling sideways; the start edge shadow falls from its end edge. |
101
+ | `stickyLastColumn` | `boolean` | `false` | The last visible column (row actions) sticks to the end edge while scrolling sideways; the end edge shadow falls from its start edge. |
100
102
  | `showHeader` | `boolean` | `true` | Render `<thead>`. |
101
103
  | `fullWidth` | `boolean` | `true` | The table spans its container; `false` sizes the table and its surface by its content (up to the container's width, then it scrolls). |
102
104
  | `rowDividers` | `boolean` | `true` | Hairlines between rows. |
@@ -117,15 +119,6 @@ Generic `DataTable<Row>`; `ref` → `HTMLDivElement`. A card-fill block with an
117
119
  | `className` | `string` | — | Class on the root `<div>`. |
118
120
  | `…rest` | `Omit<HTMLAttributes<HTMLDivElement>, "children">` | — | The other attributes of the root `<div>`. |
119
121
 
120
- ### DataTable.ColumnsMenu
121
- `ref` → `HTMLButtonElement` (the trigger). The column chooser of the table it sits in: a Button opening a Dropdown with a check item per column. Writes the table's hidden columns; throws outside a DataTable `toolbar`.
122
-
123
- | Prop | Type | Default | Description |
124
- |---|---|---|---|
125
- | `side` | `"top" \| "right" \| "bottom" \| "left"` | `"bottom"` | Side of the trigger the menu opens on. |
126
- | `align` | `"auto" \| "start" \| "center" \| "end"` | `"auto"` | Alignment to the trigger. `auto` lines the panel up with the trigger edge that has more room beyond it; `start`, `center` or `end` fix it. |
127
- | `…rest` | `Omit<ButtonHTMLAttributes<HTMLButtonElement>, "type" \| "children">` | — | `className`, `aria-label` and the other attributes of the trigger button. |
128
-
129
122
  ### Types
130
123
 
131
124
  #### `DataTableColumn<Row>`
@@ -143,10 +136,11 @@ One column of `columns`: data, not a part.
143
136
  | `align` | `"start" \| "center" \| "end"` | `"start"` (`"end"` with `numeric`) | Cell alignment; heads do not follow it. |
144
137
  | `headerAlign` | `"start" \| "center" \| "end"` | `"start"` | Head alignment; the sort icon stays at the end edge. |
145
138
  | `hideHeader` | `boolean` | `false` | `header` names the column for assistive tech only (an action column): the head cell looks empty. |
139
+ | `description` | `string` | — | What the column means: an info glyph after the header opens it as a tooltip; the header cell is described by it (`aria-describedby`). |
146
140
  | `numeric` | `boolean` | — | Tabular figures, no wrapping, end alignment unless `align` is set. |
147
141
  | `truncate` | `boolean` | — | One line with an ellipsis; width from `maxWidth` (or `width`); string values get a `title`. |
148
142
  | `grow` | `boolean` | — | Takes the free width and wraps its text; the table then fills its container. With `minWidth` it never gets narrower: below that the table scrolls instead of cells overlapping. |
149
- | `hideable` | `boolean` | `true` | The column can be hidden through `hiddenColumns` and `DataTable.ColumnsMenu`; `false` for the key column that names the row. |
143
+ | `hideable` | `boolean` | `true` | The column can be hidden through `hiddenColumns` and `columnsMenu`; `false` for the key column that names the row and for the row-actions column. |
150
144
  | `scale` | `boolean \| { min?: number; max?: number }` | — | Heatmap: each cell is shaded by its numeric value on the five-step chart scale. `true` spans the column's minimum to maximum over all rows; `{ min, max }` fixes either end. |
151
145
  | `width · minWidth · maxWidth` | `string` | — | CSS sizes of the column (`"14rem"`). |
152
146
 
@@ -222,13 +216,16 @@ Heads keep `start` whatever the cell alignment, with the sort icon at the end ed
222
216
  | `highlightRowOnHover` | `fill-subtle-active` wash on the hovered row (stronger than a zebra step, so a hovered row never takes a zebra row's color) | interactive lists | `true` |
223
217
  | `highlightColumnOnHover` | `fill-subtle-active` wash on the hovered column | comparison tables | `false` |
224
218
  | `stickyHeader` · `stickyFirstColumn` | opaque sticky head / first column with a hairline edge; on screens lower than 480px the head scrolls with the rows | long / wide tables in a `scrollHeight` window | `false` |
219
+ | `stickyLastColumn` | the last visible column sticks to the end edge, opaque in the row's fill (hover, zebra, selected, expanded), with a hairline on its start edge | a row actions column (⋯ menu, an icon Button) of a table wider than its container | `false` |
225
220
  | `stickyGroupHeaders` | group header rows stick under the head while their rows scroll | long grouped tables in a `scrollHeight` window | `false` |
226
221
  | `collapsedGroups` · `defaultCollapsedGroups` · `onCollapsedGroupsChange` | any of the three makes groups fold: a chevron toggle leads each group header, a collapsed group shows its header alone | long grouped tables where people work one group at a time; `defaultCollapsedGroups={[]}` starts with every group open | off |
227
- | column `hideable` | `false`: the column stays even when listed in `hiddenColumns`; checked and disabled in `DataTable.ColumnsMenu` | the key column that names the row | `true` |
222
+ | `columnsMenu` | an icon-only ghost Button (`view.columns`) at the end of the header row: in the head cell of a trailing row-actions column (`hideHeader`), else in a narrow cell of its own; it opens the column chooser | every table with more columns than a narrow screen holds; the default home of the chooser | `false` |
223
+ | column `hideable` | `false`: the column stays even when listed in `hiddenColumns`; checked and disabled in the column chooser | the key column that names the row, the row-actions column | `true` |
228
224
  | `showHeader` | head row shown | off only for self-explanatory key/value tables | `true` |
229
225
  | `fullWidth` | spans the container; `false` = content width | `false` for short lookup tables in wide layouts | `true` |
230
226
  | column `numeric` | tabular figures, end-aligned, no wrap | numbers, money | — |
231
227
  | column `truncate` | one line with an ellipsis and a `title` | long names in narrow columns | — |
228
+ | column `description` | an info glyph after the header; its tooltip holds the text, the header cell is described by it | a header that needs a word more («Маржа», an event type) | — |
232
229
  | column `scale` | each cell shaded by its value on the five-step chart scale, the value kept in the cell | a heatmap: counts by person × month, load by day | — |
233
230
 
234
231
  `scale: true` gives each column its own range (its minimum to maximum over all rows), so the same value can take different shades in two columns. Several columns that read as one heatmap (one column per month) share a scale when each gets the same fixed `{ min, max }` — both ends, since an open end is still the column's own: `scale: { min: 0, max: 25 }` on every month column ([heatmap.tsx](examples/heatmap.tsx)).
@@ -247,8 +244,8 @@ Heads keep `start` whatever the cell alignment, with the sort icon at the end ed
247
244
  | expanded | `expanded` / `defaultExpanded` | `data-expanded` on the parent row (one step darker); toggle `aria-expanded`, chevron turns 90° |
248
245
  | new rows | rows new in `rows` (by `getRowKey`) | `data-animate`: top-level cells drop in from above (`enterMotion`) |
249
246
  | sub-rows and detail panels | an expand / a collapse | both fold open and shut through the kit's Disclosure (`0fr ↔ 1fr`, the fade and a short slide on the same `base` clock; a detail opens on the enter curve); the row height and padding live inside the fold, so nothing is left to jump. Sub-rows: `data-fold` on the row (`open` · `closed`), every cell's content a Disclosure; a collapsed row's sub-rows stay mounted until the fold ends. Detail row: `data-state`; it unmounts after the close |
250
- | overflowing sideways | the table is wider than its viewport | `data-overflow-start` (scrolled from the start) and `data-overflow-end` (more to the end) on the root: a soft shadow over that edge, from the end edge of the sticky first column for the start; fades in and out over `fast` |
251
- | hidden columns | `hiddenColumns` / `defaultHiddenColumns`, `DataTable.ColumnsMenu` | the listed columns (except `hideable: false`) are not rendered in the head, rows, skeleton or state rows; widths are measured again; a sort by a hidden column keeps the row order |
247
+ | overflowing sideways | the table is wider than its viewport | `data-overflow-start` (scrolled from the start) and `data-overflow-end` (more to the end) on the root: a soft shadow over that edge, from the end edge of the sticky first column for the start and from the start edge of the sticky last column for the end; fades in and out over `fast` |
248
+ | hidden columns | `hiddenColumns` / `defaultHiddenColumns`, `columnsMenu` | the listed columns (except `hideable: false`) are not rendered in the head, rows, skeleton or state rows; widths are measured again; a sort by a hidden column keeps the row order |
252
249
  | opening rows | `getRowHref` / `onRowClick`, `isRowClickable` | `data-clickable` (pointer, pressed wash) on rows that open; link rows: `data-link`, an `<a data-row-link>` in every content cell; in-place rows: `tabindex="0"`. Focus (the link, or the row) rings the whole row with the hover wash |
253
250
  | grouped | `getRowGroup` | one `<tbody>` per group run on screen, opened by a `<th scope="rowgroup">` row one ladder step off the table; `data-sticky` on it with `stickyGroupHeaders` |
254
251
  | collapsed group | `collapsedGroups` / `defaultCollapsedGroups` | `data-collapsed` on the group header row, its toggle `aria-expanded="false"` with the chevron at rest; the group's `<tbody>` holds the header alone, its rows only lay out the column widths in the hidden measuring body. Its rows fold away and back like sub-rows (`data-fold`, `base`), whether a toggle or the owner changed the keys. «Select all» still takes the rows of collapsed groups; paging still counts them |
@@ -259,25 +256,26 @@ Heads keep `start` whatever the cell alignment, with the sort icon at the end ed
259
256
  | filling the parent | `scrollHeight="fill"` | `data-scroll-height="fill"` on the root; the viewport takes the free height |
260
257
  | state swap | the body moves between loading, rows, empty and error | the body fades in over `base` (opacity only, the same swap motion as [Crossfade](../crossfade/COMPONENT.md)); the head stays still; nothing moves on the first render |
261
258
 
262
- Root attributes: `data-size`, `data-row-dividers`, `data-column-dividers`, `data-sticky-header`, `data-sticky-first-column`, `data-table-width` (`fill` · `auto` · `grow`), `data-highlight-row`, `data-highlight-column`, `data-striped`, `data-loading`, `data-reorderable`, `data-selectable`, `data-expandable`, `data-dragging` (while drag-selecting), `data-overflow-start` · `data-overflow-end` (edges that hide columns), `data-scroll-height` (`fill`). Sorting and paging swap rows instantly; everything is still under `prefers-reduced-motion`.
259
+ Root attributes: `data-size`, `data-row-dividers`, `data-column-dividers`, `data-sticky-header`, `data-sticky-first-column`, `data-sticky-last-column`, `data-menu-cell` (the column chooser in a trailing cell of its own), `data-table-width` (`fill` · `auto` · `grow`), `data-highlight-row`, `data-highlight-column`, `data-striped`, `data-loading`, `data-reorderable`, `data-selectable`, `data-expandable`, `data-dragging` (while drag-selecting), `data-overflow-start` · `data-overflow-end` (edges that hide columns), `data-scroll-height` (`fill`). Sorting and paging swap rows instantly; everything is still under `prefers-reduced-motion`.
263
260
 
264
261
  ## Layout & spacing
265
262
  - The root is a layer of the surface ladder (`data-depth`, one above its host): it fills its container on `--prime-color-layer-current`, radius 12, and clips full-bleed head and rows; zebra rows and the sticky column are one ladder step off it, the head two. On a card or in a modal it is the next layer by itself — never wrap it in a Card.
263
+ - `toolbar` holds several controls of the table itself: bulk actions on the selected rows, or the search and filters of a table that is not the page's main region (a section of a record, a Drawer). One control never gets a bar: the column chooser is `columnsMenu` in the header row; the page's search, filters, period, view, figures and actions go to its top bar (`Page.Tools`, `Page.Actions`, `Page.Description`).
266
264
  - Toolbar padding `--prime-space-3` × cell padding, items `gap: --prime-space-2`; below 30rem of table width toolbar and footer stack.
267
265
  - The footer has a hairline on top: range on the left, Pagination on the right. The range shows only with more than one page or with infinite scroll.
268
- - Columns scroll sideways inside the table, never the page; pin the identifying column with `stickyFirstColumn`. A 320 px column holds the table without breaking it.
269
- - While columns are hidden past an edge, that edge shows a `--prime-space-4` shadow (`--prime-color-bg-edge-shadow`) over the content; it takes no space and follows RTL. With `stickyFirstColumn` the start shadow falls from the pinned column's end edge.
270
- - Fewer columns, less scrolling: put `DataTable.ColumnsMenu` in `toolbar` (the key column `hideable: false`). The kit stores nothing: keep `onHiddenColumnsChange`'s list where the app keeps settings and pass it back as `hiddenColumns`. Never hide columns silently by width.
271
- - `DataTable.ColumnsMenu` is an outline neutral Button one tier below the table (the `view.columns` icon, `labels.columns`); its Dropdown lists every column and ends with `labels.showAllColumns`. A `hideable: false` column stays checked and disabled, and the last visible column cannot be hidden. With `align="auto"` a trigger near the end of the screen lines up the panel's end edge and the panel grows toward the start, and the other way near the start.
266
+ - Columns scroll sideways inside the table, never the page; pin the identifying column with `stickyFirstColumn` and the row actions column with `stickyLastColumn` (it pins the last visible column, so hiding it pins the one before). A 320 px column holds the table without breaking it.
267
+ - While columns are hidden past an edge, that edge shows a `--prime-space-4` shadow (`--prime-color-bg-edge-shadow`) over the content; it takes no space and follows RTL. With `stickyFirstColumn` the start shadow falls from the pinned column's end edge; with `stickyLastColumn` the end shadow falls from the pinned column's start edge. With `stickyHeader` the pinned head cells hold both corners.
268
+ - Fewer columns, less scrolling: turn on `columnsMenu` (the key column and the row-actions column `hideable: false`). The kit stores nothing: keep `onHiddenColumnsChange`'s list where the app keeps settings and pass it back as `hiddenColumns`. Never hide columns silently by width.
269
+ - The column chooser is an icon-only ghost neutral Button one tier below the table (the `view.columns` icon; `labels.columns` is its name and its Tooltip) at the end of the header row. With a trailing row-actions column (the last visible column has `hideHeader`) it stands in that column's head cell, lined up with the ⋯ buttons under it; otherwise it takes a narrow trailing cell (the trigger plus the end padding, no column divider) that every row repeats empty. With `stickyLastColumn` it sticks: in the actions head cell with that column, or its own cell at the end edge with the last column pinned right before it. Its Dropdown opens below, lined up with the trigger's end edge, lists every column and ends with `labels.showAllColumns`; a `hideable: false` column stays checked and disabled, and the last visible column cannot be hidden.
272
270
  - Row height per `size` is public: `--prime-table-row-height-xs` · `-s` · `-m` · `-l` · `-xl` (36 · 36 · 44 · 52 · 52). A placeholder outside the table that stands in its geometry (a heatmap, a matrix skeleton) uses the same token.
273
271
  - A row that opens keeps controls out of its key cell (that cell is the link); controls in other cells stand above the row's link. Mark a custom widget with `data-row-click-ignore`.
274
272
  - Group headers: the name at the start, totals at the end (`renderGroupHeader` returns both, the kit lays them out across the visible width), head-tier text in `text-secondary`, row height = the head height. With collapsible groups the chevron toggle (the expand toggle's ghost Button) leads the header at the cell padding.
275
273
  - The empty and error content stands in a sticky box of the visible width: a wide table centres it in the viewport, and it stays there while the table scrolls sideways.
276
274
  - A trend per row: a compact [Sparkline](../sparkline/COMPONENT.md) (`layout="compact"`) in a cell fits the row height; its pointer and keys never open the row.
277
- - Long data needs no slicing: past 100 rows a body in a bounded viewport (`scrollHeight`, `"fill"`, `paging="infinite"`) renders only the rows around the view; spacer rows keep the scrollbar exact, the focused row stays rendered, rows carry `aria-rowindex` and the table `aria-rowcount`. Grouped (`getRowGroup`), reorderable (`onReorder`) and `renderExpanded` bodies, and a table the page scrolls, render every row. The browser's find-in-page sees only rendered rows: give a long table a search in `toolbar`.
275
+ - Long data needs no slicing: past 100 rows a body in a bounded viewport (`scrollHeight`, `"fill"`, `paging="infinite"`) renders only the rows around the view; spacer rows keep the scrollbar exact, the focused row stays rendered, rows carry `aria-rowindex` and the table `aria-rowcount`. Grouped (`getRowGroup`), reorderable (`onReorder`) and `renderExpanded` bodies, and a table the page scrolls, render every row. The browser's find-in-page sees only rendered rows: give a long table a search (the page's `SmartFilter`).
278
276
  - `scrollHeight="fill"` needs a parent with a height: a flex or grid column with `min-height: 0`, `Page.Root fill` in an `AppShell.Root fillViewport`, or a sized pane.
279
277
  - The sticky head stops sticking on screens lower than 480px (landscape phones), so it never takes a large share of the height.
280
- - Cell content: text, two-line text (title + `caption`), an Avatar with text, a Badge, or a control one tier down (`s` in an `m` table). Toolbar controls use `s` in an `m` table.
278
+ - Cell content: text, two-line text (title + `caption`), an Avatar with text, a Badge, or a control one tier down (`s` in an `m` table). Toolbar controls and the column chooser use `s` in an `m` table.
281
279
  - Column widths: `width` / `minWidth` / `maxWidth` strings; never size cells with custom CSS.
282
280
  - Sub-rows indent by `--dt-indent` per level (avatar of the tier + gap); override it on the root for other leading content.
283
281
 
@@ -288,7 +286,7 @@ Root attributes: `data-size`, `data-row-dividers`, `data-column-dividers`, `data
288
286
 
289
287
  | Key | Action |
290
288
  |---|---|
291
- | `Tab` | Moves through the toolbar (`DataTable.ColumnsMenu`), sort buttons, row handles, checkboxes, expand toggles, row links, rows that open in place and Pagination. |
289
+ | `Tab` | Moves through the toolbar, sort buttons, the column chooser (`columnsMenu`), row handles, checkboxes, expand toggles, row links, rows that open in place and Pagination. |
292
290
  | `Enter` · `Space` | Sorts by the column, toggles the row or the group, or opens the focused row (`onRowClick`); Enter on a row link follows it. |
293
291
  | `Space` | Toggles the focused row checkbox. |
294
292
  | `Shift + Space` | Selects the range from the last toggled row. |
@@ -302,12 +300,13 @@ Root attributes: `data-size`, `data-row-dividers`, `data-column-dividers`, `data
302
300
  - A link row has one link for assistive tech: the `<a>` in the key cell, named by its text. Its copies over the other cells are `aria-hidden` and `tabindex="-1"`, so the pointer can use the whole row. An in-place row is focusable itself (`tabindex="0"`) and reads as its cells. Either way the focused row shows a ring around all its cells.
303
301
  - A row never opens from a control inside it (links, buttons, fields, `label`, `summary`, ARIA widgets, `data-row-click-ignore`), from a text selection, or from a React event that bubbled out of a portal (a ⋯ menu item).
304
302
  - A group header is a `<th scope="rowgroup">` across every column, first in its own `<tbody>`.
305
- - `DataTable.ColumnsMenu` is a menu button: `menuitemcheckbox` items with `aria-checked`; the key column is `aria-disabled`.
303
+ - The column chooser (`columnsMenu`) is a menu button named by `labels.columns` (its tooltip says the same): `menuitemcheckbox` items with `aria-checked`; the key column is `aria-disabled`. In the row-actions head cell the column keeps its own name (`aria-labelledby`); its own trailing cell is a `<td>`.
306
304
  - Row checkboxes are named by `labels.selectRow` with `{label}` from `getRowLabel` (pass it so the names are unique); the head checkbox by `labels.selectAll`, `indeterminate` on a partial selection.
307
305
  - After a selection change a polite live region announces `labels.selectedCount`; selected rows carry `aria-selected`.
308
306
  - A row handle is a button named by `labels.reorderRow` with `aria-keyshortcuts`; a pick-up, a drop and a keyboard move are announced in a polite live region («Договор: позиция 2 из 6»). While its move is saved the row is `aria-busy`; while the table is sorted the handles are disabled and a tooltip gives `labels.reorderSorted`.
309
307
  - The expand toggle is a button with `aria-expanded`, `aria-controls` (detail row or sub-rows) and `labels.expand` / `labels.collapse`.
310
308
  - A group toggle (collapsible groups) is a button in the group header with `aria-expanded`, `aria-controls` (the group's rows, while open; not on reorderable rows, which carry no id) and `labels.expandGroup` / `labels.collapseGroup` with `{group}`.
309
+ - A column `description` describes its header cell (`aria-describedby`); its tooltip opens from the sort button, or from the info glyph (a tab stop named `labels.columnInfo`) on a plain header.
311
310
  - Loading sets `aria-busy` and a `labels.loading` status; the error is `role="alert"`; the default empty state is `role="status"`.
312
311
 
313
312
  ### Labels
@@ -325,44 +324,47 @@ Root attributes: `data-size`, `data-row-dividers`, `data-column-dividers`, `data
325
324
  | `selectedCount` | `"Выбрано: {count}"` | Polite announcement after the selection changes. |
326
325
  | `expand` | `"Развернуть строку {label}"` | Name of the toggle of a collapsed row. |
327
326
  | `collapse` | `"Свернуть строку {label}"` | Name of the toggle of an expanded row. |
328
- | `columns` | `"Колонки"` | Text of the `DataTable.ColumnsMenu` trigger; `{shown}` and `{total}` are column counts. |
329
- | `showAllColumns` | `"Показать все"` | The `DataTable.ColumnsMenu` item that shows every column again. |
327
+ | `columns` | `"Колонки"` | Name and tooltip of the column chooser trigger (`columnsMenu`); `{shown}` and `{total}` are column counts. |
328
+ | `showAllColumns` | `"Показать все"` | The column chooser item that shows every column again. |
330
329
  | `reorderRow` | `"Переместить строку {label}"` | `aria-label` of a row's drag handle (`onReorder`); `{label}` is `getRowLabel(row)`. |
331
330
  | `reorderSorted` | `"Порядок задан сортировкой. Сбросьте её, чтобы перемещать строки"` | Tooltip of the disabled handles while the table is sorted by a column. |
332
331
  | `expandGroup` | `"Развернуть группу {group}"` | Name of the toggle of a collapsed group; `{group}` is the group key. |
333
332
  | `collapseGroup` | `"Свернуть группу {group}"` | Name of the toggle of an expanded group; `{group}` is the group key. |
333
+ | `columnInfo` | `"Пояснение"` | Name of the info glyph of a column with a `description`; the tooltip holds the text. |
334
334
 
335
335
  ## Examples
336
336
  | Example | Shows |
337
337
  |---|---|
338
338
  | [overview.tsx](examples/overview.tsx) | Recent orders: sortable columns, a status Badge, numeric sums and five rows per page — `columns`, `getRowKey`, `pageSize`. |
339
339
  | [sizes.tsx](examples/sizes.tsx) | Every density: rows from 36 to 52 px, the head at the control height of the tier — `size`. |
340
- | [numeric.tsx](examples/numeric.tsx) | An inventory report: number columns align to the end in tabular figures, a long name stays on one line with a title, formatted cells sort by their raw number and article numbers in natural order — `numeric`, `truncate`, `maxWidth`, `sortAccessor`, `sortComparator`. |
340
+ | [numeric.tsx](examples/numeric.tsx) | An inventory report: number columns align to the end in tabular figures, a long name stays on one line with a title, formatted cells sort by their raw number article numbers in natural order and a header that needs a word more explains itself in a tooltip — `numeric`, `truncate`, `maxWidth`, `sortAccessor`, `sortComparator`, `description`. |
341
341
  | [heatmap.tsx](examples/heatmap.tsx) | Deals closed per manager and month as a heatmap: each count shades its cell on the chart scale and stays readable in it — `scale`, `numeric`. |
342
342
  | [trend.tsx](examples/trend.tsx) | Clients with revenue by month as a compact Sparkline in a cell of each row, next to the half-year total — `cell`, `width`. |
343
343
  | [content-width.tsx](examples/content-width.tsx) | A short lookup table sized by its content with a centered column, and a `grow` column that takes the free width and wraps — `fullWidth`, `align`, `grow`. |
344
344
  | [appearance.tsx](examples/appearance.tsx) | Row styling: zebra rows without lines, a column wash under the pointer, a headless key/value list — `striped`, `rowDividers`, `highlightColumnOnHover`, `columnDividers`, `showHeader`. |
345
- | [toolbar.tsx](examples/toolbar.tsx) | A campaign list with search, a status filter and export above the table; the empty text when nothing matches — `toolbar`, `empty`. |
345
+ | [toolbar.tsx](examples/toolbar.tsx) | A campaign table with its own search and status filter above it — two table-scoped controls; the empty text when nothing matches — `toolbar`, `empty`. |
346
346
  | [selection.tsx](examples/selection.tsx) | Team members with checkboxes: Shift+click range, press-and-drag, «select all» and bulk actions in the toolbar — `selectable`, `selected`, `onSelectedChange`, `getRowLabel`. |
347
347
  | [nested-rows.tsx](examples/nested-rows.tsx) | Partners with their expense lines: sub-rows indented under the parent's name, a chevron toggle, together with selection and sorting — `getRowChildren`, `expanded`, `onExpandedChange`. |
348
348
  | [detail-panel.tsx](examples/detail-panel.tsx) | Order details in a full-width row under an expanded order, aligned with the first content column; a cancelled order has nothing to show and gets no toggle — `renderExpanded`, `defaultExpanded`, `isRowExpandable`. |
349
349
  | [sticky.tsx](examples/sticky.tsx) | Monthly sales by region in a 280 px window: the head and the region column stay while scrolling both ways — `stickyHeader`, `stickyFirstColumn`, `scrollHeight`. |
350
+ | [actions-column.tsx](examples/actions-column.tsx) | Orders wider than the table: the order number stays at the start, the ⋯ row actions at the end with the column chooser in their header cell, and the columns between scroll sideways — `stickyFirstColumn`, `stickyLastColumn`, `columnsMenu`. |
350
351
  | [row-link.tsx](examples/row-link.tsx) | Invoices whose rows are links: ⌘-click or a middle click opens a new tab, a plain click routes inside the app, the totals row and the ⋯ menu never open a row — `getRowHref`, `onRowClick`, `isRowClickable`. |
351
352
  | [row-open.tsx](examples/row-open.tsx) | Deals that open in a side panel: a click, or Enter and Space on the focused row; the panel keeps the last deal while it slides away — `onRowClick`. |
352
353
  | [reorder.tsx](examples/reorder.tsx) | Pipeline stages put in order by the handle or Alt + ↑ / ↓; each move is saved with a spinner in its handle, and sorting by a column turns the handles off — `onReorder`, `getRowLabel`. |
353
354
  | [groups.tsx](examples/groups.tsx) | Payments grouped by month with the month's total in its header row; headers stay on top while their rows scroll, a past month folds away — `getRowGroup`, `renderGroupHeader`, `stickyGroupHeaders`, `defaultCollapsedGroups`. |
354
- | [columns-visibility.tsx](examples/columns-visibility.tsx) | Orders with the column chooser in the toolbar; the choice outlives a reload in local storage, the order number always stays — `DataTable.ColumnsMenu`, `hiddenColumns`, `onHiddenColumnsChange`, `hideable`. |
355
+ | [columns-visibility.tsx](examples/columns-visibility.tsx) | Orders with the column chooser at the end of the header row; the choice outlives a reload in local storage, the order number always stays — `columnsMenu`, `hiddenColumns`, `onHiddenColumnsChange`, `hideable`. |
355
356
  | [infinite-scroll.tsx](examples/infinite-scroll.tsx) | An audit log that reveals loaded rows in batches and then asks the server for more — `paging`, `infiniteBatchSize`, `hasMore`, `loadingMore`, `onLoadMore`. |
356
357
  | [server.tsx](examples/server.tsx) | A CRM deal list the server sorts, pages and searches; a new search returns to page 1 — `source`, `rowCount`, `sort`, `page`, `loading`. |
357
358
  | [fill-height.tsx](examples/fill-height.tsx) | An audit log that fills the height of its panel and loads older entries while scrolling; the status shows while the request is pending — `scrollHeight`, `paging`, `onLoadMore`. |
358
359
  | [states.tsx](examples/states.tsx) | Loading skeleton, an empty period and a load error with a retry: the head stays, only the body changes — `loading`, `loadingRows`, `empty`, `loadError`. |
359
360
  | [controlled.tsx](examples/controlled.tsx) | Sort, page and the column choice owned by the parent (a URL or a store): a header click goes asc → desc → none, a new sort returns to page 1 — `sort`, `onSortChange`, `page`, `onPageChange`, `hiddenColumns`, `onHiddenColumnsChange`. |
360
- | [narrow.tsx](examples/narrow.tsx) | A 320 px support queue: columns scroll inside the table with the first one pinned, the toolbar and footer reflow and the pager turns compact — `stickyFirstColumn`, `size`. |
361
+ | [narrow.tsx](examples/narrow.tsx) | A 320 px support queue: columns scroll inside the table with the first one pinned, the column chooser stays at the end of the header row, the footer reflows and the pager turns compact — `stickyFirstColumn`, `columnsMenu`, `size`. |
361
362
  | [screen.tsx](examples/screen.tsx) | A list page: the title, a line of figures, search, filters and the one primary action in its top bar, a DataTable of invoices with statuses, row actions, pages and a filtered empty state — `empty`, `pageSize`, `stickyFirstColumn`. |
362
363
 
363
364
  ## Mistakes
364
365
  - No `getRowKey` with `selectable`, expansion or sorting → selection follows positions, not records.
365
366
  - Numbers in a plain column → set `numeric` (alignment and tabular figures).
367
+ - An explanation squeezed into the header text, or a hand-made icon with a Tooltip inside `header` → `description`.
366
368
  - A custom «Ничего не найдено» row inside `rows` → use `empty`.
367
369
  - A spinner instead of rows → use `loading` (the skeleton keeps the head and the layout).
368
370
  - Wrapping the table in a Card for a border → the table is already a bounded block.
@@ -371,10 +373,13 @@ Root attributes: `data-size`, `data-row-dividers`, `data-column-dividers`, `data
371
373
  - Applying the new order before the server answers and undoing it by hand → return the request's promise from `onReorder` and apply after it resolves: the table keeps the row in place meanwhile and moves it back on a rejection.
372
374
  - A long table in a `scrollHeight` window without `stickyHeader` → the head scrolls away.
373
375
  - `paging="none"` for hundreds of rows → use `pages` or `infinite`.
374
- - Dropping columns below a breakpoint → people lose data without knowing it; offer `DataTable.ColumnsMenu`.
375
- - A hand-built column chooser from Dropdown items → `DataTable.ColumnsMenu` (key column, last visible column, «Показать все» built in).
376
+ - Dropping columns below a breakpoint → people lose data without knowing it; turn on `columnsMenu`.
377
+ - A hand-built column chooser from Dropdown items → `columnsMenu` (key column, last visible column, «Показать все» built in).
378
+ - A toolbar with one button (the column chooser, «Экспорт», «Создать») → a whole bar above the table for one control; the chooser is `columnsMenu` in the header row, the page's actions go to `Page.Actions`.
379
+ - The page's search, filters, period, view or figures in `toolbar` → they belong to the page's top bar (`Page.Tools`, `Page.Actions`, `Page.Description`); `toolbar` keeps several controls of the table itself (bulk actions, the search and filters of a table in a section or a Drawer).
376
380
  - Letting the key column be hidden → set `hideable: false` on it, so every row keeps its name.
377
381
  - Wrapping the table in an `overflow-x` box of your own → it already scrolls inside and shows the edge shadows.
382
+ - A row actions column that scrolls out of view in a wide table, or a hand-made `position: sticky` on it → make it the last column and set `stickyLastColumn`.
378
383
  - `onRowClick` with `navigate()` for a record page → use `getRowHref` (⌘-click, new tab, status-bar URL) and route the plain click in `onRowClick` with `event.preventDefault()`.
379
384
  - Checking `event.target` in `onRowClick` to skip a button or a menu in the row → the table already ignores controls and portals; mark a custom widget with `data-row-click-ignore`.
380
385
  - A totals row that opens like a record → `isRowClickable`.
@@ -388,5 +393,5 @@ Root attributes: `data-size`, `data-row-dividers`, `data-column-dividers`, `data
388
393
  - A new search that keeps the current page → set `page` to 1 together with the search.
389
394
 
390
395
  ## Related
391
- - **Built from:** [Checkbox](../checkbox/COMPONENT.md), [Button](../button/COMPONENT.md), [Dropdown](../dropdown/COMPONENT.md) (`DataTable.ColumnsMenu`), [Pagination](../pagination/COMPONENT.md), [ScrollContainer](../scroll-container/COMPONENT.md), [EmptyPage](../empty-page/COMPONENT.md), [VisuallyHidden](../visually-hidden/COMPONENT.md) (loading status, selection announcement), [Skeleton](../skeleton/COMPONENT.md) (loading rows, in the table tier), [Dnd](../dnd/COMPONENT.md) (`onReorder`: `Dnd.Sortable as="tbody"`, `Dnd.Handle`), [Tooltip](../tooltip/COMPONENT.md) (handle hint), Icon (sort arrows, the expand chevron, the `DataTable.ColumnsMenu` trigger); `useVirtualRows` (the window of a long body)
396
+ - **Built from:** [Checkbox](../checkbox/COMPONENT.md), [Button](../button/COMPONENT.md), [Dropdown](../dropdown/COMPONENT.md) (the column chooser), [Pagination](../pagination/COMPONENT.md), [ScrollContainer](../scroll-container/COMPONENT.md), [EmptyPage](../empty-page/COMPONENT.md), [VisuallyHidden](../visually-hidden/COMPONENT.md) (loading status, selection announcement), [Skeleton](../skeleton/COMPONENT.md) (loading rows, in the table tier), [Dnd](../dnd/COMPONENT.md) (`onReorder`: `Dnd.Sortable as="tbody"`, `Dnd.Handle`), [Tooltip](../tooltip/COMPONENT.md) (handle hint, a column `description`, the column chooser), Icon (sort arrows, the info glyph of a column `description`, the expand chevron, the column chooser trigger); `useVirtualRows` (the window of a long body)
392
397
  - **See also:** [Sparkline](../sparkline/COMPONENT.md) (`layout="compact"` in a cell), [SmartFilter](../smart-filter/COMPONENT.md), [Page](../../layout/page/COMPONENT.md) (`Page.Tools`, `Page.Chips`), [Gantt](../gantt/COMPONENT.md), [Kanban](../kanban/COMPONENT.md), [Badge](../badge/COMPONENT.md), [Avatar](../avatar/COMPONENT.md), [Card](../card/COMPONENT.md)
@@ -0,0 +1,154 @@
1
+ /** Orders wider than the table: the order number stays at the start, the ⋯ row actions at the end with the column chooser in their header cell, and the columns between scroll sideways — `stickyFirstColumn`, `stickyLastColumn`, `columnsMenu`. */
2
+ import { Badge, Button, DataTable, type DataTableColumn, Dropdown, Icon } from "prime-ui-kit";
3
+
4
+ type Order = {
5
+ id: string;
6
+ client: string;
7
+ manager: string;
8
+ city: string;
9
+ address: string;
10
+ status: "new" | "paid" | "shipped" | "cancelled";
11
+ date: string;
12
+ items: number;
13
+ amount: number;
14
+ };
15
+
16
+ const ORDERS: Order[] = [
17
+ {
18
+ id: "З-2041",
19
+ client: "ООО «Северный ветер»",
20
+ manager: "Анна Смирнова",
21
+ city: "Санкт-Петербург",
22
+ address: "Лиговский пр., 50, склад 3",
23
+ status: "paid",
24
+ date: "02.10.2026",
25
+ items: 14,
26
+ amount: 184_500,
27
+ },
28
+ {
29
+ id: "З-2042",
30
+ client: "ИП Козлов",
31
+ manager: "Игорь Петров",
32
+ city: "Казань",
33
+ address: "ул. Петербургская, 12, офис 4",
34
+ status: "new",
35
+ date: "03.10.2026",
36
+ items: 3,
37
+ amount: 27_900,
38
+ },
39
+ {
40
+ id: "З-2043",
41
+ client: "АО «Технопарк»",
42
+ manager: "Анна Смирнова",
43
+ city: "Новосибирск",
44
+ address: "ул. Станционная, 38, терминал Б",
45
+ status: "shipped",
46
+ date: "05.10.2026",
47
+ items: 42,
48
+ amount: 612_000,
49
+ },
50
+ {
51
+ id: "З-2044",
52
+ client: "ООО «Лента Логистик»",
53
+ manager: "Мария Орлова",
54
+ city: "Екатеринбург",
55
+ address: "ул. Монтажников, 4, ворота 2",
56
+ status: "cancelled",
57
+ date: "06.10.2026",
58
+ items: 8,
59
+ amount: 96_300,
60
+ },
61
+ {
62
+ id: "З-2045",
63
+ client: "ООО «Гранит»",
64
+ manager: "Игорь Петров",
65
+ city: "Москва",
66
+ address: "Варшавское ш., 125, стр. 1",
67
+ status: "paid",
68
+ date: "08.10.2026",
69
+ items: 21,
70
+ amount: 275_400,
71
+ },
72
+ ];
73
+
74
+ const STATUS = {
75
+ new: { label: "Новый", tone: "info" },
76
+ paid: { label: "Оплачен", tone: "success" },
77
+ shipped: { label: "Отгружен", tone: "neutral" },
78
+ cancelled: { label: "Отменён", tone: "danger" },
79
+ } as const;
80
+
81
+ const RUB = new Intl.NumberFormat("ru-RU", {
82
+ style: "currency",
83
+ currency: "RUB",
84
+ maximumFractionDigits: 0,
85
+ });
86
+
87
+ const COLUMNS: DataTableColumn<Order>[] = [
88
+ { id: "id", header: "Заказ", accessor: "id", hideable: false },
89
+ { id: "client", header: "Клиент", accessor: "client", minWidth: "14rem" },
90
+ { id: "manager", header: "Менеджер", accessor: "manager", minWidth: "10rem" },
91
+ { id: "city", header: "Город", accessor: "city", minWidth: "10rem" },
92
+ { id: "address", header: "Адрес доставки", accessor: "address", minWidth: "18rem" },
93
+ {
94
+ id: "status",
95
+ header: "Статус",
96
+ cell: (row) => (
97
+ <Badge.Root tone={STATUS[row.status].tone}>{STATUS[row.status].label}</Badge.Root>
98
+ ),
99
+ },
100
+ { id: "date", header: "Дата", accessor: "date", numeric: true, headerAlign: "end" },
101
+ { id: "items", header: "Позиций", accessor: "items", numeric: true, headerAlign: "end" },
102
+ {
103
+ id: "amount",
104
+ header: "Сумма",
105
+ accessor: "amount",
106
+ numeric: true,
107
+ headerAlign: "end",
108
+ cell: (row) => RUB.format(row.amount),
109
+ },
110
+ {
111
+ id: "actions",
112
+ header: "Действия",
113
+ hideHeader: true,
114
+ hideable: false,
115
+ align: "end",
116
+ cell: (row) => (
117
+ <Dropdown.Root>
118
+ <Dropdown.Trigger>
119
+ <Button.Root
120
+ variant="ghost"
121
+ tone="neutral"
122
+ size="s"
123
+ aria-label={`Действия с заказом ${row.id}`}
124
+ >
125
+ <Button.Icon>
126
+ <Icon name="action.more" />
127
+ </Button.Icon>
128
+ </Button.Root>
129
+ </Dropdown.Trigger>
130
+ <Dropdown.Content>
131
+ <Dropdown.Item>Открыть</Dropdown.Item>
132
+ <Dropdown.Item>Скачать счёт</Dropdown.Item>
133
+ <Dropdown.Item>Повторить заказ</Dropdown.Item>
134
+ <Dropdown.Separator />
135
+ <Dropdown.Item tone="danger">Отменить</Dropdown.Item>
136
+ </Dropdown.Content>
137
+ </Dropdown.Root>
138
+ ),
139
+ },
140
+ ];
141
+
142
+ export default function DataTableActionsColumnExample() {
143
+ return (
144
+ <DataTable
145
+ columns={COLUMNS}
146
+ rows={ORDERS}
147
+ getRowKey={(row) => row.id}
148
+ paging="none"
149
+ stickyFirstColumn
150
+ stickyLastColumn
151
+ columnsMenu
152
+ />
153
+ );
154
+ }
@@ -1,9 +1,7 @@
1
- /** Orders with the column chooser in the toolbar; the choice outlives a reload in local storage, the order number always stays — `DataTable.ColumnsMenu`, `hiddenColumns`, `onHiddenColumnsChange`, `hideable`. */
2
- import { Badge, DataTable, type DataTableColumn, Typography } from "prime-ui-kit";
1
+ /** Orders with the column chooser at the end of the header row; the choice outlives a reload in local storage, the order number always stays — `columnsMenu`, `hiddenColumns`, `onHiddenColumnsChange`, `hideable`. */
2
+ import { Badge, DataTable, type DataTableColumn } from "prime-ui-kit";
3
3
  import * as React from "react";
4
4
 
5
- import styles from "./examples.module.css";
6
-
7
5
  type Status = "paid" | "shipped" | "waiting";
8
6
  type Order = {
9
7
  id: string;
@@ -138,14 +136,7 @@ export default function DataTableColumnsVisibilityExample() {
138
136
  rows={ORDERS}
139
137
  getRowKey={(row) => row.id}
140
138
  stickyFirstColumn
141
- toolbar={
142
- <div className={styles.toolbar}>
143
- <Typography as="span" variant="body-s" tone="secondary">
144
- Заказы за неделю: {ORDERS.length}
145
- </Typography>
146
- <DataTable.ColumnsMenu />
147
- </div>
148
- }
139
+ columnsMenu
149
140
  />
150
141
  );
151
142
  }
@@ -52,7 +52,7 @@ export default function DataTableControlledExample() {
52
52
  columns={COLUMNS}
53
53
  rows={ORDERS}
54
54
  getRowKey={(row) => row.id}
55
- toolbar={<DataTable.ColumnsMenu />}
55
+ columnsMenu
56
56
  hiddenColumns={hiddenColumns}
57
57
  onHiddenColumnsChange={setHiddenColumns}
58
58
  sort={sort}
@@ -1,5 +1,5 @@
1
- /** A 320 px support queue: columns scroll inside the table with the first one pinned, the toolbar and footer reflow and the pager turns compact — `stickyFirstColumn`, `size`. */
2
- import { Badge, Button, DataTable, type DataTableColumn, Typography } from "prime-ui-kit";
1
+ /** A 320 px support queue: columns scroll inside the table with the first one pinned, the column chooser stays at the end of the header row, the footer reflows and the pager turns compact — `stickyFirstColumn`, `columnsMenu`, `size`. */
2
+ import { Badge, DataTable, type DataTableColumn } from "prime-ui-kit";
3
3
 
4
4
  import styles from "./examples.module.css";
5
5
 
@@ -15,7 +15,7 @@ const TICKETS: Ticket[] = Array.from({ length: 36 }, (_, i) => ({
15
15
  }));
16
16
 
17
17
  const COLUMNS: DataTableColumn<Ticket>[] = [
18
- { id: "id", header: "Тикет", accessor: "id" },
18
+ { id: "id", header: "Тикет", accessor: "id", hideable: false },
19
19
  { id: "subject", header: "Тема", accessor: "subject", truncate: true, maxWidth: "10rem" },
20
20
  {
21
21
  id: "priority",
@@ -39,15 +39,8 @@ export default function DataTableNarrowExample() {
39
39
  rows={TICKETS}
40
40
  getRowKey={(row) => row.id}
41
41
  stickyFirstColumn
42
+ columnsMenu
42
43
  pageSize={5}
43
- toolbar={
44
- <div className={styles.toolbar}>
45
- <Typography as="span" variant="body-s" tone="secondary">
46
- Открытые: {TICKETS.length}
47
- </Typography>
48
- <Button.Root size="xs">Новый тикет</Button.Root>
49
- </div>
50
- }
51
44
  />
52
45
  </div>
53
46
  );
@@ -1,4 +1,4 @@
1
- /** An inventory report: number columns align to the end in tabular figures, a long name stays on one line with a title, formatted cells sort by their raw number and article numbers in natural order — `numeric`, `truncate`, `maxWidth`, `sortAccessor`, `sortComparator`. */
1
+ /** An inventory report: number columns align to the end in tabular figures, a long name stays on one line with a title, formatted cells sort by their raw number article numbers in natural order and a header that needs a word more explains itself in a tooltip — `numeric`, `truncate`, `maxWidth`, `sortAccessor`, `sortComparator`, `description`. */
2
2
  import { DataTable, type DataTableColumn } from "prime-ui-kit";
3
3
 
4
4
  type Sku = {
@@ -57,10 +57,17 @@ const COLUMNS: DataTableColumn<Sku>[] = [
57
57
  cell: (row) => INT.format(row.stock),
58
58
  },
59
59
  { id: "price", header: "Цена, ₽", numeric: true, cell: (row) => INT.format(row.price) },
60
- { id: "sold", header: "Продано", numeric: true, cell: (row) => INT.format(row.sold) },
60
+ {
61
+ id: "sold",
62
+ header: "Продано",
63
+ description: "Штук за последние 30 дней, без возвратов",
64
+ numeric: true,
65
+ cell: (row) => INT.format(row.sold),
66
+ },
61
67
  {
62
68
  id: "margin",
63
69
  header: "Маржа",
70
+ description: "Доля прибыли в цене после закупки и доставки",
64
71
  numeric: true,
65
72
  sortable: true,
66
73
  sortAccessor: (row) => row.margin,
@@ -2,8 +2,6 @@
2
2
  import { Button, DataTable, type DataTableColumn, Dropdown, Icon, Typography } from "prime-ui-kit";
3
3
  import * as React from "react";
4
4
 
5
- import styles from "./examples.module.css";
6
-
7
5
  type Invoice = { id: string; client: string; due: string; amount: number; total?: boolean };
8
6
 
9
7
  const INVOICES: Invoice[] = [
@@ -77,25 +75,23 @@ export default function DataTableRowLinkExample() {
77
75
  ];
78
76
 
79
77
  return (
80
- <DataTable
81
- columns={columns}
82
- rows={ROWS}
83
- getRowKey={(row) => row.id}
84
- paging="none"
85
- getRowHref={(row) => `/invoices/${row.id}`}
86
- isRowClickable={(row) => !row.total}
87
- onRowClick={(row, _index, event) => {
88
- // A client-side router goes here (navigate(href)); the page itself never reloads.
89
- event.preventDefault();
90
- setStatus(`Открыт ${row.id} · ${row.client}`);
91
- }}
92
- toolbar={
93
- <div className={styles.toolbar}>
94
- <Typography as="span" variant="body-s" tone="secondary" aria-live="polite">
95
- {status}
96
- </Typography>
97
- </div>
98
- }
99
- />
78
+ <>
79
+ <DataTable
80
+ columns={columns}
81
+ rows={ROWS}
82
+ getRowKey={(row) => row.id}
83
+ paging="none"
84
+ getRowHref={(row) => `/invoices/${row.id}`}
85
+ isRowClickable={(row) => !row.total}
86
+ onRowClick={(row, _index, event) => {
87
+ // A client-side router goes here (navigate(href)); the page itself never reloads.
88
+ event.preventDefault();
89
+ setStatus(`Открыт ${row.id} · ${row.client}`);
90
+ }}
91
+ />
92
+ <Typography as="span" variant="body-s" tone="secondary" aria-live="polite">
93
+ {status}
94
+ </Typography>
95
+ </>
100
96
  );
101
97
  }