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
@@ -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
  }
@@ -177,7 +177,15 @@ const initials = (name: string) =>
177
177
  .toUpperCase();
178
178
 
179
179
  const COLUMNS: DataTableColumn<Invoice>[] = [
180
- { id: "id", header: "Счёт", accessor: "id", sortable: true, numeric: true, align: "start" },
180
+ {
181
+ id: "id",
182
+ header: "Счёт",
183
+ accessor: "id",
184
+ sortable: true,
185
+ numeric: true,
186
+ align: "start",
187
+ hideable: false,
188
+ },
181
189
  {
182
190
  id: "client",
183
191
  header: "Клиент",
@@ -230,6 +238,7 @@ const COLUMNS: DataTableColumn<Invoice>[] = [
230
238
  id: "actions",
231
239
  header: "Действия",
232
240
  hideHeader: true,
241
+ hideable: false,
233
242
  width: "3.5rem",
234
243
  align: "end",
235
244
  cell: (row) => (
@@ -320,6 +329,8 @@ export default function DataTableScreenExample() {
320
329
  getRowLabel={(row) => `Счёт ${row.id}`}
321
330
  pageSize={6}
322
331
  stickyFirstColumn
332
+ stickyLastColumn
333
+ columnsMenu
323
334
  defaultSort={{ columnId: "due", order: "desc" }}
324
335
  empty={
325
336
  <EmptyPage.Root size="s" role="status" aria-labelledby="invoices-empty">
@@ -1,7 +1,6 @@
1
- /** A campaign list with search, a status filter and export above the table; the empty text when nothing matches — `toolbar`, `empty`. */
1
+ /** A campaign table with its own search and status filter above it — two table-scoped controls; the empty text when nothing matches — `toolbar`, `empty`. */
2
2
  import {
3
3
  Badge,
4
- Button,
5
4
  DataTable,
6
5
  type DataTableColumn,
7
6
  Icon,
@@ -87,36 +86,31 @@ export default function DataTableToolbarExample() {
87
86
  pageSize={5}
88
87
  empty="Ничего не найдено — измените запрос или фильтр"
89
88
  toolbar={
90
- <div className={styles.toolbar}>
91
- <div className={styles.filters}>
92
- <Input.Root size="s" className={styles.search}>
93
- <Input.Wrapper>
94
- <Input.Icon side="start">
95
- <Icon name="action.search" />
96
- </Input.Icon>
97
- <Input.Field
98
- type="search"
99
- placeholder="Поиск кампаний"
100
- aria-label="Поиск кампаний"
101
- value={query}
102
- onValueChange={setQuery}
103
- />
104
- </Input.Wrapper>
105
- </Input.Root>
106
- <SegmentedControl.Root
107
- size="s"
108
- aria-label="Статус"
109
- value={status}
110
- onValueChange={setStatus}
111
- >
112
- <SegmentedControl.Item value="all">Все</SegmentedControl.Item>
113
- <SegmentedControl.Item value="active">Активные</SegmentedControl.Item>
114
- <SegmentedControl.Item value="paused">На паузе</SegmentedControl.Item>
115
- </SegmentedControl.Root>
116
- </div>
117
- <Button.Root variant="outline" tone="neutral" size="s">
118
- Экспорт
119
- </Button.Root>
89
+ <div className={styles.filters}>
90
+ <Input.Root size="s" className={styles.search}>
91
+ <Input.Wrapper>
92
+ <Input.Icon side="start">
93
+ <Icon name="action.search" />
94
+ </Input.Icon>
95
+ <Input.Field
96
+ type="search"
97
+ placeholder="Поиск кампаний"
98
+ aria-label="Поиск кампаний"
99
+ value={query}
100
+ onValueChange={setQuery}
101
+ />
102
+ </Input.Wrapper>
103
+ </Input.Root>
104
+ <SegmentedControl.Root
105
+ size="s"
106
+ aria-label="Статус"
107
+ value={status}
108
+ onValueChange={setStatus}
109
+ >
110
+ <SegmentedControl.Item value="all">Все</SegmentedControl.Item>
111
+ <SegmentedControl.Item value="active">Активные</SegmentedControl.Item>
112
+ <SegmentedControl.Item value="paused">На паузе</SegmentedControl.Item>
113
+ </SegmentedControl.Root>
120
114
  </div>
121
115
  }
122
116
  />
@@ -12,7 +12,7 @@
12
12
  - An annual day and month without a year (`yearless`).
13
13
 
14
14
  ## When not to use
15
- - Time of day only → use [Input](../input/COMPONENT.md) with a time mask.
15
+ - Time of day only → use [Input](../input/COMPONENT.md) with `Input.Field type="time"`: the time is typed in hour and minute segments, there is no day to pick (a date with a time is `withTime`).
16
16
  - A choice between a few fixed periods («7 дней», «30 дней») → use [SegmentedControl](../segmented-control/COMPONENT.md) or [Select](../select/COMPONENT.md).
17
17
  - A free-text date the user types → use [Input](../input/COMPONENT.md).
18
18
 
@@ -63,6 +63,7 @@ panel presets column (range) · 1–2 month grids · promp
63
63
  | `size` | `"xs" \| "s" \| "m" \| "l" \| "xl"` | host tier, else `"m"` | Field tier (height 28 · 32 · 36 · 40 · 48) and panel tier (day cell 24 · 28 · 32 · 36 · 40). Without it the tier of its host, else `m`. |
64
64
  | `label` | `ReactNode` | — | Field label; part of the button's accessible name together with the value. |
65
65
  | `hint` | `ReactNode` | — | Support text under the field (`aria-describedby`). |
66
+ | `hintTone` | `"neutral" \| "success" \| "warning" \| "danger"` | `"neutral"` | Status color of `hint` («Осталось 12 дней» in `warning`). The words carry the status, the color repeats it; an `error` replaces the hint and its tone. A validation error is `error`, never a `danger` hint. |
66
67
  | `error` | `ReactNode` | — | Error message in place of the hint; implies `invalid`. |
67
68
  | `required` | `boolean` | `false` | Red `*` after the label; the field button is described by `labels.required` (a button takes no `aria-required`). |
68
69
  | `optional` | `boolean` | — | Muted `labels.optional` after the label. |
@@ -241,6 +242,7 @@ Committing: without `footer` a picked day (or the second day of a range) applies
241
242
  | [inline-panel.tsx](examples/inline-panel.tsx) | A booking calendar embedded in a card: the card is its container, two months when the parent has room, the range applies at once — `Datepicker.Panel`, `months`, `prompt`. |
242
243
  | [yearless.tsx](examples/yearless.tsx) | An annual price change date: day and month without a year, a value prefix and taken days disabled — `yearless`, `valuePrefix`, `isDayDisabled`. |
243
244
  | [locale.tsx](examples/locale.tsx) | A delivery window on a partner portal in English: month and weekday names from the date-fns locale, the week from Sunday and the system texts translated — `locale`, `weekStartsOn`, `labels`. |
245
+ | [deadline.tsx](examples/deadline.tsx) | A document's expiry date whose hint counts the days left and takes the status tone — `hint`, `hintTone`. |
244
246
  | [dismiss.tsx](examples/dismiss.tsx) | A shift period with a footer: the calendar keeps the draft on a press beside it and closes by Escape, Reset or Apply — `closeOnOutsideClick`, `closeOnEscape`. |
245
247
  | [controlled.tsx](examples/controlled.tsx) | A report filter owns the period: quick buttons set it from outside, the field shows it — `value`, `onValueChange`. |
246
248
  | [controlled-open.tsx](examples/controlled-open.tsx) | The parent owns the panel: a reminder button opens the calendar from code, a picked day closes it — `open`, `onOpenChange`. |
@@ -0,0 +1,33 @@
1
+ /** A document's expiry date whose hint counts the days left and takes the status tone — `hint`, `hintTone`. */
2
+ import { differenceInCalendarDays } from "date-fns";
3
+ import { Datepicker } from "prime-ui-kit";
4
+ import * as React from "react";
5
+
6
+ const TODAY = new Date(2026, 9, 15);
7
+ const WARN_DAYS = 30;
8
+
9
+ /** The hint and its tone: the words say the status, the tone repeats it. */
10
+ function expiryHint(expires: Date | null) {
11
+ if (!expires) return { hint: "Дата из договора страхования", tone: "neutral" as const };
12
+ const days = differenceInCalendarDays(expires, TODAY);
13
+ if (days < 0) return { hint: `Срок истёк ${-days} дн. назад`, tone: "danger" as const };
14
+ if (days <= WARN_DAYS) return { hint: `Осталось ${days} дн.`, tone: "warning" as const };
15
+ return { hint: `Действует ещё ${days} дн.`, tone: "success" as const };
16
+ }
17
+
18
+ export default function DatepickerDeadlineExample() {
19
+ const [expires, setExpires] = React.useState<Date | null>(new Date(2026, 9, 27));
20
+ const { hint, tone } = expiryHint(expires);
21
+
22
+ return (
23
+ <Datepicker.Root
24
+ mode="single"
25
+ label="Страховка действует до"
26
+ value={expires}
27
+ onValueChange={setExpires}
28
+ hint={hint}
29
+ hintTone={tone}
30
+ fullWidth
31
+ />
32
+ );
33
+ }
@@ -42,6 +42,7 @@ DigitInput field frame: label row → cells → support row (hint | e
42
42
  | `required` | `boolean` | — | Red `*` after the label and native `required` on every cell. |
43
43
  | `optional` | `boolean` | — | Muted marker right after the label text (`labels.optional`). |
44
44
  | `hint` | `ReactNode` | — | Help text under the cells. Hidden while `error` is shown. |
45
+ | `hintTone` | `"neutral" \| "success" \| "warning" \| "danger"` | `"neutral"` | Status color of `hint` («Осталось 12 дней» in `warning`). The words carry the status, the color repeats it; an `error` replaces the hint and its tone. A validation error is `error`, never a `danger` hint. |
45
46
  | `error` | `ReactNode` | — | Error message in the hint slot; implies `invalid`. |
46
47
  | `invalid` | `boolean` | — | Danger ring and danger digits on every cell, `aria-invalid`. A non-empty `error` implies it. |
47
48
  | `success` | `boolean` | `false` | The code was accepted (after the server checked it): the cells turn success one after another. Ignored while invalid. Say it in words too (`hint`). |
@@ -30,7 +30,7 @@ Dnd.Root session owner: overlay (portal), live region, l
30
30
  ├─ Dnd.Sortable list container and drop target; renders items in the drawn order
31
31
  │ ├─ header optional content before the items that never moves (a group's heading row)
32
32
  │ ├─ Dnd.SortableItem one item (li in ul/ol, div otherwise); the gap is drawn before it
33
- │ │ └─ Dnd.Handle optional grip: a ghost icon-only Button (with `handle` on the list); a lock in a `locked` item; busy while the item's move is saved
33
+ │ │ └─ Dnd.Handle optional grip, last in the item: a ghost icon-only Button (with `handle` on the list); a lock in a `locked` item; busy while the item's move is saved
34
34
  │ ├─ empty the `empty` content while the list has no items
35
35
  │ └─ children optional content after the items that never moves (an add tile)
36
36
  ├─ Dnd.Draggable an item to carry elsewhere; stays in place, faded, until the drop
@@ -85,7 +85,7 @@ Generic `Dnd.Sortable<T>`; `ref` → `HTMLElement`. The list and its drop target
85
85
  | `…rest` | `Omit<HTMLAttributes<HTMLElement>, "id">` | — | `aria-labelledby` / `aria-describedby` (the visible title and description) and the other attributes. |
86
86
 
87
87
  ### Dnd.Handle
88
- `ref` → `HTMLButtonElement` (`HTMLSpanElement` in a `locked` item). The grip: a ghost icon-only `xs` Button that starts the drag and takes the item's keys; busy while the item's move is saved. In a `locked` item it is a lock.
88
+ `ref` → `HTMLButtonElement` (`HTMLSpanElement` in a `locked` item). The grip: a ghost icon-only `xs` Button that starts the drag and takes the item's keys; busy while saving. In a `locked` item it is a lock. Place it last in the item, after its controls.
89
89
 
90
90
  | Prop | Type | Default | Description |
91
91
  |---|---|---|---|
@@ -201,6 +201,7 @@ An item's own `onPointerDown` / `onKeyDown` run before the kit's: `preventDefaul
201
201
  ## Layout & spacing
202
202
  - The distance between items is `--prime-space-2`; a host sets `--dnd-sortable-gap` on the list for another one.
203
203
  - A grid (`axis="grid"`) is `display: grid`: the host sets the tracks (`grid-template-columns`) and the cells' size; the gap takes a cell, and a carried item resizes to the cell it would land in.
204
+ - A `Dnd.Handle` ends its item: the last child, after the item's own trailing controls (a remove button), at the inline end (on the left in RTL); a `locked` item's lock takes the same place, so the grips of every row stand on one line. In a table it is the last cell. An on / off switch leads the item (its first child), so its state reads first and nothing stands between the text and the grip.
204
205
  - The reason chip stands `--prime-tooltip-offset` under the carried copy, start-aligned, at most `--prime-tooltip-max-width` wide.
205
206
  - The look of a row is the consumer's: give `Dnd.SortableItem` / `Dnd.Draggable` a radius on its own class (the gap and the clone's fill take it) and keep the row's look within its ancestors up to the nearest surface (`data-depth`) — the clone flies inside empty copies (`display: contents`) of exactly those, so their variables and selectors still apply. A table row flies in a one-row copy of its table inside them.
206
207
  - A scrollable ancestor under the pointer auto-scrolls within 64 px of its edge (a `ScrollContainer` strip works).
@@ -251,7 +252,7 @@ An item's own `onPointerDown` / `onKeyDown` run before the kit's: `preventDefaul
251
252
  | Example | Shows |
252
253
  |---|---|
253
254
  | [overview.tsx](examples/overview.tsx) | Project tasks reordered by dragging the whole row; one root above, the move applied with a helper — `Dnd.Root`, `Dnd.Sortable`, `onReorder`, `moveBefore`. |
254
- | [handle.tsx](examples/handle.tsx) | Notification channels with switches: only the grip starts a drag, and the async save can roll the order back — `handle`, `Dnd.Handle`, `onReorder`. |
255
+ | [handle.tsx](examples/handle.tsx) | Notification channels, each switch leading its row and the grip ending it: only the grip starts a drag, and the async save can roll the order back — `handle`, `Dnd.Handle`, `onReorder`. |
255
256
  | [grid.tsx](examples/grid.tsx) | Product photos in a wrapping grid: a photo carried across rows lands in reading order, the gap takes a cell, Alt + ← / → steps it one place — `axis`. |
256
257
  | [locked.tsx](examples/locked.tsx) | Sections of a workspace menu: the home section is pinned first with a lock in place of its grip, the rest reorder around nothing past it; each row is named by its visible title — `locked`, `handle`, `aria-labelledby`. |
257
258
  | [board.tsx](examples/board.tsx) | A ticket board: columns share one kind, so a ticket lands in another column at an exact position or moves there with Alt + ← / →, an empty column says so, and a full column refuses it before the release with the reason under the ticket — `kind`, `canDrop`, `empty`, `onReorder`. |
@@ -18,9 +18,9 @@
18
18
  box-shadow: var(--prime-shadow-raised);
19
19
  }
20
20
 
21
- /* The grip sits closer to the edge: it is a square button with its own inner room. */
21
+ /* The grip ends the row and sits closer to the edge: a square button with its own inner room. */
22
22
  .handleRow {
23
- padding-inline-start: var(--prime-space-2);
23
+ padding-inline-end: var(--prime-space-2);
24
24
  }
25
25
 
26
26
  .rowText {
@@ -134,9 +134,10 @@
134
134
  text-align: end;
135
135
  }
136
136
 
137
+ /* The grip column ends the row. */
137
138
  .grip {
138
139
  inline-size: var(--prime-space-10);
139
- padding-inline-end: 0;
140
+ padding-inline-start: 0;
140
141
  }
141
142
 
142
143
  /* A stage's heading row: a fill marks where a new stage starts. */
@@ -1,4 +1,4 @@
1
- /** Notification channels with switches: only the grip starts a drag, and the async save can roll the order back — `handle`, `Dnd.Handle`, `onReorder`. */
1
+ /** Notification channels, each switch leading its row and the grip ending it: only the grip starts a drag, and the async save can roll the order back — `handle`, `Dnd.Handle`, `onReorder`. */
2
2
  import { Dnd, moveBefore, Switch, Typography } from "prime-ui-kit";
3
3
  import * as React from "react";
4
4
 
@@ -37,10 +37,6 @@ export default function DndHandleExample() {
37
37
  }}
38
38
  renderItem={(channel) => (
39
39
  <Dnd.SortableItem id={channel.id} className={styles.handleRow}>
40
- <Dnd.Handle />
41
- <Typography as="span" variant="body-m" className={styles.rowText}>
42
- {channel.title}
43
- </Typography>
44
40
  <Switch.Root
45
41
  aria-label={channel.title}
46
42
  checked={channel.enabled}
@@ -50,6 +46,10 @@ export default function DndHandleExample() {
50
46
  )
51
47
  }
52
48
  />
49
+ <Typography as="span" variant="body-m" className={styles.rowText}>
50
+ {channel.title}
51
+ </Typography>
52
+ <Dnd.Handle />
53
53
  </Dnd.SortableItem>
54
54
  )}
55
55
  />
@@ -40,7 +40,6 @@ export default function DndLockedExample() {
40
40
  aria-labelledby={`${uid}-${section.id}`}
41
41
  aria-describedby={`${uid}-${section.id}-note`}
42
42
  >
43
- <Dnd.Handle aria-label={`Переместить раздел «${section.title}»`} />
44
43
  <span className={styles.rowText}>
45
44
  <Typography as="span" variant="body-m" id={`${uid}-${section.id}`}>
46
45
  {section.title}
@@ -49,6 +48,7 @@ export default function DndLockedExample() {
49
48
  {section.description}
50
49
  </Typography>
51
50
  </span>
51
+ <Dnd.Handle aria-label={`Переместить раздел «${section.title}»`} />
52
52
  </Dnd.SortableItem>
53
53
  )}
54
54
  />
@@ -51,9 +51,6 @@ export default function DndTableExample() {
51
51
  </caption>
52
52
  <thead>
53
53
  <tr>
54
- <th scope="col" className={styles.grip}>
55
- <VisuallyHidden>Порядок</VisuallyHidden>
56
- </th>
57
54
  <th scope="col" className={styles.cell}>
58
55
  <Typography as="span" variant="caption" tone="muted">
59
56
  Работа
@@ -64,6 +61,9 @@ export default function DndTableExample() {
64
61
  Часы
65
62
  </Typography>
66
63
  </th>
64
+ <th scope="col" className={styles.grip}>
65
+ <VisuallyHidden>Порядок</VisuallyHidden>
66
+ </th>
67
67
  </tr>
68
68
  </thead>
69
69
  {stages.map((stage) => (
@@ -90,9 +90,6 @@ export default function DndTableExample() {
90
90
  }
91
91
  renderItem={(line) => (
92
92
  <Dnd.SortableItem id={line.id}>
93
- <td className={styles.grip}>
94
- <Dnd.Handle />
95
- </td>
96
93
  <td className={styles.cell}>
97
94
  <Typography as="span" variant="body-m">
98
95
  {line.title}
@@ -103,6 +100,9 @@ export default function DndTableExample() {
103
100
  {line.hours}
104
101
  </Typography>
105
102
  </td>
103
+ <td className={styles.grip}>
104
+ <Dnd.Handle />
105
+ </td>
106
106
  </Dnd.SortableItem>
107
107
  )}
108
108
  />