@daisforge/ui 1.18.0 → 1.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 (189) hide show
  1. package/chunks/{EXTERNAL_PACKAGE_MODULE_sdds_finai_high_contrast__light_theme-B8FhA_zv.cjs → EXTERNAL_PACKAGE_MODULE_sdds_finai_high_contrast__light_theme-75fNjCa0.cjs} +1059 -1293
  2. package/chunks/{EXTERNAL_PACKAGE_MODULE_sdds_finai_high_contrast__light_theme-w2nh9o1i.mjs → EXTERNAL_PACKAGE_MODULE_sdds_finai_high_contrast__light_theme-DjDujEzF.mjs} +1060 -1294
  3. package/chunks/{TableCanvas-DcoUBrgC.mjs → TableCanvas-DkZAx-r9.mjs} +4402 -4172
  4. package/chunks/TableCanvas-QmXGAjPk.cjs +30 -0
  5. package/chunks/TableGlide-Bngn5_5l.cjs +1 -0
  6. package/chunks/{TableGlide-Ch-gaROR.mjs → TableGlide-CkorJrl9.mjs} +1633 -1595
  7. package/chunks/styles-AUqEaroI.cjs +2 -0
  8. package/chunks/styles-C-1Srtr7.mjs +132 -0
  9. package/chunks/{vendor-BzEO8Fvp.cjs → vendor-BSEdLAmZ.cjs} +1049 -1309
  10. package/chunks/{vendor-DBRfVjyT.mjs → vendor-CA3z7N_7.mjs} +1053 -1313
  11. package/components/DrawerDF/components/styled.d.ts +1 -1
  12. package/components/Notification/index.cjs +1 -1
  13. package/components/Notification/index.mjs +1 -1
  14. package/components/NumberFormat/NumberFormat.d.ts +48 -0
  15. package/components/NumberFormatAmount/NumberFormatAmount.styled.d.ts +48 -0
  16. package/components/Table/feature-edit/textEditor.styled.d.ts +48 -0
  17. package/components/TableCanvas/TableGlideInstance/adapters/column/index.cjs +1 -1
  18. package/components/TableCanvas/TableGlideInstance/adapters/column/index.mjs +1 -1
  19. package/components/TableCanvas/TableGlideInstance/adapters/index.cjs +1 -1
  20. package/components/TableCanvas/TableGlideInstance/adapters/index.mjs +1 -1
  21. package/components/TableCanvas/TableGlideInstance/index.cjs +1 -1
  22. package/components/TableCanvas/TableGlideInstance/index.mjs +2 -2
  23. package/components/TableCanvas/TableGlideInstance/utils/column/index.cjs +1 -1
  24. package/components/TableCanvas/TableGlideInstance/utils/column/index.mjs +1 -1
  25. package/components/TableCanvas/TableGlideInstance/utils/index.cjs +1 -1
  26. package/components/TableCanvas/TableGlideInstance/utils/index.mjs +1 -1
  27. package/components/TableCanvas/components/SplitIconButton/index.cjs +1 -1
  28. package/components/TableCanvas/components/SplitIconButton/index.mjs +1 -1
  29. package/components/TableCanvas/components/TableDropdown/index.cjs +1 -1
  30. package/components/TableCanvas/components/TableDropdown/index.mjs +1 -1
  31. package/components/TableCanvas/feature-cell-transfer/index.cjs +1 -1
  32. package/components/TableCanvas/feature-cell-transfer/index.mjs +1 -1
  33. package/components/TableCanvas/feature-collapse-table/index.cjs +1 -1
  34. package/components/TableCanvas/feature-collapse-table/index.mjs +1 -1
  35. package/components/TableCanvas/feature-column-control/ColumnsList/index.cjs +1 -1
  36. package/components/TableCanvas/feature-column-control/ColumnsList/index.mjs +1 -1
  37. package/components/TableCanvas/feature-column-control/columnsRenderOrder.d.ts +1 -0
  38. package/components/TableCanvas/feature-column-control/groupDepth.d.ts +14 -0
  39. package/components/TableCanvas/feature-column-control/hiddenBoundaries.d.ts +4 -0
  40. package/components/TableCanvas/feature-column-control/index.cjs +1 -1
  41. package/components/TableCanvas/feature-column-control/index.d.ts +2 -0
  42. package/components/TableCanvas/feature-column-control/index.mjs +4 -2
  43. package/components/TableCanvas/feature-column-control/types.d.ts +7 -0
  44. package/components/TableCanvas/feature-column-control/useHiddenColumnsIndicator.d.ts +19 -0
  45. package/components/TableCanvas/feature-columns-grouping/index.cjs +1 -1
  46. package/components/TableCanvas/feature-columns-grouping/index.mjs +1 -1
  47. package/components/TableCanvas/feature-content-state/index.cjs +1 -1
  48. package/components/TableCanvas/feature-content-state/index.mjs +1 -1
  49. package/components/TableCanvas/feature-context-menu/index.cjs +1 -1
  50. package/components/TableCanvas/feature-context-menu/index.mjs +1 -1
  51. package/components/TableCanvas/feature-edit/index.cjs +1 -1
  52. package/components/TableCanvas/feature-edit/index.mjs +3 -3
  53. package/components/TableCanvas/feature-filtering/combobox/index.cjs +1 -1
  54. package/components/TableCanvas/feature-filtering/combobox/index.mjs +2 -2
  55. package/components/TableCanvas/feature-filtering/filter-list-block/index.cjs +1 -1
  56. package/components/TableCanvas/feature-filtering/filter-list-block/index.mjs +2 -2
  57. package/components/TableCanvas/feature-filtering/header-filter-button/index.cjs +1 -1
  58. package/components/TableCanvas/feature-filtering/header-filter-button/index.mjs +1 -1
  59. package/components/TableCanvas/feature-filtering/index.cjs +1 -1
  60. package/components/TableCanvas/feature-filtering/index.mjs +3 -3
  61. package/components/TableCanvas/feature-filtering/sidebar-filter-block/index.cjs +1 -1
  62. package/components/TableCanvas/feature-filtering/sidebar-filter-block/index.mjs +1 -1
  63. package/components/TableCanvas/feature-infinity-scroll/index.cjs +1 -1
  64. package/components/TableCanvas/feature-infinity-scroll/index.mjs +3 -3
  65. package/components/TableCanvas/feature-key-text/index.cjs +1 -1
  66. package/components/TableCanvas/feature-key-text/index.mjs +1 -1
  67. package/components/TableCanvas/feature-notifications/index.cjs +1 -1
  68. package/components/TableCanvas/feature-notifications/index.mjs +1 -1
  69. package/components/TableCanvas/feature-pagination/index.cjs +1 -1
  70. package/components/TableCanvas/feature-pagination/index.mjs +1 -1
  71. package/components/TableCanvas/feature-popover-table/context/index.cjs +1 -1
  72. package/components/TableCanvas/feature-popover-table/context/index.mjs +1 -1
  73. package/components/TableCanvas/feature-popover-table/hooks/index.cjs +1 -1
  74. package/components/TableCanvas/feature-popover-table/hooks/index.mjs +1 -1
  75. package/components/TableCanvas/feature-popover-table/index.cjs +1 -1
  76. package/components/TableCanvas/feature-popover-table/index.mjs +4 -4
  77. package/components/TableCanvas/feature-popover-table/utils/index.cjs +1 -1
  78. package/components/TableCanvas/feature-popover-table/utils/index.mjs +1 -1
  79. package/components/TableCanvas/feature-right-sidebar/index.cjs +1 -1
  80. package/components/TableCanvas/feature-right-sidebar/index.mjs +1 -1
  81. package/components/TableCanvas/feature-row-detail/index.cjs +1 -1
  82. package/components/TableCanvas/feature-row-detail/index.mjs +1 -1
  83. package/components/TableCanvas/feature-row-instruments/index.cjs +1 -1
  84. package/components/TableCanvas/feature-row-instruments/index.mjs +1 -1
  85. package/components/TableCanvas/feature-row-markers/index.cjs +1 -1
  86. package/components/TableCanvas/feature-row-markers/index.mjs +1 -1
  87. package/components/TableCanvas/feature-row-size/index.cjs +1 -1
  88. package/components/TableCanvas/feature-row-size/index.mjs +1 -1
  89. package/components/TableCanvas/feature-rows-grouping/index.cjs +1 -1
  90. package/components/TableCanvas/feature-rows-grouping/index.mjs +1 -1
  91. package/components/TableCanvas/feature-searching/index.cjs +1 -1
  92. package/components/TableCanvas/feature-searching/index.mjs +1 -1
  93. package/components/TableCanvas/feature-select-row/index.cjs +1 -1
  94. package/components/TableCanvas/feature-select-row/index.mjs +1 -1
  95. package/components/TableCanvas/feature-sorting/index.cjs +1 -1
  96. package/components/TableCanvas/feature-sorting/index.mjs +1 -1
  97. package/components/TableCanvas/feature-table-settings/index.cjs +1 -1
  98. package/components/TableCanvas/feature-table-settings/index.mjs +1 -1
  99. package/components/TableCanvas/feature-tooltip/constants.d.ts +1 -0
  100. package/components/TableCanvas/feature-tooltip/index.cjs +1 -1
  101. package/components/TableCanvas/feature-tooltip/index.mjs +1 -1
  102. package/components/TableCanvas/feature-tooltip/types.d.ts +2 -0
  103. package/components/TableCanvas/feature-tooltip/utils/index.cjs +1 -1
  104. package/components/TableCanvas/feature-tooltip/utils/index.mjs +4 -4
  105. package/components/TableCanvas/feature-tree/index.cjs +1 -1
  106. package/components/TableCanvas/feature-tree/index.mjs +1 -1
  107. package/components/TableCanvas/feature-tree/tree-disclosure-icons.d.ts +65 -0
  108. package/components/TableCanvas/index.cjs +1 -1
  109. package/components/TableCanvas/index.mjs +17 -17
  110. package/components/TableCanvas/renders/formatCell/index.cjs +1 -1
  111. package/components/TableCanvas/renders/formatCell/index.mjs +1 -1
  112. package/components/TableCanvas/renders/rowIconConfig.d.ts +6 -0
  113. package/components/TableCanvas/renders/styleConstants.d.ts +3 -1
  114. package/components/TableCanvas/renders/styled.d.ts +0 -1
  115. package/components/TableCanvas/styles/index.cjs +1 -1
  116. package/components/TableCanvas/styles/index.mjs +1 -1
  117. package/components/TableCanvas/table-hooks/index.cjs +1 -1
  118. package/components/TableCanvas/table-hooks/index.mjs +3 -3
  119. package/components/TableCanvas/table-hooks/useColumns.d.ts +1 -0
  120. package/components/TableCanvas/types/index.cjs +1 -1
  121. package/components/TableCanvas/types/index.mjs +1 -1
  122. package/components/TableCanvas/types/table-config.type.d.ts +2 -0
  123. package/components/TableCanvas/utils/index.cjs +1 -1
  124. package/components/TableCanvas/utils/index.mjs +1 -1
  125. package/components/TableCanvas/widgets/control-block/compression/index.cjs +1 -1
  126. package/components/TableCanvas/widgets/control-block/compression/index.mjs +1 -1
  127. package/components/TableCanvas/widgets/control-block/index.cjs +1 -1
  128. package/components/TableCanvas/widgets/control-block/index.mjs +3 -3
  129. package/components/TableCanvas/widgets/control-block/right-side/index.cjs +1 -1
  130. package/components/TableCanvas/widgets/control-block/right-side/index.mjs +1 -1
  131. package/components/TableCanvas/widgets/index.cjs +1 -1
  132. package/components/TableCanvas/widgets/index.mjs +1 -1
  133. package/components/TableCanvas/widgets/mass-actions/hooks/index.cjs +1 -1
  134. package/components/TableCanvas/widgets/mass-actions/hooks/index.mjs +1 -1
  135. package/components/TableCanvas/widgets/mass-actions/index.cjs +1 -1
  136. package/components/TableCanvas/widgets/mass-actions/index.mjs +1 -1
  137. package/components/TableCanvasSharedConstants/index.cjs +1 -1
  138. package/components/TableCanvasSharedConstants/index.d.ts +1 -0
  139. package/components/TableCanvasSharedConstants/index.mjs +4 -3
  140. package/components/TableGlide/constants.d.ts +1 -1
  141. package/components/TableGlide/hooks/selection/index.cjs +1 -1
  142. package/components/TableGlide/hooks/selection/index.mjs +1 -1
  143. package/components/TableGlide/hooks/useItemHoveredHandler.d.ts +4 -1
  144. package/components/TableGlide/index.cjs +1 -1
  145. package/components/TableGlide/index.mjs +1 -1
  146. package/components/TableGlide/lib/canvas/cells/buttons/index.cjs +1 -1
  147. package/components/TableGlide/lib/canvas/cells/buttons/index.mjs +1 -1
  148. package/components/TableGlide/lib/canvas/cells/iconSprites/index.cjs +1 -1
  149. package/components/TableGlide/lib/canvas/cells/iconSprites/index.mjs +1 -1
  150. package/components/TableGlide/lib/canvas/cells/index.cjs +1 -1
  151. package/components/TableGlide/lib/canvas/cells/index.mjs +1 -1
  152. package/components/TableGlide/lib/canvas/cells/renderer/index.cjs +1 -1
  153. package/components/TableGlide/lib/canvas/cells/renderer/index.mjs +1 -1
  154. package/components/TableGlide/lib/canvas/components/index.d.ts +1 -0
  155. package/components/TableGlide/lib/canvas/core/helpers/index.cjs +1 -1
  156. package/components/TableGlide/lib/canvas/core/helpers/index.mjs +1 -1
  157. package/components/TableGlide/lib/canvas/core/index.cjs +1 -1
  158. package/components/TableGlide/lib/canvas/core/index.mjs +1 -1
  159. package/components/TableGlide/lib/canvas/hooks/index.cjs +1 -1
  160. package/components/TableGlide/lib/canvas/hooks/index.mjs +1 -1
  161. package/components/TableGlide/lib/canvas/index.cjs +1 -1
  162. package/components/TableGlide/lib/canvas/index.mjs +1 -1
  163. package/components/TableGlide/lib/canvas/miniflex/index.cjs +1 -1
  164. package/components/TableGlide/lib/canvas/miniflex/index.mjs +1 -1
  165. package/components/TableGlide/lib/canvas/primitives/CanvasEmbedIconButton.d.ts +2 -0
  166. package/components/TableGlide/lib/canvas/primitives/index.cjs +1 -1
  167. package/components/TableGlide/lib/canvas/primitives/index.mjs +1 -1
  168. package/components/TableGlide/lib/canvas/utils/index.cjs +1 -1
  169. package/components/TableGlide/lib/canvas/utils/index.mjs +1 -1
  170. package/components/TableGlide/lib/canvas/utils/portalHoverEvents.d.ts +1 -0
  171. package/components/TableGlide/theming/glide-colors.d.ts +1 -0
  172. package/components/TableGlide/theming/index.cjs +1 -1
  173. package/components/TableGlide/theming/index.mjs +1 -1
  174. package/components/TableGlide/theming/size-tokens.d.ts +1 -1
  175. package/components/TableGlide/theming/sizes.d.ts +2 -2
  176. package/components/TourWidget/index.cjs +1 -1
  177. package/components/TourWidget/index.mjs +2 -2
  178. package/index.cjs +1 -1
  179. package/index.mjs +4 -4
  180. package/mcp-data/component-index.json +477 -93
  181. package/package.json +10 -10
  182. package/styles/index.cjs +1 -1
  183. package/styles/index.mjs +1 -1
  184. package/themes/index.cjs +1 -1
  185. package/themes/index.mjs +2 -2
  186. package/chunks/TableCanvas-MMWMrYiV.cjs +0 -30
  187. package/chunks/TableGlide-TYzM2bEB.cjs +0 -1
  188. package/chunks/styles-BBVEBDDw.mjs +0 -132
  189. package/chunks/styles-C-pJNMSQ.cjs +0 -2
@@ -1,6 +1,6 @@
1
1
  {
2
- "generatedAt": "2026-09-08T15:47:33.375Z",
3
- "libVersion": "1.18.0",
2
+ "generatedAt": "2026-09-15T09:09:39.134Z",
3
+ "libVersion": "1.19.0",
4
4
  "components": {
5
5
  "Accordion": {
6
6
  "name": "Accordion",
@@ -128,6 +128,18 @@
128
128
  "required": false,
129
129
  "description": ""
130
130
  },
131
+ {
132
+ "name": "defaultIconContent",
133
+ "type": "AccordionItemDefaultIconContent | undefined",
134
+ "required": false,
135
+ "description": ""
136
+ },
137
+ {
138
+ "name": "defaultIconPlacement",
139
+ "type": "AccordionItemDefaultIconPlacement | undefined",
140
+ "required": false,
141
+ "description": ""
142
+ },
131
143
  {
132
144
  "name": "eventKey",
133
145
  "type": "number | undefined",
@@ -393,6 +405,12 @@
393
405
  "required": false,
394
406
  "description": "Предотвратить автоматическое изменение положения."
395
407
  },
408
+ {
409
+ "name": "stretchHeight",
410
+ "type": "boolean | undefined",
411
+ "required": false,
412
+ "description": "Растянуть Popover до границы доступной области по вертикали."
413
+ },
396
414
  {
397
415
  "name": "target",
398
416
  "type": "string | number | boolean | React.ReactElement<any, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | React.ReactPortal | ((instance: HTMLElement | null) => void) | React.RefObject<HTMLElement> | null | undefined",
@@ -3774,7 +3792,14 @@
3774
3792
  "folderName": "Calendar",
3775
3793
  "role": "primary",
3776
3794
  "description": "Календарь для выбора одной даты или диапазона дат с отметкой событий",
3777
- "props": [],
3795
+ "props": [
3796
+ {
3797
+ "name": "onChangeVisibleDate",
3798
+ "type": "((date: Date) => void) | undefined",
3799
+ "required": false,
3800
+ "description": "Обработчик изменения отображаемых месяца или года при навигации по календарю."
3801
+ }
3802
+ ],
3778
3803
  "propsTypeName": "CalendarProps",
3779
3804
  "sourceFile": "node_modules/@salutejs/sdds-finai/types/components/Calendar/Calendar.d.ts",
3780
3805
  "type": "wrapper",
@@ -4129,6 +4154,12 @@
4129
4154
  "required": false,
4130
4155
  "description": "Минимальное значение даты."
4131
4156
  },
4157
+ {
4158
+ "name": "onChangeVisibleDate",
4159
+ "type": "((date: Date) => void) | undefined",
4160
+ "required": false,
4161
+ "description": "Обработчик изменения отображаемых месяца или года при навигации по календарю."
4162
+ },
4132
4163
  {
4133
4164
  "name": "renderFromDate",
4134
4165
  "type": "Date | undefined",
@@ -4311,6 +4342,12 @@
4311
4342
  "required": false,
4312
4343
  "description": "Обработчик для выбора стартового значения в диапазоне."
4313
4344
  },
4345
+ {
4346
+ "name": "onChangeVisibleDate",
4347
+ "type": "((date: Date) => void) | undefined",
4348
+ "required": false,
4349
+ "description": "Обработчик изменения отображаемых месяца или года при навигации по календарю."
4350
+ },
4314
4351
  {
4315
4352
  "name": "renderFromDate",
4316
4353
  "type": "Date | undefined",
@@ -4475,6 +4512,12 @@
4475
4512
  "required": false,
4476
4513
  "description": "Минимальное значение даты."
4477
4514
  },
4515
+ {
4516
+ "name": "onChangeVisibleDate",
4517
+ "type": "((date: Date) => void) | undefined",
4518
+ "required": false,
4519
+ "description": "Обработчик изменения отображаемых месяца или года при навигации по календарю."
4520
+ },
4478
4521
  {
4479
4522
  "name": "renderFromDate",
4480
4523
  "type": "Date | undefined",
@@ -4651,6 +4694,12 @@
4651
4694
  "required": false,
4652
4695
  "description": "Обработчик для выбора стартового значения в диапазоне."
4653
4696
  },
4697
+ {
4698
+ "name": "onChangeVisibleDate",
4699
+ "type": "((date: Date) => void) | undefined",
4700
+ "required": false,
4701
+ "description": "Обработчик изменения отображаемых месяца или года при навигации по календарю."
4702
+ },
4654
4703
  {
4655
4704
  "name": "renderFromDate",
4656
4705
  "type": "Date | undefined",
@@ -5617,7 +5666,15 @@
5617
5666
  "type": "boolean",
5618
5667
  "required": false,
5619
5668
  "description": "Компонент c округлым border-radius",
5620
- "default": "false",
5669
+ "default": "'false'",
5670
+ "inheritedFrom": "Chip",
5671
+ "inheritedPackage": "@salutejs/sdds-finai"
5672
+ },
5673
+ {
5674
+ "name": "pin",
5675
+ "type": "\"square-square\" | \"square-clear\" | \"clear-square\" | \"clear-clear\" | \"clear-circle\" | \"circle-clear\" | \"circle-circle\"",
5676
+ "required": false,
5677
+ "description": "Свойство задает скругление border-radius",
5621
5678
  "inheritedFrom": "Chip",
5622
5679
  "inheritedPackage": "@salutejs/sdds-finai"
5623
5680
  },
@@ -5661,13 +5718,6 @@
5661
5718
  "inheritedFrom": "Chip",
5662
5719
  "inheritedPackage": "@salutejs/sdds-finai"
5663
5720
  },
5664
- {
5665
- "name": "pin",
5666
- "type": "\"square-square\" | \"square-clear\" | \"clear-square\" | \"clear-clear\" | \"clear-circle\" | \"circle-clear\" | \"circle-circle\"",
5667
- "required": false,
5668
- "inheritedFrom": "Chip",
5669
- "inheritedPackage": "@salutejs/sdds-finai"
5670
- },
5671
5721
  {
5672
5722
  "name": "readOnly",
5673
5723
  "type": "boolean",
@@ -5742,7 +5792,7 @@
5742
5792
  "type": "boolean",
5743
5793
  "required": false,
5744
5794
  "description": "Группа будет переопределять view и size для всех элементов внутри",
5745
- "default": "true",
5795
+ "default": "'true'",
5746
5796
  "inheritedFrom": "ChipGroup",
5747
5797
  "inheritedPackage": "@salutejs/sdds-finai"
5748
5798
  },
@@ -5754,6 +5804,15 @@
5754
5804
  "inheritedFrom": "ChipGroup",
5755
5805
  "inheritedPackage": "@salutejs/sdds-finai"
5756
5806
  },
5807
+ {
5808
+ "name": "shape",
5809
+ "type": "\"default\" | \"segmented\"",
5810
+ "required": false,
5811
+ "description": "Скругления для чипов внутри группы",
5812
+ "default": "default",
5813
+ "inheritedFrom": "ChipGroup",
5814
+ "inheritedPackage": "@salutejs/sdds-finai"
5815
+ },
5757
5816
  {
5758
5817
  "name": "size",
5759
5818
  "type": "\"s\" | \"m\" | \"xs\"",
@@ -5769,13 +5828,6 @@
5769
5828
  "description": "Вид группы",
5770
5829
  "inheritedFrom": "ChipGroup",
5771
5830
  "inheritedPackage": "@salutejs/sdds-finai"
5772
- },
5773
- {
5774
- "name": "shape",
5775
- "type": "\"default\" | \"segmented\"",
5776
- "required": false,
5777
- "inheritedFrom": "ChipGroup",
5778
- "inheritedPackage": "@salutejs/sdds-finai"
5779
5831
  }
5780
5832
  ],
5781
5833
  "atomicMcpVersion": "0.355.0",
@@ -6999,7 +7051,14 @@
6999
7051
  "folderName": "DatePicker",
7000
7052
  "role": "primary",
7001
7053
  "description": "Поле выбора одной даты со встроенным календарём и иконкой",
7002
- "props": [],
7054
+ "props": [
7055
+ {
7056
+ "name": "onChangeVisibleDate",
7057
+ "type": "((date: Date) => void) | undefined",
7058
+ "required": false,
7059
+ "description": "Обработчик изменения отображаемых месяца или года при навигации по календарю."
7060
+ }
7061
+ ],
7003
7062
  "propsTypeName": "DatePickerProps",
7004
7063
  "sourceFile": "packages/ui-kit/src/components/DatePicker/DatePicker.tsx",
7005
7064
  "type": "wrapper",
@@ -7493,7 +7552,7 @@
7493
7552
  "name": "stretched",
7494
7553
  "type": "boolean",
7495
7554
  "required": false,
7496
- "description": "Растянуть поле ввода на всю доступную ширину",
7555
+ "description": "Растянуть поле ввода на всю доступную ширину, а календарь — на всю доступную ширину и высоту",
7497
7556
  "inheritedFrom": "DatePicker",
7498
7557
  "inheritedPackage": "@salutejs/sdds-finai"
7499
7558
  },
@@ -7701,6 +7760,13 @@
7701
7760
  "description": "Флаг наличия индикатора обязательности поля",
7702
7761
  "default": "false"
7703
7762
  },
7763
+ {
7764
+ "name": "isCalendarPositionedByInput",
7765
+ "type": "boolean | undefined",
7766
+ "required": false,
7767
+ "description": "Позиционировать одиночный календарь относительно активного поля ввода",
7768
+ "default": "false"
7769
+ },
7704
7770
  {
7705
7771
  "name": "isDoubleCalendar",
7706
7772
  "type": "boolean | undefined",
@@ -8016,6 +8082,12 @@
8016
8082
  "required": false,
8017
8083
  "description": "Должны ли значения минимального и максимального дня включаться в диапазон."
8018
8084
  },
8085
+ {
8086
+ "name": "inputWrapperRef",
8087
+ "type": "React.Ref<HTMLDivElement> | undefined",
8088
+ "required": false,
8089
+ "description": "Ссылка на обертку полей ввода"
8090
+ },
8019
8091
  {
8020
8092
  "name": "lang",
8021
8093
  "type": "\"ru\" | \"en\" | undefined",
@@ -8065,6 +8137,12 @@
8065
8137
  "required": false,
8066
8138
  "description": "Коллбэк, вызываемый при потере фокуса вторым полем ввода"
8067
8139
  },
8140
+ {
8141
+ "name": "onChangeVisibleDate",
8142
+ "type": "((date: Date) => void) | undefined",
8143
+ "required": false,
8144
+ "description": "Обработчик изменения отображаемых месяца или года при навигации по календарю."
8145
+ },
8068
8146
  {
8069
8147
  "name": "onFocusFirstTextfield",
8070
8148
  "type": "((event: React.FocusEvent<HTMLInputElement, Element>) => void) | undefined",
@@ -8154,7 +8232,7 @@
8154
8232
  "name": "stretched",
8155
8233
  "type": "boolean | undefined",
8156
8234
  "required": false,
8157
- "description": "Растянуть поле ввода на всю доступную ширину"
8235
+ "description": "Растянуть поле ввода на всю доступную ширину, а календарь — на всю доступную ширину и высоту"
8158
8236
  },
8159
8237
  {
8160
8238
  "name": "titleCaption",
@@ -8265,6 +8343,12 @@
8265
8343
  "role": "primary",
8266
8344
  "description": "Поле для ввода даты и времени одновременно в одном контроле",
8267
8345
  "props": [
8346
+ {
8347
+ "name": "onChangeVisibleDate",
8348
+ "type": "((date: Date) => void) | undefined",
8349
+ "required": false,
8350
+ "description": "Обработчик изменения отображаемых месяца или года при навигации по календарю."
8351
+ },
8268
8352
  {
8269
8353
  "name": "enterKeyHint",
8270
8354
  "type": "\"search\" | \"enter\" | \"done\" | \"go\" | \"next\" | \"previous\" | \"send\" | undefined",
@@ -8588,7 +8672,7 @@
8588
8672
  "name": "stretched",
8589
8673
  "type": "boolean",
8590
8674
  "required": false,
8591
- "description": "Растянуть поле ввода на всю доступную ширину",
8675
+ "description": "Растянуть поле ввода на всю доступную ширину, а календарь — на всю доступную ширину и высоту",
8592
8676
  "inheritedFrom": "DateTimePicker",
8593
8677
  "inheritedPackage": "@salutejs/sdds-finai"
8594
8678
  },
@@ -8998,7 +9082,14 @@
8998
9082
  "folderName": "Drawer",
8999
9083
  "role": "primary",
9000
9084
  "description": "Базовая выезжающая боковая панель поверх контента страницы",
9001
- "props": [],
9085
+ "props": [
9086
+ {
9087
+ "name": "overlayProps",
9088
+ "type": "DrawerOverlayProps | undefined",
9089
+ "required": false,
9090
+ "description": "Настройки подложки.\nПо умолчанию `position` равен `fixed` для document и `absolute` для остальных frame."
9091
+ }
9092
+ ],
9002
9093
  "propsTypeName": "DrawerProps",
9003
9094
  "sourceFile": "node_modules/@salutejs/sdds-finai/types/components/Drawer/Drawer.d.ts",
9004
9095
  "type": "wrapper",
@@ -9599,7 +9690,7 @@
9599
9690
  },
9600
9691
  {
9601
9692
  "name": "overlayProps",
9602
- "type": "any",
9693
+ "type": "DrawerOverlayProps | undefined",
9603
9694
  "required": false,
9604
9695
  "description": ""
9605
9696
  },
@@ -16244,7 +16335,14 @@
16244
16335
  "folderName": "Modal",
16245
16336
  "role": "primary",
16246
16337
  "description": "Базовое модальное окно поверх контента без готовых layout-слотов",
16247
- "props": [],
16338
+ "props": [
16339
+ {
16340
+ "name": "focusTrapSelectors",
16341
+ "type": "string[] | undefined",
16342
+ "required": false,
16343
+ "description": "Селекторы дополнительных DOM-поддеревьев, которые считаются частью модального окна для focus trap.\nИспользуется для элементов, отрисованных через Portal или вне DOM-поддерева модального окна."
16344
+ }
16345
+ ],
16248
16346
  "propsTypeName": "ModalProps",
16249
16347
  "sourceFile": "node_modules/@salutejs/sdds-finai/types/components/Modal/Modal.d.ts",
16250
16348
  "type": "wrapper",
@@ -17412,6 +17510,12 @@
17412
17510
  "role": "primary",
17413
17511
  "description": "Расширенное модальное окно с compound-слотами: шапка, контент, футер, Left/Main",
17414
17512
  "props": [
17513
+ {
17514
+ "name": "focusTrapSelectors",
17515
+ "type": "string[] | undefined",
17516
+ "required": false,
17517
+ "description": "Селекторы дополнительных DOM-поддеревьев, которые считаются частью модального окна для focus trap.\nИспользуется для элементов, отрисованных через Portal или вне DOM-поддерева модального окна."
17518
+ },
17415
17519
  {
17416
17520
  "name": "contentContainerProps",
17417
17521
  "type": "Partial<ContainerProps> | undefined",
@@ -18321,6 +18425,12 @@
18321
18425
  "required": false,
18322
18426
  "description": "Иконка в верхней части модального окна"
18323
18427
  },
18428
+ {
18429
+ "name": "focusTrapSelectors",
18430
+ "type": "string[] | undefined",
18431
+ "required": false,
18432
+ "description": "Селекторы дополнительных DOM-поддеревьев, которые считаются частью модального окна для focus trap.\nИспользуется для элементов, отрисованных через Portal или вне DOM-поддерева модального окна."
18433
+ },
18324
18434
  {
18325
18435
  "name": "contentContainerProps",
18326
18436
  "type": "Partial<ContainerProps> | undefined",
@@ -19290,6 +19400,12 @@
19290
19400
  "role": "primary",
19291
19401
  "description": "Поле ввода с форматированием чисел (разделители, десятичные) и кнопкой очистки",
19292
19402
  "props": [
19403
+ {
19404
+ "name": "suffix",
19405
+ "type": "string | undefined",
19406
+ "required": false,
19407
+ "description": "Суффикс текста в поле ввода."
19408
+ },
19293
19409
  {
19294
19410
  "name": "onClear",
19295
19411
  "type": "(() => void) | undefined",
@@ -19803,6 +19919,12 @@
19803
19919
  "description": "Задает выравнивание индикатора обязательности поля",
19804
19920
  "default": "right"
19805
19921
  },
19922
+ {
19923
+ "name": "suffix",
19924
+ "type": "string | undefined",
19925
+ "required": false,
19926
+ "description": "Суффикс текста в поле ввода."
19927
+ },
19806
19928
  {
19807
19929
  "name": "thousandSeparator",
19808
19930
  "type": "string | boolean | undefined",
@@ -20865,7 +20987,14 @@
20865
20987
  "folderName": "Popover",
20866
20988
  "role": "primary",
20867
20989
  "description": "Всплывающая панель у элемента-триггера для доп. контента, меню или подсказок",
20868
- "props": [],
20990
+ "props": [
20991
+ {
20992
+ "name": "stretchHeight",
20993
+ "type": "boolean | undefined",
20994
+ "required": false,
20995
+ "description": "Растянуть Popover до границы доступной области по вертикали."
20996
+ }
20997
+ ],
20869
20998
  "propsTypeName": "PopoverProps",
20870
20999
  "sourceFile": "node_modules/@salutejs/sdds-finai/types/components/Popover/Popover.d.ts",
20871
21000
  "type": "wrapper",
@@ -25022,11 +25151,29 @@
25022
25151
  "description": "Стиль для UI конфигурации\nВлияет на выбор предустановленого набора токенов",
25023
25152
  "default": "default"
25024
25153
  },
25154
+ {
25155
+ "name": "firstTextfieldInputWrapperRef",
25156
+ "type": "React.Ref<HTMLDivElement> | undefined",
25157
+ "required": false,
25158
+ "description": "Ссылка на обертку первого поля ввода"
25159
+ },
25025
25160
  {
25026
25161
  "name": "hasClearDivider",
25027
25162
  "type": "boolean | undefined",
25028
25163
  "required": false,
25029
25164
  "description": "Отображение разделителя для `appearance='clear'`"
25165
+ },
25166
+ {
25167
+ "name": "inputWrapperRef",
25168
+ "type": "React.Ref<HTMLDivElement> | undefined",
25169
+ "required": false,
25170
+ "description": "Ссылка на обертку полей ввода"
25171
+ },
25172
+ {
25173
+ "name": "secondTextfieldInputWrapperRef",
25174
+ "type": "React.Ref<HTMLDivElement> | undefined",
25175
+ "required": false,
25176
+ "description": "Ссылка на обертку второго поля ввода"
25030
25177
  }
25031
25178
  ],
25032
25179
  "propsTypeName": "RangeProps",
@@ -26645,7 +26792,45 @@
26645
26792
  "folderName": "Sheet",
26646
26793
  "role": "primary",
26647
26794
  "description": "Шторка (bottom sheet), выезжающая поверх экрана снизу с шапкой и футером",
26648
- "props": [],
26795
+ "props": [
26796
+ {
26797
+ "name": "closeOnEsc",
26798
+ "type": "boolean | undefined",
26799
+ "required": false,
26800
+ "description": "Закрывать шторку при нажатии на ESC.",
26801
+ "default": "true"
26802
+ },
26803
+ {
26804
+ "name": "initialSnapPoint",
26805
+ "type": "string | undefined",
26806
+ "required": false,
26807
+ "description": "Начальная точка остановки.\nПо умолчанию — первая из `snapPoints`."
26808
+ },
26809
+ {
26810
+ "name": "onEscKeyDown",
26811
+ "type": "((event: KeyboardEvent) => void) | undefined",
26812
+ "required": false,
26813
+ "description": "Обработчик нажатия ESC (если не передан, используется onClose)."
26814
+ },
26815
+ {
26816
+ "name": "onOverlayClick",
26817
+ "type": "((event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void) | undefined",
26818
+ "required": false,
26819
+ "description": "Обработчик клика по оверлею (если не передан, используется onClose)."
26820
+ },
26821
+ {
26822
+ "name": "onSnapPointChange",
26823
+ "type": "((snapPoint: string) => void) | undefined",
26824
+ "required": false,
26825
+ "description": "Обработчик смены активной точки остановки."
26826
+ },
26827
+ {
26828
+ "name": "snapPoints",
26829
+ "type": "SheetSnapPoints | undefined",
26830
+ "required": false,
26831
+ "description": "Точки остановки шторки.\nCSS-размеры: '320px', '50%', '40dvh'.\nЕсли не передано или массив пуст — snap-points отключены."
26832
+ }
26833
+ ],
26649
26834
  "propsTypeName": "SheetProps",
26650
26835
  "sourceFile": "node_modules/@salutejs/sdds-finai/types/components/Sheet/Sheet.d.ts",
26651
26836
  "type": "wrapper",
@@ -26662,7 +26847,7 @@
26662
26847
  "name": "onClose",
26663
26848
  "type": "() => void",
26664
26849
  "required": true,
26665
- "description": "Обработчик закрытия шторки. Вызывается при клике по оверлею или смахиванию шторки вниз",
26850
+ "description": "Обработчик закрытия шторки. Вызывается при смахивании шторки вниз,\nпри клике по оверлею (если не передан onOverlayClick)\nи при нажатии ESC (если не передан onEscKeyDown).",
26666
26851
  "inheritedFrom": "Sheet",
26667
26852
  "inheritedPackage": "@salutejs/sdds-finai"
26668
26853
  },
@@ -26802,7 +26987,14 @@
26802
26987
  "folderName": "Skeleton",
26803
26988
  "role": "primary",
26804
26989
  "description": "Плейсхолдер-линия для имитации загрузки текстовой строки",
26805
- "props": [],
26990
+ "props": [
26991
+ {
26992
+ "name": "animationDuration",
26993
+ "type": "number | undefined",
26994
+ "required": false,
26995
+ "description": "Длительность одного цикла анимации в миллисекундах"
26996
+ }
26997
+ ],
26806
26998
  "propsTypeName": "ComponentProps<typeof LineSkeleton>",
26807
26999
  "sourceFile": "node_modules/@salutejs/sdds-finai/types/components/Skeleton/Skeleton.d.ts",
26808
27000
  "type": "wrapper",
@@ -26819,7 +27011,8 @@
26819
27011
  "name": "animationType",
26820
27012
  "type": "\"shimmer\" | \"pulse\"",
26821
27013
  "required": false,
26822
- "description": "Скругленность",
27014
+ "description": "Тип анимации",
27015
+ "default": "'shimmer'",
26823
27016
  "inheritedFrom": "LineSkeleton",
26824
27017
  "inheritedPackage": "@salutejs/sdds-finai"
26825
27018
  },
@@ -26835,7 +27028,7 @@
26835
27028
  "name": "customFadeOutColor",
26836
27029
  "type": "string",
26837
27030
  "required": false,
26838
- "description": "Значение цвета фона в кл=онце анимации `pulse`",
27031
+ "description": "Значение цвета фона в конце анимации `pulse`",
26839
27032
  "inheritedFrom": "LineSkeleton",
26840
27033
  "inheritedPackage": "@salutejs/sdds-finai"
26841
27034
  },
@@ -26917,11 +27110,18 @@
26917
27110
  "role": "primary",
26918
27111
  "description": "Прямоугольный плейсхолдер для блоков и изображений на время загрузки",
26919
27112
  "props": [
27113
+ {
27114
+ "name": "animationDuration",
27115
+ "type": "number | undefined",
27116
+ "required": false,
27117
+ "description": "Длительность одного цикла анимации в миллисекундах"
27118
+ },
26920
27119
  {
26921
27120
  "name": "animationType",
26922
27121
  "type": "\"shimmer\" | \"pulse\" | undefined",
26923
27122
  "required": false,
26924
- "description": "Скругленность"
27123
+ "description": "Тип анимации",
27124
+ "default": "'shimmer'"
26925
27125
  },
26926
27126
  {
26927
27127
  "name": "customFadeInColor",
@@ -26933,7 +27133,7 @@
26933
27133
  "name": "customFadeOutColor",
26934
27134
  "type": "string | undefined",
26935
27135
  "required": false,
26936
- "description": "Значение цвета фона в кл=онце анимации `pulse`"
27136
+ "description": "Значение цвета фона в конце анимации `pulse`"
26937
27137
  },
26938
27138
  {
26939
27139
  "name": "customGradientColor",
@@ -27010,11 +27210,18 @@
27010
27210
  "required": true,
27011
27211
  "description": ""
27012
27212
  },
27213
+ {
27214
+ "name": "animationDuration",
27215
+ "type": "number | undefined",
27216
+ "required": false,
27217
+ "description": "Длительность одного цикла анимации в миллисекундах"
27218
+ },
27013
27219
  {
27014
27220
  "name": "animationType",
27015
27221
  "type": "\"shimmer\" | \"pulse\" | undefined",
27016
27222
  "required": false,
27017
- "description": "Скругленность"
27223
+ "description": "Тип анимации",
27224
+ "default": "'shimmer'"
27018
27225
  },
27019
27226
  {
27020
27227
  "name": "customFadeInColor",
@@ -27026,7 +27233,7 @@
27026
27233
  "name": "customFadeOutColor",
27027
27234
  "type": "string | undefined",
27028
27235
  "required": false,
27029
- "description": "Значение цвета фона в кл=онце анимации `pulse`"
27236
+ "description": "Значение цвета фона в конце анимации `pulse`"
27030
27237
  },
27031
27238
  {
27032
27239
  "name": "customGradientColor",
@@ -27153,7 +27360,7 @@
27153
27360
  "type": "\"outer\" | \"inner\"",
27154
27361
  "required": false,
27155
27362
  "description": "Расположение подписи.",
27156
- "default": "top",
27363
+ "default": "`top`",
27157
27364
  "inheritedFrom": "Slider",
27158
27365
  "inheritedPackage": "@salutejs/sdds-finai"
27159
27366
  },
@@ -29458,6 +29665,12 @@
29458
29665
  "required": true,
29459
29666
  "description": ""
29460
29667
  },
29668
+ {
29669
+ "name": "suffix",
29670
+ "type": "string | undefined",
29671
+ "required": false,
29672
+ "description": "Суффикс текста в поле ввода."
29673
+ },
29461
29674
  {
29462
29675
  "name": "align",
29463
29676
  "type": "\"center\" | \"right\" | \"left\" | undefined",
@@ -30342,6 +30555,12 @@
30342
30555
  "required": false,
30343
30556
  "description": "Additional header icons for use by `GridColumn`.\n\nProviding custom header icons to the data grid must be done with a somewhat non-standard mechanism to allow\ntheming and scaling. The `headerIcons` property takes a dictionary which maps icon names to functions which can\ntake a foreground and background color and returns back a string representation of an svg. The svg should contain\na header similar to this `<svg width=\"20\" height=\"20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">` and\ninterpolate the fg/bg colors into the string.\n\nWe recognize this process is not fantastic from a graphics workflow standpoint, improvements are very welcome\nhere."
30344
30557
  },
30558
+ {
30559
+ "name": "hiddenColumnsIndicator",
30560
+ "type": "((col: number) => number | HiddenColumnsIndicatorInfo) | undefined",
30561
+ "required": false,
30562
+ "description": "Индикатор скрытых колонок: сколько колонок скрыто на левой границе колонки col.\ncol === columns.length означает «справа от последней». 0 или undefined значит,\nчто индикатора нет. Полоска одна независимо от числа скрытых. Ресайз на этой границе работает\nкак обычно, а двойной клик вместо автосайза зовёт onHiddenColumnsIndicatorClicked.\nМожно вернуть { count, groupDepth }, где groupDepth задаёт, сколько верхних\nгрупп-рядов пропустить (высота полосы под сгруппированную шапку). Просто число\nозначает полосу на всю высоту."
30563
+ },
30345
30564
  {
30346
30565
  "name": "hideGrid",
30347
30566
  "type": "boolean | undefined",
@@ -30570,6 +30789,12 @@
30570
30789
  "required": false,
30571
30790
  "description": "Emitted when a header menu disclosure indicator is clicked."
30572
30791
  },
30792
+ {
30793
+ "name": "onHiddenColumnsIndicatorClicked",
30794
+ "type": "((col: number, event: HeaderClickedEventArgs | GroupHeaderClickedEventArgs) => void) | undefined",
30795
+ "required": false,
30796
+ "description": "Двойной клик по индикатору скрытых колонок раскрывает промежуток."
30797
+ },
30573
30798
  {
30574
30799
  "name": "onHighlightActiveRowChange",
30575
30800
  "type": "((row: number | undefined, rowData?: R | undefined) => void) | undefined",
@@ -31095,6 +31320,13 @@
31095
31320
  "role": "internal",
31096
31321
  "description": "JSX-набор примитивов (Container, Text, Icon, Button…) для кастомного контента ячеек TableGlide",
31097
31322
  "props": [
31323
+ {
31324
+ "name": "offsetX",
31325
+ "type": "number | undefined",
31326
+ "required": false,
31327
+ "description": "Сдвиг тултипа по X (px) относительно центра ноды. Нужен, когда видимая\nчасть ноды смещена внутри неё (например, иконка прижата к краю кнопки).",
31328
+ "default": "0"
31329
+ },
31098
31330
  {
31099
31331
  "name": "preserveLineBreaks",
31100
31332
  "type": "boolean | undefined",
@@ -31717,6 +31949,12 @@
31717
31949
  "required": false,
31718
31950
  "description": "Additional header icons for use by `GridColumn`.\n\nProviding custom header icons to the data grid must be done with a somewhat non-standard mechanism to allow\ntheming and scaling. The `headerIcons` property takes a dictionary which maps icon names to functions which can\ntake a foreground and background color and returns back a string representation of an svg. The svg should contain\na header similar to this `<svg width=\"20\" height=\"20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">` and\ninterpolate the fg/bg colors into the string.\n\nWe recognize this process is not fantastic from a graphics workflow standpoint, improvements are very welcome\nhere."
31719
31951
  },
31952
+ {
31953
+ "name": "hiddenColumnsIndicator",
31954
+ "type": "((col: number) => number | HiddenColumnsIndicatorInfo) | undefined",
31955
+ "required": false,
31956
+ "description": "Индикатор скрытых колонок: сколько колонок скрыто на левой границе колонки col.\ncol === columns.length означает «справа от последней». 0 или undefined значит,\nчто индикатора нет. Полоска одна независимо от числа скрытых. Ресайз на этой границе работает\nкак обычно, а двойной клик вместо автосайза зовёт onHiddenColumnsIndicatorClicked.\nМожно вернуть { count, groupDepth }, где groupDepth задаёт, сколько верхних\nгрупп-рядов пропустить (высота полосы под сгруппированную шапку). Просто число\nозначает полосу на всю высоту."
31957
+ },
31720
31958
  {
31721
31959
  "name": "highlightRegions",
31722
31960
  "type": "readonly Highlight[] | undefined",
@@ -31922,6 +32160,12 @@
31922
32160
  "required": false,
31923
32161
  "description": "Emitted when a header menu disclosure indicator is clicked."
31924
32162
  },
32163
+ {
32164
+ "name": "onHiddenColumnsIndicatorClicked",
32165
+ "type": "((col: number, event: HeaderClickedEventArgs | GroupHeaderClickedEventArgs) => void) | undefined",
32166
+ "required": false,
32167
+ "description": "Двойной клик по индикатору скрытых колонок раскрывает промежуток."
32168
+ },
31925
32169
  {
31926
32170
  "name": "onItemHovered",
31927
32171
  "type": "((args: GridMouseEventArgs) => void) | undefined",
@@ -32542,6 +32786,13 @@
32542
32786
  "role": "internal",
32543
32787
  "description": "Базовый класс узла canvas-сцены TableGlide: layout, hit-test, отрисовка, события",
32544
32788
  "props": [
32789
+ {
32790
+ "name": "offsetX",
32791
+ "type": "number | undefined",
32792
+ "required": false,
32793
+ "description": "Сдвиг тултипа по X (px) относительно центра ноды. Нужен, когда видимая\nчасть ноды смещена внутри неё (например, иконка прижата к краю кнопки).",
32794
+ "default": "0"
32795
+ },
32545
32796
  {
32546
32797
  "name": "preserveLineBreaks",
32547
32798
  "type": "boolean | undefined",
@@ -32943,6 +33194,12 @@
32943
33194
  "required": false,
32944
33195
  "description": "Переопределяет размер квадратной кнопки (px), приоритет над SIZE_CONFIG"
32945
33196
  },
33197
+ {
33198
+ "name": "overrideWidth",
33199
+ "type": "number | undefined",
33200
+ "required": false,
33201
+ "description": "Только EmbedIconButton: ширина кнопки в раскладке и hit-area (px),\nпо умолчанию — сторона квадрата. Иконка рисуется в квадрате от левого края."
33202
+ },
32946
33203
  {
32947
33204
  "name": "view",
32948
33205
  "type": "ButtonView | undefined",
@@ -33553,10 +33810,10 @@
33553
33810
  },
33554
33811
  {
33555
33812
  "exportName": "Usage2",
33556
- "displayName": "Использование в TableCanvas.rowHeight.stories.tsx",
33813
+ "displayName": "Использование в TableCanvasTooltip.stories.tsx",
33557
33814
  "type": "usage",
33558
- "code": "<Canvas.Text\n font={theme.baseFontStyle}\n lineHeight={1.85}\n wordWrap\n >\n {row.loremIpsum}\n </Canvas.Text>",
33559
- "sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.RowHeight/TableCanvas.rowHeight.stories.tsx"
33815
+ "code": "<Canvas.Text\n overflow=\"hidden\"\n textOverflow=\"ellipsis\"\n autoTooltip\n style={{ flexGrow: 1 }}\n >\n {`${row.task}: ${longText}`}\n </Canvas.Text>",
33816
+ "sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.Tooltip/TableCanvasTooltip.stories.tsx"
33560
33817
  }
33561
33818
  ]
33562
33819
  },
@@ -33970,6 +34227,12 @@
33970
34227
  "required": false,
33971
34228
  "description": "Additional header icons for use by `GridColumn`.\n\nProviding custom header icons to the data grid must be done with a somewhat non-standard mechanism to allow\ntheming and scaling. The `headerIcons` property takes a dictionary which maps icon names to functions which can\ntake a foreground and background color and returns back a string representation of an svg. The svg should contain\na header similar to this `<svg width=\"20\" height=\"20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">` and\ninterpolate the fg/bg colors into the string.\n\nWe recognize this process is not fantastic from a graphics workflow standpoint, improvements are very welcome\nhere."
33972
34229
  },
34230
+ {
34231
+ "name": "hiddenColumnsIndicator",
34232
+ "type": "((col: number) => number | HiddenColumnsIndicatorInfo) | undefined",
34233
+ "required": false,
34234
+ "description": "Индикатор скрытых колонок: сколько колонок скрыто на левой границе колонки col.\ncol === columns.length означает «справа от последней». 0 или undefined значит,\nчто индикатора нет. Полоска одна независимо от числа скрытых. Ресайз на этой границе работает\nкак обычно, а двойной клик вместо автосайза зовёт onHiddenColumnsIndicatorClicked.\nМожно вернуть { count, groupDepth }, где groupDepth задаёт, сколько верхних\nгрупп-рядов пропустить (высота полосы под сгруппированную шапку). Просто число\nозначает полосу на всю высоту."
34235
+ },
33973
34236
  {
33974
34237
  "name": "highlightRegions",
33975
34238
  "type": "readonly Highlight[] | undefined",
@@ -34174,6 +34437,12 @@
34174
34437
  "required": false,
34175
34438
  "description": "Emitted when a header menu disclosure indicator is clicked."
34176
34439
  },
34440
+ {
34441
+ "name": "onHiddenColumnsIndicatorClicked",
34442
+ "type": "((col: number, event: HeaderClickedEventArgs | GroupHeaderClickedEventArgs) => void) | undefined",
34443
+ "required": false,
34444
+ "description": "Двойной клик по индикатору скрытых колонок раскрывает промежуток."
34445
+ },
34177
34446
  {
34178
34447
  "name": "onItemHovered",
34179
34448
  "type": "((args: GridMouseEventArgs) => void) | undefined",
@@ -35267,6 +35536,13 @@
35267
35536
  "required": false,
35268
35537
  "description": "Сменить рендер на другой тип компонента."
35269
35538
  },
35539
+ {
35540
+ "name": "disableScroll",
35541
+ "type": "boolean | undefined",
35542
+ "required": false,
35543
+ "description": "Отключает скролл к TabItem при его выборе",
35544
+ "default": "false"
35545
+ },
35270
35546
  {
35271
35547
  "name": "itemIndex",
35272
35548
  "type": "number | undefined",
@@ -35348,6 +35624,13 @@
35348
35624
  "required": false,
35349
35625
  "description": "Контент справа"
35350
35626
  },
35627
+ {
35628
+ "name": "disableScroll",
35629
+ "type": "boolean | undefined",
35630
+ "required": false,
35631
+ "description": "Отключает скролл к TabItem при его выборе",
35632
+ "default": "false"
35633
+ },
35351
35634
  {
35352
35635
  "name": "itemIndex",
35353
35636
  "type": "number | undefined",
@@ -35520,6 +35803,15 @@
35520
35803
  "inheritedFrom": "Tabs",
35521
35804
  "inheritedPackage": "@salutejs/sdds-finai"
35522
35805
  },
35806
+ {
35807
+ "name": "pilled",
35808
+ "type": "boolean",
35809
+ "required": false,
35810
+ "description": "Табы c округлым border-radius",
35811
+ "default": "false",
35812
+ "inheritedFrom": "Tabs",
35813
+ "inheritedPackage": "@salutejs/sdds-finai"
35814
+ },
35523
35815
  {
35524
35816
  "name": "size",
35525
35817
  "type": "\"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"s\" | \"l\" | \"m\" | \"xs\"",
@@ -35557,13 +35849,6 @@
35557
35849
  "inheritedFrom": "Tabs",
35558
35850
  "inheritedPackage": "@salutejs/sdds-finai"
35559
35851
  },
35560
- {
35561
- "name": "pilled",
35562
- "type": "boolean",
35563
- "required": false,
35564
- "inheritedFrom": "Tabs",
35565
- "inheritedPackage": "@salutejs/sdds-finai"
35566
- },
35567
35852
  {
35568
35853
  "name": "stretch",
35569
35854
  "type": "boolean",
@@ -35658,7 +35943,7 @@
35658
35943
  },
35659
35944
  {
35660
35945
  "name": "size",
35661
- "type": "\"xs\" | \"s\" | \"m\" | \"l\" | undefined",
35946
+ "type": "string | undefined",
35662
35947
  "required": false,
35663
35948
  "description": "Размер табов"
35664
35949
  },
@@ -38782,7 +39067,7 @@
38782
39067
  "exportName": "Usage2",
38783
39068
  "displayName": "Использование в TourWidget.examples.tsx",
38784
39069
  "type": "usage",
38785
- "code": "<TourWidget.Header title=\"Title\" />",
39070
+ "code": "<TourWidget.Header\n title={'Знакомьтесь:\\nновые возможности'}\n description={\n 'Режимы просмотра\\nОбщий реестр — все пилоты со статусом «В реестре»\\n• Мои пилоты — только ваши проекты, включая черновики'\n }\n />",
38786
39071
  "sourceFile": "packages/storybook/src/stories/TourWidget/TourWidget.examples.tsx"
38787
39072
  }
38788
39073
  ]
@@ -38915,7 +39200,7 @@
38915
39200
  "онбординг",
38916
39201
  "степ-виджет"
38917
39202
  ],
38918
- "docs": "# TourWidget\n\n`TourWidget` — локальная compound-обертка для карточки тура. Компонент отвечает за внешний вид, раскладку, фон, буллеты и пульсацию через mixin, но не управляет сценарием тура, переходами между шагами и позиционированием относительно target-элемента.\n\n## Ключевые особенности\n\n- Две ориентации: `vertical` и `horizontal`.\n- Compound API: `TourWidget.Header`, `TourWidget.Content`, `TourWidget.Footer`, `TourWidget.Bullets`, `TourWidget.Bullet`.\n- Активный шаг передается в `TourWidget` через `activeStepIndex`, а `Bullet` читает его автоматически.\n- `Content` не фиксирует размер вложенного элемента и дает ему занять `100%`.\n- `$css` есть у корневого компонента и compound-частей для локального переопределения стилей.\n- Пульсация вынесена в `tourPulseMixin` и применяется отдельно к target-элементу.\n\n## Использование\n\n```tsx\n\n```\n\nБазовая схема работы:\n\n```tsx\nconst [activeStepIndex, setActiveStepIndex] = useState(0);\n\n<ViewContainer view=\"onDark\">\n <TourWidget\n activeStepIndex={activeStepIndex}\n $css={{ width: '286px', height: '480px' }}\n >\n <TourWidget.Content>\n <Box as=\"img\" src={imageSrc} alt=\"\" $css={{ width: '100%' }} />\n </TourWidget.Content>\n <TourWidget.Header title=\"Title\" description=\"Description\" />\n <TourWidget.Footer>\n <TourWidget.Bullets count={steps.length} />\n <Button onClick={() => setActiveStepIndex((step) => step + 1)}>\n Далее\n </Button>\n </TourWidget.Footer>\n </TourWidget>\n</ViewContainer>;\n```\n\n## Compound-компоненты\n\n- `TourWidget.Header` — выводит `title`, `description` и дополнительные `children`.\n- `TourWidget.Content` — область под изображение, видео, иллюстрацию или любой ReactNode.\n- `TourWidget.Footer` — произвольная зона для кнопок, ссылки пропуска и буллетов.\n- `TourWidget.Bullets` — контейнер, который рисует массив буллетов по `count`; если буллетов больше семи, отображает окно максимум на 7 точек, прокручивает его по `activeStepIndex`, а крайние видимые точки уменьшаются до `6px`, когда за ними есть скрытые шаги.\n- `TourWidget.Bullet` — низкоуровневый визуальный индикатор шага. Активность считается как `active ?? index === activeStepIndex`.\n\n## Правильная композиция\n\n`TourWidget.Header`, `TourWidget.Content` и `TourWidget.Footer` нужно вкладывать напрямую в `TourWidget`. Компонент использует эти части как слоты: так он понимает, есть ли в туре медиа-зона, и выбирает корректную раскладку для `horizontal` и `vertical`.\n\nПравильно:\n\n```tsx\n<TourWidget orientation=\"horizontal\">\n <TourWidget.Content>\n <Box as=\"img\" src={imageSrc} alt=\"\" $css={{ width: '100%' }} />\n </TourWidget.Content>\n <TourWidget.Header title=\"Title\" description=\"Description\" />\n <TourWidget.Footer>\n <TourWidget.Bullets count={steps.length} />\n </TourWidget.Footer>\n</TourWidget>\n```\n\nЕсли нужен свой wrapper для картинки, кнопок или текста, размещайте его внутри соответствующего slot-компонента.\n\n```tsx\n<TourWidget orientation=\"horizontal\">\n <TourWidget.Content>\n <MyImageWrapper>\n <Box as=\"img\" src={imageSrc} alt=\"\" />\n </MyImageWrapper>\n </TourWidget.Content>\n <TourWidget.Header>\n <MyHeaderContent />\n </TourWidget.Header>\n <TourWidget.Footer>\n <MyFooterContent />\n </TourWidget.Footer>\n</TourWidget>\n```\n\nНе оборачивайте сам `TourWidget.Content` во внешний компонент. В таком случае `TourWidget` не сможет определить медиа-зону как свой прямой slot и горизонтальная раскладка будет работать как вариант без `Content`.\n\n```tsx\n<TourWidget orientation=\"horizontal\">\n <MyContentWrapper>\n <TourWidget.Content>\n <Box as=\"img\" src={imageSrc} alt=\"\" />\n </TourWidget.Content>\n </MyContentWrapper>\n <TourWidget.Header title=\"Title\" />\n <TourWidget.Footer />\n</TourWidget>\n```\n\n## Активный шаг\n\n`activeStepIndex` хранится на корневом `TourWidget`. Внутри компонент создает локальный context, поэтому не нужно импортировать `Provider` или прокидывать `active` в каждый буллет.\n\n```tsx\n<TourWidget activeStepIndex={5}>\n <TourWidget.Footer>\n <TourWidget.Bullets count={10} />\n </TourWidget.Footer>\n</TourWidget>\n```\n\nДля переключения шагов используйте свои кнопки или другой внешний контрол. `TourWidget.Bullets` не кликабельный и только отображает `activeStepIndex`.\n\n```tsx\n<TourWidget activeStepIndex={activeStepIndex}>\n <TourWidget.Footer>\n <TourWidget.Bullets count={10} />\n <Button onClick={() => setActiveStepIndex((step) => step + 1)}>\n Далее\n </Button>\n </TourWidget.Footer>\n</TourWidget>\n```\n\nЕсли нужна полностью ручная раскладка или состояние отдельной точки, используйте низкоуровневый `TourWidget.Bullet` и передайте `active`.\n\n## Content\n\n`TourWidget.Content` не задает жесткий размер медиа. Размер определяет вложенная нода или стиль самого `Content`.\n\n```tsx\n<TourWidget.Content>\n <Box\n as=\"img\"\n src={imageSrc}\n alt=\"\"\n $css={{ width: '270px', height: '270px' }}\n />\n</TourWidget.Content>\n```\n\n## Пульсация\n\nПульсация не встроена в `TourWidget`, потому что target-элемент и позиционирование тура контролируются снаружи. Для target используется `tourPulseMixin`.\n\n```tsx\n\nconst Target = styled(Box)`\n position: relative;\n\n &::after {\n content: '';\n position: absolute;\n ${tourPulseMixin()}\n }\n`;\n```\n\nПо умолчанию `tourPulseMixin` сам задает `inset: -4px` и `border-radius: 16px` и не добавляет заливку на target.\n\n## Темная тема\n\n`TourWidget` всегда используется на темной поверхности. Если внутри футера есть SDDS-кнопки или ссылки, оборачивайте композицию в `ViewContainer view=\"onDark\"`, чтобы вложенные controls взяли on-dark токены без ручных переопределений цвета.\n\n```tsx\n<ViewContainer view=\"onDark\">\n <TourWidget activeStepIndex={activeStepIndex}>\n <TourWidget.Footer>\n <Button view=\"secondary\">Назад</Button>\n <Button view=\"white\">Далее</Button>\n </TourWidget.Footer>\n </TourWidget>\n</ViewContainer>\n```\n\n## CSS-переменные\n\nКорневой `$css` можно использовать для точечной настройки внешнего вида.\n\n```tsx\n<TourWidget\n $css={{\n '--tour-widget-min-width': '0',\n '--tour-widget-border-radius': '16px',\n '--tour-widget-gradient-frame-height': '34%',\n '--tour-widget-gradient-frame-fade': '56%',\n }}\n/>\n```\n\n## Особенности\n\n- `TourWidget` не содержит positioner и не добавляет зависимость на `floating-ui`.\n- Компонент не хранит шаги и не переключает их сам, только отображает `activeStepIndex`.\n- `TourWidget.Bullet` — это span-индикатор, а не интерактивная кнопка.\n- `TourWidget.Bullets` — это div-viewport со сдвигающимся треком точек; при `count > 7` видны максимум семь буллетов.\n\nОписание типов — в разделе [API](?path=/docs/локальные-компоненты-tourwidget-api--docs).",
39203
+ "docs": "# TourWidget\n\n`TourWidget` — локальная compound-обертка для карточки тура. Компонент отвечает за внешний вид, раскладку, фон, буллеты и пульсацию через mixin, но не управляет сценарием тура, переходами между шагами и позиционированием относительно target-элемента.\n\n## Ключевые особенности\n\n- Две ориентации: `vertical` и `horizontal`.\n- Compound API: `TourWidget.Header`, `TourWidget.Content`, `TourWidget.Footer`, `TourWidget.Bullets`, `TourWidget.Bullet`.\n- Заголовок и описание сохраняют переводы строк `\\n` (`white-space: pre-line`); повторяющиеся пробелы схлопываются, автоматический перенос по ширине сохраняется.\n- Активный шаг передается в `TourWidget` через `activeStepIndex`, а `Bullet` читает его автоматически.\n- `Content` не фиксирует размер вложенного элемента и дает ему занять `100%`.\n- `$css` есть у корневого компонента и compound-частей для локального переопределения стилей.\n- Пульсация вынесена в `tourPulseMixin` и применяется отдельно к target-элементу.\n\n## Использование\n\n```tsx\n\n```\n\nБазовая схема работы:\n\n```tsx\nconst [activeStepIndex, setActiveStepIndex] = useState(0);\n\n<ViewContainer view=\"onDark\">\n <TourWidget\n activeStepIndex={activeStepIndex}\n $css={{ width: '286px', height: '480px' }}\n >\n <TourWidget.Content>\n <Box as=\"img\" src={imageSrc} alt=\"\" $css={{ width: '100%' }} />\n </TourWidget.Content>\n <TourWidget.Header title=\"Title\" description=\"Description\" />\n <TourWidget.Footer>\n <TourWidget.Bullets count={steps.length} />\n <Button onClick={() => setActiveStepIndex((step) => step + 1)}>\n Далее\n </Button>\n </TourWidget.Footer>\n </TourWidget>\n</ViewContainer>;\n```\n\n## Compound-компоненты\n\n- `TourWidget.Header` — выводит `title`, `description` и дополнительные `children`.\n- `TourWidget.Content` — область под изображение, видео, иллюстрацию или любой ReactNode.\n- `TourWidget.Footer` — произвольная зона для кнопок, ссылки пропуска и буллетов.\n- `TourWidget.Bullets` — контейнер, который рисует массив буллетов по `count`; если буллетов больше семи, отображает окно максимум на 7 точек, прокручивает его по `activeStepIndex`, а крайние видимые точки уменьшаются до `6px`, когда за ними есть скрытые шаги.\n- `TourWidget.Bullet` — низкоуровневый визуальный индикатор шага. Активность считается как `active ?? index === activeStepIndex`.\n\n## Правильная композиция\n\n`TourWidget.Header`, `TourWidget.Content` и `TourWidget.Footer` нужно вкладывать напрямую в `TourWidget`. Компонент использует эти части как слоты: так он понимает, есть ли в туре медиа-зона, и выбирает корректную раскладку для `horizontal` и `vertical`.\n\nПравильно:\n\n```tsx\n<TourWidget orientation=\"horizontal\">\n <TourWidget.Content>\n <Box as=\"img\" src={imageSrc} alt=\"\" $css={{ width: '100%' }} />\n </TourWidget.Content>\n <TourWidget.Header title=\"Title\" description=\"Description\" />\n <TourWidget.Footer>\n <TourWidget.Bullets count={steps.length} />\n </TourWidget.Footer>\n</TourWidget>\n```\n\nЕсли нужен свой wrapper для картинки, кнопок или текста, размещайте его внутри соответствующего slot-компонента.\n\n```tsx\n<TourWidget orientation=\"horizontal\">\n <TourWidget.Content>\n <MyImageWrapper>\n <Box as=\"img\" src={imageSrc} alt=\"\" />\n </MyImageWrapper>\n </TourWidget.Content>\n <TourWidget.Header>\n <MyHeaderContent />\n </TourWidget.Header>\n <TourWidget.Footer>\n <MyFooterContent />\n </TourWidget.Footer>\n</TourWidget>\n```\n\nНе оборачивайте сам `TourWidget.Content` во внешний компонент. В таком случае `TourWidget` не сможет определить медиа-зону как свой прямой slot и горизонтальная раскладка будет работать как вариант без `Content`.\n\n```tsx\n<TourWidget orientation=\"horizontal\">\n <MyContentWrapper>\n <TourWidget.Content>\n <Box as=\"img\" src={imageSrc} alt=\"\" />\n </TourWidget.Content>\n </MyContentWrapper>\n <TourWidget.Header title=\"Title\" />\n <TourWidget.Footer />\n</TourWidget>\n```\n\n## Активный шаг\n\n`activeStepIndex` хранится на корневом `TourWidget`. Внутри компонент создает локальный context, поэтому не нужно импортировать `Provider` или прокидывать `active` в каждый буллет.\n\n```tsx\n<TourWidget activeStepIndex={5}>\n <TourWidget.Footer>\n <TourWidget.Bullets count={10} />\n </TourWidget.Footer>\n</TourWidget>\n```\n\nДля переключения шагов используйте свои кнопки или другой внешний контрол. `TourWidget.Bullets` не кликабельный и только отображает `activeStepIndex`.\n\n```tsx\n<TourWidget activeStepIndex={activeStepIndex}>\n <TourWidget.Footer>\n <TourWidget.Bullets count={10} />\n <Button onClick={() => setActiveStepIndex((step) => step + 1)}>\n Далее\n </Button>\n </TourWidget.Footer>\n</TourWidget>\n```\n\nЕсли нужна полностью ручная раскладка или состояние отдельной точки, используйте низкоуровневый `TourWidget.Bullet` и передайте `active`.\n\n## Content\n\n`TourWidget.Content` не задает жесткий размер медиа. Размер определяет вложенная нода или стиль самого `Content`.\n\n```tsx\n<TourWidget.Content>\n <Box\n as=\"img\"\n src={imageSrc}\n alt=\"\"\n $css={{ width: '270px', height: '270px' }}\n />\n</TourWidget.Content>\n```\n\n## Пульсация\n\nПульсация не встроена в `TourWidget`, потому что target-элемент и позиционирование тура контролируются снаружи. Для target используется `tourPulseMixin`.\n\n```tsx\n\nconst Target = styled(Box)`\n position: relative;\n\n &::after {\n content: '';\n position: absolute;\n ${tourPulseMixin()}\n }\n`;\n```\n\nПо умолчанию `tourPulseMixin` сам задает `inset: -4px` и `border-radius: 16px` и не добавляет заливку на target.\n\n## Темная тема\n\n`TourWidget` всегда используется на темной поверхности. Если внутри футера есть SDDS-кнопки или ссылки, оборачивайте композицию в `ViewContainer view=\"onDark\"`, чтобы вложенные controls взяли on-dark токены без ручных переопределений цвета.\n\n```tsx\n<ViewContainer view=\"onDark\">\n <TourWidget activeStepIndex={activeStepIndex}>\n <TourWidget.Footer>\n <Button view=\"secondary\">Назад</Button>\n <Button view=\"white\">Далее</Button>\n </TourWidget.Footer>\n </TourWidget>\n</ViewContainer>\n```\n\n## CSS-переменные\n\nКорневой `$css` можно использовать для точечной настройки внешнего вида.\n\n```tsx\n<TourWidget\n $css={{\n '--tour-widget-min-width': '0',\n '--tour-widget-border-radius': '16px',\n '--tour-widget-gradient-frame-height': '34%',\n '--tour-widget-gradient-frame-fade': '56%',\n }}\n/>\n```\n\n## Особенности\n\n- `TourWidget` не содержит positioner и не добавляет зависимость на `floating-ui`.\n- Компонент не хранит шаги и не переключает их сам, только отображает `activeStepIndex`.\n- `TourWidget.Bullet` — это span-индикатор, а не интерактивная кнопка.\n- `TourWidget.Bullets` — это div-viewport со сдвигающимся треком точек; при `count > 7` видны максимум семь буллетов.\n\nОписание типов — в разделе [API](?path=/docs/локальные-компоненты-tourwidget-api--docs).",
38919
39204
  "apiDocs": "# TourWidget API\n\n## TourWidgetOrientation\n\n```typescript\ntype TourWidgetOrientation = 'vertical' | 'horizontal';\n```\n\n## TourWidgetCss\n\n```typescript\ntype TourWidgetCss = string | CSSObject | FlattenSimpleInterpolation;\n```\n\n## TourWidgetProps\n\n```typescript\ntype TourWidgetProps = ComponentPropsWithoutRef<'div'> & {\n /**\n * @default 'vertical'\n */\n orientation?: TourWidgetOrientation;\n /**\n * Активный шаг тура. Нумерация с нуля.\n */\n activeStepIndex?: number;\n $css?: TourWidgetCss;\n};\n```\n\n## TourWidget.Header\n\n```typescript\ntype TourWidgetHeaderProps = Omit<\n ComponentPropsWithoutRef<'div'>,\n 'title'\n> & {\n title?: ReactNode;\n description?: ReactNode;\n $css?: TourWidgetCss;\n};\n```\n\n## TourWidget.Content\n\n```typescript\ntype TourWidgetContentProps = ComponentPropsWithoutRef<'div'> & {\n children?: ReactNode;\n $css?: TourWidgetCss;\n};\n```\n\n## TourWidget.Footer\n\n```typescript\ntype TourWidgetFooterProps = ComponentPropsWithoutRef<'div'> & {\n children?: ReactNode;\n $css?: TourWidgetCss;\n};\n```\n\n## TourWidget.Bullets\n\n```typescript\ntype TourWidgetBulletsProps = Omit<\n ComponentPropsWithoutRef<'div'>,\n 'children' | 'onClick'\n> & {\n count: number;\n $css?: TourWidgetCss;\n};\n```\n\n## TourWidget.Bullet\n\n```typescript\ntype TourWidgetBulletProps = Omit<\n ComponentPropsWithoutRef<'span'>,\n 'onClick'\n> & {\n /**\n * Индекс буллета. Сравнивается с `TourWidget.activeStepIndex`.\n */\n index?: number;\n /**\n * Ручное переопределение активного состояния.\n */\n active?: boolean;\n $css?: TourWidgetCss;\n};\n```",
38920
39205
  "curatedStories": [
38921
39206
  {
@@ -38930,6 +39215,12 @@
38930
39215
  "type": "full-code",
38931
39216
  "code": "function HorizontalExample() {\n const tourStepsCount = 14;\n const [activeStepIndex, setActiveStepIndex] = useState(5);\n\n return (\n <TourView>\n <TourWidget\n orientation=\"horizontal\"\n activeStepIndex={activeStepIndex}\n $css={{ width: '720px', height: '260px' }}\n >\n <TourWidget.Content>\n <MediaPlaceholder width={240} height={240} />\n </TourWidget.Content>\n <TourWidget.Header title=\"Title\" description=\"Description\" />\n <TourWidget.Footer>\n <Box\n $css={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: '32px',\n width: '100%',\n }}\n >\n <Box\n $css={{\n display: 'flex',\n alignItems: 'center',\n gap: '32px',\n minWidth: 0,\n }}\n >\n <LinkButton\n size=\"s\"\n view=\"default\"\n onClick={() => setActiveStepIndex(0)}\n >\n Пропустить всё\n </LinkButton>\n <TourWidget.Bullets count={tourStepsCount} />\n </Box>\n <Box\n $css={{\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n }}\n >\n <Button\n size=\"s\"\n view=\"secondary\"\n onClick={() =>\n setActiveStepIndex((current) =>\n clampStep(current - 1, tourStepsCount),\n )\n }\n >\n Назад\n </Button>\n <Button\n size=\"s\"\n view=\"white\"\n onClick={() =>\n setActiveStepIndex((current) =>\n clampStep(current + 1, tourStepsCount),\n )\n }\n >\n Далее\n </Button>\n </Box>\n </Box>\n </TourWidget.Footer>\n </TourWidget>\n </TourView>\n );\n};"
38932
39217
  },
39218
+ {
39219
+ "exportName": "LineBreaks",
39220
+ "displayName": "Переносы строк",
39221
+ "type": "full-code",
39222
+ "code": "function LineBreaksExample() {\n return (\n <TourView>\n <TourWidget $css={{ width: '320px', paddingBottom: '24px' }}>\n <TourWidget.Header\n title={'Знакомьтесь:\\nновые возможности'}\n description={\n 'Режимы просмотра\\nОбщий реестр — все пилоты со статусом «В реестре»\\n• Мои пилоты — только ваши проекты, включая черновики'\n }\n />\n </TourWidget>\n </TourView>\n );\n};"
39223
+ },
38933
39224
  {
38934
39225
  "exportName": "TourWithPulse",
38935
39226
  "displayName": "Тур рядом с пульсацией",
@@ -38975,16 +39266,16 @@
38975
39266
  "code": "function HorizontalExample() {\n const tourStepsCount = 14;\n const [activeStepIndex, setActiveStepIndex] = useState(5);\n\n return (\n <TourView>\n <TourWidget\n orientation=\"horizontal\"\n activeStepIndex={activeStepIndex}\n $css={{ width: '720px', height: '260px' }}\n >\n <TourWidget.Content>\n <MediaPlaceholder width={240} height={240} />\n </TourWidget.Content>\n <TourWidget.Header title=\"Title\" description=\"Description\" />\n <TourWidget.Footer>\n <Box\n $css={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: '32px',\n width: '100%',\n }}\n >\n <Box\n $css={{\n display: 'flex',\n alignItems: 'center',\n gap: '32px',\n minWidth: 0,\n }}\n >\n <LinkButton\n size=\"s\"\n view=\"default\"\n onClick={() => setActiveStepIndex(0)}\n >\n Пропустить всё\n </LinkButton>\n <TourWidget.Bullets count={tourStepsCount} />\n </Box>\n <Box\n $css={{\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n }}\n >\n <Button\n size=\"s\"\n view=\"secondary\"\n onClick={() =>\n setActiveStepIndex((current) =>\n clampStep(current - 1, tourStepsCount),\n )\n }\n >\n Назад\n </Button>\n <Button\n size=\"s\"\n view=\"white\"\n onClick={() =>\n setActiveStepIndex((current) =>\n clampStep(current + 1, tourStepsCount),\n )\n }\n >\n Далее\n </Button>\n </Box>\n </Box>\n </TourWidget.Footer>\n </TourWidget>\n </TourView>\n );\n};"
38976
39267
  },
38977
39268
  {
38978
- "exportName": "TourWithPulse",
38979
- "displayName": "Тур рядом с пульсацией",
39269
+ "exportName": "LineBreaks",
39270
+ "displayName": "Переносы строк",
38980
39271
  "type": "full-code",
38981
- "code": "function TourWithPulseExample() {\n const tourStepsCount = 14;\n const [activeStepIndex, setActiveStepIndex] = useState(2);\n\n return (\n <TourView>\n <Box\n $css={{\n display: 'grid',\n gridTemplateColumns: '220px minmax(0, max-content)',\n gap: '14px',\n alignItems: 'center',\n }}\n >\n <Box\n $css={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: '300px',\n }}\n >\n <PulseTarget />\n </Box>\n <TourWidget\n orientation=\"horizontal\"\n activeStepIndex={activeStepIndex}\n $css={{ width: '720px', height: '264px' }}\n >\n <TourWidget.Content>\n <MediaPlaceholder width={240} height={240} />\n </TourWidget.Content>\n <TourWidget.Header title=\"Title\" description=\"Description\" />\n <TourWidget.Footer>\n <Box\n $css={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: '32px',\n width: '100%',\n }}\n >\n <Box\n $css={{\n display: 'flex',\n alignItems: 'center',\n gap: '32px',\n minWidth: 0,\n }}\n >\n <LinkButton\n size=\"s\"\n view=\"default\"\n onClick={() => setActiveStepIndex(0)}\n >\n Пропустить всё\n </LinkButton>\n <TourWidget.Bullets count={tourStepsCount} />\n </Box>\n <Box\n $css={{\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n }}\n >\n <Button\n size=\"s\"\n view=\"secondary\"\n onClick={() =>\n setActiveStepIndex((current) =>\n clampStep(current - 1, tourStepsCount),\n )\n }\n >\n Назад\n </Button>\n <Button\n size=\"s\"\n view=\"white\"\n onClick={() =>\n setActiveStepIndex((current) =>\n clampStep(current + 1, tourStepsCount),\n )\n }\n >\n Далее\n </Button>\n </Box>\n </Box>\n </TourWidget.Footer>\n </TourWidget>\n </Box>\n </TourView>\n );\n};"
39272
+ "code": "function LineBreaksExample() {\n return (\n <TourView>\n <TourWidget $css={{ width: '320px', paddingBottom: '24px' }}>\n <TourWidget.Header\n title={'Знакомьтесь:\\nновые возможности'}\n description={\n 'Режимы просмотра\\nОбщий реестр — все пилоты со статусом «В реестре»\\n• Мои пилоты — только ваши проекты, включая черновики'\n }\n />\n </TourWidget>\n </TourView>\n );\n};"
38982
39273
  },
38983
39274
  {
38984
- "exportName": "Pulse",
38985
- "displayName": "Пульсация",
39275
+ "exportName": "TourWithPulse",
39276
+ "displayName": "Тур рядом с пульсацией",
38986
39277
  "type": "full-code",
38987
- "code": "function PulseExample() {\n return (\n <TourView>\n <Box\n $css={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: '300px',\n }}\n >\n <PulseTarget />\n </Box>\n </TourView>\n );\n};"
39278
+ "code": "function TourWithPulseExample() {\n const tourStepsCount = 14;\n const [activeStepIndex, setActiveStepIndex] = useState(2);\n\n return (\n <TourView>\n <Box\n $css={{\n display: 'grid',\n gridTemplateColumns: '220px minmax(0, max-content)',\n gap: '14px',\n alignItems: 'center',\n }}\n >\n <Box\n $css={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: '300px',\n }}\n >\n <PulseTarget />\n </Box>\n <TourWidget\n orientation=\"horizontal\"\n activeStepIndex={activeStepIndex}\n $css={{ width: '720px', height: '264px' }}\n >\n <TourWidget.Content>\n <MediaPlaceholder width={240} height={240} />\n </TourWidget.Content>\n <TourWidget.Header title=\"Title\" description=\"Description\" />\n <TourWidget.Footer>\n <Box\n $css={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: '32px',\n width: '100%',\n }}\n >\n <Box\n $css={{\n display: 'flex',\n alignItems: 'center',\n gap: '32px',\n minWidth: 0,\n }}\n >\n <LinkButton\n size=\"s\"\n view=\"default\"\n onClick={() => setActiveStepIndex(0)}\n >\n Пропустить всё\n </LinkButton>\n <TourWidget.Bullets count={tourStepsCount} />\n </Box>\n <Box\n $css={{\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n }}\n >\n <Button\n size=\"s\"\n view=\"secondary\"\n onClick={() =>\n setActiveStepIndex((current) =>\n clampStep(current - 1, tourStepsCount),\n )\n }\n >\n Назад\n </Button>\n <Button\n size=\"s\"\n view=\"white\"\n onClick={() =>\n setActiveStepIndex((current) =>\n clampStep(current + 1, tourStepsCount),\n )\n }\n >\n Далее\n </Button>\n </Box>\n </Box>\n </TourWidget.Footer>\n </TourWidget>\n </Box>\n </TourView>\n );\n};"
38988
39279
  }
38989
39280
  ]
38990
39281
  },
@@ -45223,6 +45514,12 @@
45223
45514
  "description": "Отступ календаря относительно поля ввода.",
45224
45515
  "default": "[0, 2]"
45225
45516
  },
45517
+ {
45518
+ "name": "onChangeVisibleDate",
45519
+ "type": "((date: Date) => void) | undefined",
45520
+ "required": false,
45521
+ "description": "Обработчик изменения отображаемых месяца или года при навигации по календарю."
45522
+ },
45226
45523
  {
45227
45524
  "name": "onToggle",
45228
45525
  "type": "((isOpen: boolean, event?: Event | React.SyntheticEvent<Element, Event> | undefined) => void) | undefined",
@@ -45259,7 +45556,7 @@
45259
45556
  "name": "stretched",
45260
45557
  "type": "boolean | undefined",
45261
45558
  "required": false,
45262
- "description": "Растянуть поле ввода на всю доступную ширину"
45559
+ "description": "Растянуть поле ввода на всю доступную ширину, а календарь — на всю доступную ширину и высоту"
45263
45560
  },
45264
45561
  {
45265
45562
  "name": "type",
@@ -45710,6 +46007,12 @@
45710
46007
  "description": "Отступ календаря относительно поля ввода.",
45711
46008
  "default": "[0, 0]"
45712
46009
  },
46010
+ {
46011
+ "name": "onChangeVisibleDate",
46012
+ "type": "((date: Date) => void) | undefined",
46013
+ "required": false,
46014
+ "description": "Обработчик изменения отображаемых месяца или года при навигации по календарю."
46015
+ },
45713
46016
  {
45714
46017
  "name": "onToggle",
45715
46018
  "type": "((isOpen: boolean, event?: Event | React.SyntheticEvent<Element, Event> | undefined) => void) | undefined",
@@ -45738,7 +46041,7 @@
45738
46041
  "name": "stretched",
45739
46042
  "type": "boolean | undefined",
45740
46043
  "required": false,
45741
- "description": "Растянуть поле ввода на всю доступную ширину"
46044
+ "description": "Растянуть поле ввода на всю доступную ширину, а календарь — на всю доступную ширину и высоту"
45742
46045
  },
45743
46046
  {
45744
46047
  "name": "type",
@@ -46615,6 +46918,12 @@
46615
46918
  "description": "Задает выравнивание индикатора обязательности поля",
46616
46919
  "default": "right"
46617
46920
  },
46921
+ {
46922
+ "name": "suffix",
46923
+ "type": "string | undefined",
46924
+ "required": false,
46925
+ "description": "Суффикс текста в поле ввода."
46926
+ },
46618
46927
  {
46619
46928
  "name": "thousandSeparator",
46620
46929
  "type": "string | boolean | undefined",
@@ -47124,6 +47433,13 @@
47124
47433
  "required": true,
47125
47434
  "description": ""
47126
47435
  },
47436
+ {
47437
+ "name": "clip",
47438
+ "type": "boolean | undefined",
47439
+ "required": false,
47440
+ "description": "При ограничении ширины разрешает скролл и отображает дополнительные элементы со стрелками",
47441
+ "default": "true"
47442
+ },
47127
47443
  {
47128
47444
  "name": "filledBackground",
47129
47445
  "type": "boolean | undefined",
@@ -47225,14 +47541,6 @@
47225
47541
  "type": "React.ReactNode",
47226
47542
  "required": false,
47227
47543
  "description": ""
47228
- },
47229
- {
47230
- "name": "clip",
47231
- "type": "boolean | undefined",
47232
- "required": false,
47233
- "description": "При ограничении ширины разрешает скролл и отображает дополнительные элементы со стрелками",
47234
- "deprecated": true,
47235
- "default": "true"
47236
47544
  }
47237
47545
  ],
47238
47546
  "propsTypeName": "FormSegmentGroupProps",
@@ -49600,6 +49908,13 @@
49600
49908
  "required": false,
49601
49909
  "description": "Контент справа"
49602
49910
  },
49911
+ {
49912
+ "name": "disableScroll",
49913
+ "type": "boolean | undefined",
49914
+ "required": false,
49915
+ "description": "Отключает скролл к TabItem при его выборе",
49916
+ "default": "false"
49917
+ },
49603
49918
  {
49604
49919
  "name": "itemIndex",
49605
49920
  "type": "number | undefined",
@@ -49639,7 +49954,7 @@
49639
49954
  },
49640
49955
  {
49641
49956
  "name": "size",
49642
- "type": "\"s\" | \"xs\" | \"m\" | \"l\" | \"h6\" | \"h5\" | \"h4\" | \"h3\" | \"h2\" | \"h1\" | undefined",
49957
+ "type": "\"s\" | \"xs\" | \"m\" | \"h6\" | \"h5\" | \"h4\" | \"h3\" | \"h2\" | \"h1\" | \"l\" | undefined",
49643
49958
  "required": false,
49644
49959
  "description": ""
49645
49960
  },
@@ -49747,6 +50062,14 @@
49747
50062
  "type": "string | undefined",
49748
50063
  "required": false,
49749
50064
  "description": "Вид табов"
50065
+ },
50066
+ {
50067
+ "name": "pilled",
50068
+ "type": "boolean | undefined",
50069
+ "required": false,
50070
+ "description": "Табы c округлым border-radius",
50071
+ "deprecated": true,
50072
+ "default": "false"
49750
50073
  }
49751
50074
  ],
49752
50075
  "propsTypeName": "ComponentProps<typeof FiltersActionsTabs>",
@@ -50577,6 +50900,14 @@
50577
50900
  "type": "string | undefined",
50578
50901
  "required": false,
50579
50902
  "description": "Вид табов"
50903
+ },
50904
+ {
50905
+ "name": "pilled",
50906
+ "type": "boolean | undefined",
50907
+ "required": false,
50908
+ "description": "Табы c округлым border-radius",
50909
+ "deprecated": true,
50910
+ "default": "false"
50580
50911
  }
50581
50912
  ]
50582
50913
  },
@@ -50608,6 +50939,13 @@
50608
50939
  "required": false,
50609
50940
  "description": "Контент справа"
50610
50941
  },
50942
+ {
50943
+ "name": "disableScroll",
50944
+ "type": "boolean | undefined",
50945
+ "required": false,
50946
+ "description": "Отключает скролл к TabItem при его выборе",
50947
+ "default": "false"
50948
+ },
50611
50949
  {
50612
50950
  "name": "itemIndex",
50613
50951
  "type": "number | undefined",
@@ -50647,7 +50985,7 @@
50647
50985
  },
50648
50986
  {
50649
50987
  "name": "size",
50650
- "type": "\"s\" | \"xs\" | \"m\" | \"l\" | \"h6\" | \"h5\" | \"h4\" | \"h3\" | \"h2\" | \"h1\" | undefined",
50988
+ "type": "\"s\" | \"xs\" | \"m\" | \"h6\" | \"h5\" | \"h4\" | \"h3\" | \"h2\" | \"h1\" | \"l\" | undefined",
50651
50989
  "required": false,
50652
50990
  "description": ""
50653
50991
  },
@@ -51896,6 +52234,12 @@
51896
52234
  "displayName": "Default",
51897
52235
  "type": "full-code",
51898
52236
  "code": "import { Canvas, ColumnConfig, TableCanvas } from '@daisforge/ui/components/TableCanvas';\n\nconst columnConfig: ColumnConfig[] = [\n {\n key: 'status',\n name: 'Статус',\n width: 120,\n renderCell: ({ row }) => (\n <Canvas.Container direction=\"row\" alignItems=\"center\" padding={8}>\n <Canvas.Badge text={row.status} view=\"accent\" size=\"s\" />\n </Canvas.Container>\n ),\n },\n];\n\n<TableCanvas\n tableConfig={{ containerStyle: { height: '400px' } }}\n columnConfig={columnConfig}\n rows={rows}\n/>"
52237
+ },
52238
+ {
52239
+ "exportName": "IconOnly",
52240
+ "displayName": "Only Icon",
52241
+ "type": "full-code",
52242
+ "code": "import { Canvas, ColumnConfig, TableCanvas } from '@daisforge/ui/components/TableCanvas';\nimport { IconSearch } from '@daisforge/ui/icons';\n\nconst icon = Canvas.icon(<IconSearch />);\n\nconst columnConfig: ColumnConfig[] = [\n {\n key: 'badge',\n name: 'Бейдж',\n width: 120,\n renderCell: ({ row }) => (\n <Canvas.Container direction=\"row\" alignItems=\"center\" padding={8}>\n <Canvas.Badge text=\"\" leftIcon={icon} view={row.view} size=\"s\" />\n </Canvas.Container>\n ),\n },\n];\n\n<TableCanvas\n tableConfig={{ containerStyle: { height: '400px' } }}\n columnConfig={columnConfig}\n rows={rows}\n/>"
51899
52243
  }
51900
52244
  ]
51901
52245
  },
@@ -52132,8 +52476,8 @@
52132
52476
  "feature": "CellsMerging",
52133
52477
  "legacy": false,
52134
52478
  "summary": "Объединение ячеек тела таблицы: по строкам (rowSpan), по колонкам (colSpan) и",
52135
- "docs": "# CellsMerging (TableCanvas)\n\nОбъединение ячеек тела таблицы: по строкам (rowSpan), по колонкам (colSpan) и\nпрямоугольными блоками. Несколько одинаковых ячеек рисуются одной большой, а всё\nвзаимодействие — клики, выделение, навигация, копирование, вставка, протяжка,\nредактирование — обращается с блоком как с одной ячейкой.\n\nЭта страница — обзор: как выбрать способ и с чего начать, плюс живые примеры.\nПодробности (совмещение способов, работа с деревом, выравнивание, сводные\nограничения) — в\n[Справочнике](?path=/docs/локальные-компоненты-tablecanvas-cellsmerging-справочник--docs),\nтипы — в\n[API](?path=/docs/локальные-компоненты-tablecanvas-cellsmerging-api--docs).\n\n## Как это устроено\n\nГлавная идея простая: объединение — это способ показа, а не способ хранения.\n\n- В данных значение повторяется в каждой строке блока. Если «Отдел А» тянется на\n три строки, то во всех трёх строках в поле отдела записано «Отдел А».\n- Таблица замечает повторы (или получает границы блока явно) и вместо трёх\n одинаковых ячеек рисует одну высокую. Содержимое берётся из верхней-левой\n ячейки блока.\n- Данные при этом не меняются. Уберите объединение — увидите те же строки с теми\n же значениями.\n\nОтсюда следует и поведение, знакомое по Excel: клик в любую точку блока выделяет\nблок целиком, правка блока меняет значение во всех его строках, копирование\nотдаёт значение один раз.\n\n## Три способа включить объединение\n\nМеханика под всеми способами одна. Отличие — кто вычисляет границы блоков:\nпотребитель или таблица. Способы можно совмещать в одной таблице — правила в\nСправочнике, глава «Если включено несколько способов сразу».\n\n### 1. mergeCells.mergedCellsRegions — блоки, заданные снаружи\n\n«Слей вот эти конкретные ячейки». Список блоков по стабильным ключам строк и\nколонок; списком владеет потребитель, как выделением. Таблица переводит ключи в\nтекущие видимые позиции. Если сортировка, перестановка или скрытие колонки\nразорвали блок — он не рисуется (как ограничение сортировки в Excel).\n\n```tsx\ntableConfig={{\n mergeCells: {\n mergedCellsRegions: [\n { rowKeys: ['r1', 'r2'], colKeys: ['dept'] },\n { rowKeys: ['r4', 'r5'], colKeys: ['plan', 'fact'] }, // прямоугольник 2×2\n ],\n rowKeyGetter: (row) => row.id,\n },\n}}\n```\n\nПримеры — стори с префиксом `mergedCellsRegions:` ниже.\n\n### 2. mergeCells.mergeByCellValues — по одинаковым значениям\n\n«В этих колонках сливай подряд идущие одинаковые значения». Границы блоков\nтаблица вычисляет сама из данных; после сортировки или фильтра блоки\nпересобираются.\n\n```tsx\ntableConfig={{\n mergeCells: {\n mergeByCellValues: [\n 'dept', // по значению колонки\n { colKey: 'role', value: (row) => row.roleGroup }, // по своей функции\n ],\n },\n}}\n```\n\nОдинаковые названия в разных ветках иерархии могут ложно слиться — лечится\nсоставным ключом, разбор в Справочнике, глава «Объединение по значению: где\nпроходит граница». Примеры — стори с префиксом `mergeByCellValues:` ниже.\n\n### 3. Merged-виды группировки и subRows — полный автомат\n\nПотребитель включает вид — всю работу с блоками делает таблица: строки\nупорядочиваются по группам, колонки уровней сливаются по границам групп, чекбокс\nи нумерация работают по верхней группе.\n\nЧерез группировку (структуру задают значения группирующих колонок):\n\n```tsx\ntableConfig={{\n rowsGrouping: {\n view: 'merged',\n groupByState: [groupBy, setGroupBy], // например ['dept', 'role']\n rowKeyGetter: (row) => row.id,\n },\n}}\n```\n\nЧерез subRows (структуру задаёт готовое дерево потребителя):\n\n```tsx\ntableConfig={{\n subRows: {\n view: 'merged',\n mergedColumns: ['dept', 'role'], // колонки уровней дерева\n getSubRows: (row) => row.children,\n rowKeyGetter: (row) => row.id,\n },\n}}\n```\n\nПримеры — «subRows: дерево с пагинацией» и «rowsGrouping: группировка\nпользователем» в конце страницы.\n\n## Какой способ выбрать\n\nКартинка у способов похожая, поэтому выбирать стоит не по внешнему виду, а по\nтому, кто владеет данными и что нужно пользователю.\n\n### Дерево приходит с сервера, нужна постраничная загрузка — subRows\n\nЕсли данные уже иерархические (дивизион, управление, команда, сотрудники) и\nприходят от сервера частями, берите `subRows` с `view: 'merged'`. Дерево остаётся\nу вас: вы отдаёте таблице страницу дерева, она разворачивает её в строки и сама\nсливает колонки-предки. Именно поэтому здесь работает пагинация по верхним\nблокам — таблице не нужно видеть все данные сразу.\n\nОбратная сторона: раз данными владеете вы, то поиск, сортировка и фильтрация\nдерева — тоже на вашей стороне. Формат дерева, пагинация и возврат правок —\nв Справочнике, глава «Дерево через subRows».\n\n### Плоские строки, пользователь сам выбирает группировку — rowsGrouping\n\nЕсли строки плоские, а пользователь должен на лету решать, по каким колонкам\nгруппировать, — берите `rowsGrouping` с `view: 'merged'`. Состав группировки живёт\nв `groupByState`, а с настройкой `groupButton` в блоке управления появляется\nкнопка: пользователь сам выбирает колонки, таблица пересобирает блоки. Встроенные\nпоиск, сортировка и фильтры работают — таблица применяет их до сборки групп.\n\nОбратная сторона: пагинации в этом виде нет — таблице нужны все строки сразу.\nНе действует и всё, что привязано к строкам-групп и шевронам дерева\n(`groupedColumnProps`, `renderGroupCell`, `expandAllBtn`) — полный список в\nСправочнике, глава «Что не работает и почему».\n\n### Плоские строки, группировка фиксированная, всё считает сервер — mergeByCellValues\n\nЕсли структура известна заранее и не меняется пользователем, а данные (включая\nстраницы, сортировку и фильтры) готовит сервер, — самый прямой путь это\n`mergeByCellValues`. Вы упорядочиваете строки как нужно, таблица сливает соседние\nодинаковые значения. Никакой лишней механики: ни кнопок, ни дерева.\n\n### Отдельные ручные блоки — mergedCellsRegions\n\nШапки секций внутри таблицы, нестандартные прямоугольники, объединение по кнопке\nили из контекстного меню — всё, что не выводится из значений, делается регионами.\nПотребитель добавляет блок в свой список — таблица его рисует.\n\n## Смежные разделы\n\n- [Справочник](?path=/docs/локальные-компоненты-tablecanvas-cellsmerging-справочник--docs) —\n совмещение способов, составные ключи, дерево, выравнивание, сводные ограничения.\n- [CellsMerging API](?path=/docs/локальные-компоненты-tablecanvas-cellsmerging-api--docs) —\n типы.\n- Объединение ячеек шапки — раздел ColumnsGrouping (`squashEmptyCells`).\n\n## Полные примеры\n\nТри больших примера ниже собраны как заготовки для продуктов: в каждом —\nобъединение ячеек в связке с поиском, сортировкой, фильтрами, пагинацией,\nредактированием и выделением. Различаются они тем, кто владеет данными, поэтому\nи код обвязки разный. Полный код каждого примера открывается кнопкой «Show code»\nи снабжён комментариями по ключевым местам.\n\n### mergeByCellValues: пример с серверными данными\n\nДанные плоские, всё считает «сервер» (в примере его заменяет функция\n`selectPage`), таблица только рисует полученную страницу.\n\nЧто здесь показано:\n\n- поиск, фильтры, сортировка и пагинация в `manual`-режиме — считает потребитель;\n- составные ключи пути (`divPath` / `unitPath` / `teamPath`) против ложного\n слияния одинаковых имён из разных веток;\n- сортировка внутри команды — блоки не рассыпаются;\n- закрепление колонок вместе с групповой шапкой;\n- редактирование с возвратом правок страницы в полный набор.\n\n<Canvas of={CellsMergingExamples.Showcase} />\n\n### subRows: дерево с пагинацией\n\nДанные — дерево, и оно остаётся у потребителя: таблице отдаётся страница целых\nподдеревьев.\n\nЧто здесь показано:\n\n- пагинация по верхним блокам (дивизионам) со своим списком «показывать по»;\n- `manual`-поиск, сортировка и фильтры, посчитанные по дереву\n (функция `selectTreePage`);\n- сортировка показателей внутри команды и перестановка веток по имени;\n- возврат правок листьев обратно в дерево.\n\n<Canvas of={CellsMergingExamples.SubRowsMerged} />\n\n### rowsGrouping: группировка пользователем\n\nДанные плоские и передаются целиком, остальное делает таблица. Самый короткий\nкод из трёх.\n\nЧто здесь показано:\n\n- встроенные поиск, сортировка и фильтры — применяются до сборки групп;\n- выбор состава группировки пользователем (кнопка `groupButton`);\n- полный стейт фильтров: ключ на каждый фильтр из колонок;\n- без пагинации — чтобы собрать группы, таблице нужны все строки сразу.\n\n<Canvas of={CellsMergingExamples.GroupingMerged} />\n\n## Как перенести пример к себе\n\n1. Замените данные и типы строк на свои. Сохраните стабильный `id` строки — на\n нём держатся выделение и возврат правок, между страницами он меняться не\n должен.\n2. Замените `selectPage` / `selectTreePage` реальным запросом к серверу. Контракт\n тот же: параметры выборки на входе, страница и общее количество на выходе.\n3. Проверьте, что в `filtering.state` есть ключ каждого фильтра из колонок (со\n значением «показать всё»), — селект-фильтр без своего ключа молча отсеет все\n строки.\n4. Для `mergeByCellValues` заведите составные ключи пути, если одинаковые\n названия возможны в разных ветках иерархии.\n5. Уберите фичи, которые вам не нужны, — настройки в примерах независимы друг от\n друга: пагинация, закрепление, чекбоксы, редактирование отключаются по\n отдельности.\n\n# CellsMerging: справочник\n\nПодробности объединения ячеек: совмещение способов, составные ключи, работа с\nдеревом, взаимодействие с остальными фичами таблицы, выравнивание и сводный\nсписок ограничений. Обзор способов и живые примеры — на странице\n[Docs](?path=/docs/локальные-компоненты-tablecanvas-cellsmerging--docs), типы —\nна странице\n[API](?path=/docs/локальные-компоненты-tablecanvas-cellsmerging-api--docs).\n\n## Если включено несколько способов сразу\n\nСпособы можно совмещать в одной таблице — правила простые и считаются по колонке:\n\n- Если колонка входит хотя бы в один регион из `mergedCellsRegions`, её\n объединения описывают только регионы. `mergeByCellValues` на этой колонке не\n действует.\n- Колонка merged-вида (группировки или subRows) сливается по границам групп.\n Пользовательский `mergeByCellValues` на той же колонке не действует — иначе два\n механизма спорили бы за одни ячейки.\n- В остальных случаях работает `mergeByCellValues`.\n- Разные колонки живут независимо: регион на одной колонке и слияние по значению\n на другой — обычная рабочая комбинация.\n\nПример: таблица с группировкой по «Отделу» (merged-вид) может дополнительно\nсливать колонку «Статус» через `mergeByCellValues`, а строки-заголовки секций\nрисовать регионами на всю ширину — все три способа уживаются, потому что заняты\nразными колонками.\n\n## Объединение по значению: где проходит граница\n\nУ `mergeByCellValues` есть классическая ловушка. Допустим, регионы «Север» и «Юг»,\nи в каждом есть «Команда 1» и «Команда 2»:\n\n```\nСевер | Команда 1 | Иванов\nСевер | Команда 2 | Петров\nЮг | Команда 2 | Сидоров\nЮг | Команда 1 | Смирнов\n```\n\nЕсли сливать колонку команды по её значению, «Команда 2» из Севера и «Команда 2»\nиз Юга стоят рядом — и сольются в один блок через границу региона. Визуально это\nвыглядит как ошибка: одна команда, а на деле две разные.\n\nРешение — сливать не по тексту в ячейке, а по составному ключу, в котором зашит\nпуть от корня:\n\n```tsx\nmergeCells: {\n mergeByCellValues: [\n 'region',\n // Сравнивается результат функции, а не текст в ячейке.\n { colKey: 'team', value: (row) => `${row.region} / ${row.team}` },\n ],\n}\n```\n\nТеперь у «Команды 2» из Севера ключ «Север / Команда 2», а у южной —\n«Юг / Команда 2». Ключи разные, слияние останавливается на границе региона само,\nбез какой-либо отдельной логики. В ячейке при этом показывается обычное значение\nколонки — функция влияет только на сравнение.\n\nВ полном примере (стори «mergeByCellValues: пример с серверными данными») такие\nключи собраны заранее в полях строки: `divPath`, `unitPath`, `teamPath` — по\nодному на каждый уровень иерархии.\n\nMerged-виды группировки и subRows строят такие ключи сами — там об этой ловушке\nдумать не нужно.\n\n## Дерево через subRows: как передавать данные\n\nРазберём подробнее самый ёмкий сценарий — `subRows` с `view: 'merged'`.\n\n### Какое дерево ждёт таблица\n\nВ `rows` передаются корневые узлы, детей таблица достаёт через `getSubRows`.\nРоли узлов распределены так:\n\n- **Внутренние узлы** (дивизион, управление, команда) — ярлыки уровней. Каждый\n несёт поле с именем своей колонки из `mergedColumns`: узел дивизиона — поле\n `division`, узел управления — поле `unit`, и так далее.\n- **Листья** — строки данных. Именно они становятся строками таблицы со своими\n показателями; внутренние узлы отдельными строками не показываются.\n\n```tsx\nconst tree = [\n {\n id: 'd1',\n division: 'Розничный бизнес', // узел уровня 0\n subRows: [\n {\n id: 'u1',\n unit: 'Управление продаж', // узел уровня 1\n subRows: [\n {\n id: 't1',\n team: 'Команда Север', // узел уровня 2\n subRows: [\n { id: 'e1', employee: 'Иванов', plan: 100, fact: 90 }, // лист\n { id: 'e2', employee: 'Петров', plan: 80, fact: 85 },\n ],\n },\n ],\n },\n ],\n },\n];\n```\n\n```tsx\ntableConfig={{\n subRows: {\n view: 'merged',\n mergedColumns: ['division', 'unit', 'team'], // порядок = уровни дерева\n getSubRows: (row) => row.subRows,\n rowKeyGetter: (row) => row.id,\n },\n}}\n```\n\n`mergedColumns` — это соответствие уровней дерева и колонок: первый элемент\nпоказывает узлы верхнего уровня, второй — следующего, и так далее. Колонка\n`division` возьмёт значение из узла дивизиона и сольётся на все его листья,\n`unit` — на листья своего управления, вложенно.\n\nСворачивания в этом виде нет: таблица показывает всё переданное дерево целиком.\nХотите меньше строк на экране — передайте меньший кусок дерева (следующий\nраздел).\n\n### Пагинация по верхним блокам\n\nДерево у вас, поэтому страницы нарезаете вы — по верхним узлам. Таблице отдаётся\nсрез дерева, а в `pagination.count` — общее число верхних узлов:\n\n```tsx\nconst [page, setPage] = useState(1);\nconst [perPage, setPerPage] = useState(2); // дивизионов на страницу\nconst pageTree = tree.slice((page - 1) * perPage, page * perPage);\n\ntableConfig={{\n pagination: {\n count: tree.length, // всего верхних узлов, не листьев\n perPage,\n perPageList: [1, 2, 3], // варианты «показывать по» — в блоках\n value: page,\n onChange: (nextPage, nextPerPage) => {\n if (typeof nextPerPage === 'number' && nextPerPage !== perPage) {\n setPerPage(nextPerPage);\n setPage(1);\n } else if (typeof nextPage === 'number') {\n setPage(nextPage);\n }\n },\n },\n subRows: { /* как выше */ },\n}}\n// ...\nrows={pageTree}\n```\n\nСтраница «2 дивизиона» может содержать разное число строк-листьев — это нормально:\nединица пагинации здесь блок, а не строка. По той же причине настройте селектор\n«Показывать по»: его стандартные варианты (20/50/100) рассчитаны на строки и для\nблоков не имеют смысла — задайте свой список `perPageList` в блоках, как выше,\nлибо спрячьте селектор (`hasPerPage: false`). Если дерево приходит с сервера\nчастями, вместо `slice` будет запрос следующей страницы — контракт тот же.\n\n### Редактирование: правки возвращаются листьями\n\nРедактируются листья. В `editing.onRowsChange` приходят изменённые строки-листья —\nзаписать их обратно в своё дерево должен потребитель, например по `id`:\n\n```tsx\nediting: {\n rowKeyGetter: (r) => r.id,\n onRowsChange: (updatedLeaves) => {\n const byId = new Map(updatedLeaves.map((r) => [r.id, r]));\n // Обойдите дерево и замените листья с совпавшими id.\n setTree((prev) => writeLeavesBack(prev, byId));\n },\n},\n```\n\nЭто следствие владения данными: таблица не знает, как устроено ваше дерево,\nпоэтому отдаёт плоский результат, а раскладываете его вы.\n\n### Что остаётся на вашей стороне\n\n- **Поиск, сортировка, фильтрация** — встроенные механизмы к структурному дереву\n пока не применяются. Отфильтровали или отсортировали своё дерево — передали\n результат в `rows`, таблица показала.\n- **Выделение** при этом работает из коробки: один чекбокс на верхний блок, клик\n выделяет все его листья (подробнее — в разделе про выделение ниже).\n\nЖивой пример всего вместе — стори «subRows: дерево с пагинацией» на странице\n[Docs](?path=/docs/локальные-компоненты-tablecanvas-cellsmerging--docs).\n\n## Объединение и остальные возможности таблицы\n\nБлоки — не отдельный мир: выделение, сортировка, буфер обмена и редактирование\nпродолжают работать. Здесь собрано, как именно.\n\n### Выделение, нумерация и навигация\n\nВыделение настраивается как обычно — `selecting` со стейтом и `rowKeyGetter`.\nА вот ведёт оно себя по-разному в зависимости от способа объединения:\n\n- **Плоский вид с mergeByCellValues** — чекбокс у каждой строки, номер у каждой\n строки. Объединение колонок на выделение не влияет: в стори\n «mergeByCellValues: пример с серверными данными» можно выделить одного\n сотрудника внутри слитого блока.\n- **Merged-виды группировки и subRows** — один чекбокс и один номер на группу\n верхнего уровня. Клик по чекбоксу выделяет все строки группы разом, повторный —\n снимает. «Выделить всё» в шапке тоже работает. Счётчик выбранного внизу\n считает строки, а не группы: выделили дивизион из 12 сотрудников — внизу\n «выбрано 12».\n\nСпециально настраивать групповое поведение не нужно: таблица включает его сама,\nкогда активен merged-вид.\n\nНавигация тоже понимает блоки: клик в любую точку блока выделяет его целиком,\nрамка фокуса рисуется вокруг всего блока, один шаг стрелкой перепрыгивает блок.\nПопасть «внутрь» блока с клавиатуры нельзя — для таблицы это одна ячейка.\n\n### Сортировка, фильтрация, поиск и пагинация\n\nВозможности зависят от того, кто владеет данными.\n\n**mergeByCellValues (плоский вид).** Встроенные сортировка, фильтр и поиск\nработают как обычно, а блоки пересобираются после каждого изменения порядка —\nобъединение всегда отражает текущий видимый список строк. Если данные приходят с\nсервера постранично, следите, чтобы сортировка на сервере не разрывала группы:\nполовина группы на одной странице и половина на другой будут выглядеть как два\nотдельных блока.\n\n**rowsGrouping (view: 'merged').** Встроенные поиск, сортировка и фильтры\nработают: таблица применяет их к строкам до сборки групп, поэтому группы всегда\nсобираются из уже отфильтрованного списка. Пагинации нет: группировке нужны все\nстроки сразу. Сортировку по группирующим колонкам можно снять настройкой\n`disableGroupColumnsSort` — как в дереве, где сгруппированные колонки не\nсортируются.\n\nЧастая ошибка при встроенных фильтрах (не только в этом виде): в стейте\n`filtering.state` должен быть ключ каждого фильтра, объявленного в колонках.\nSelect-фильтр без своего ключа получит пустое значение вместо «показать всё» и\nможет отсеять все строки — таблица окажется пустой без единой ошибки.\n\n**subRows (view: 'merged').** Дерево у потребителя, поэтому пагинация по верхним\nблокам работает: отдаёте страницу дерева — таблица её показывает. Встроенные\nпоиск, сортировка и фильтрация к структурному дереву пока не применяются — эти\nоперации делаются на стороне потребителя над его данными.\n\n### Копирование, вставка и протяжка\n\n- Копирование отдаёт значение в позиции верхней-левой ячейки блока, остальные\n ячейки блока в буфере пустые — как в Excel.\n- Вставка пишет во весь блок: значение попадает во все его строки.\n- Протяжка (fill) растягивается только до целых блоков — залить пол-блока нельзя;\n пунктирная рамка протяжки сама прилипает к границам блоков.\n\n### Редактирование\n\n- Правка ячейки блока записывает значение во все его строки — данные под блоком\n всегда совпадают с тем, что на экране.\n- При объединении по значению правка пересобирает блоки: изменили «Отдел» у\n блока — он разъедется или сольётся с соседним, потому что объединение выводится\n из данных.\n- У редактируемых Select-ячеек редактор открывается по выравниванию блока: текст\n прижат к низу — редактор откроется у нижнего края, а выпадающий список\n раскроется вверх.\n\n## Выравнивание контента в блоке\n\nПо умолчанию контент блока выравнивается по горизонтали из `contentAlign` колонки\n(иначе слева), по вертикали — по центру. Настраивается лестницей «точечное важнее\nобщего»:\n\n- `mergedCellsAlign` конкретного региона (только для `mergedCellsRegions`);\n- `mergedCellsAlign` на колонке — все блоки этой колонки, работает для всех\n способов включения;\n- дефолт фичи: `mergeCells.mergedCellsAlign` или `rowsGrouping.mergedCellsAlign`.\n\n```tsx\ncolumnConfig={[\n { key: 'dept', name: 'Отдел', mergedCellsAlign: { horizontal: 'center', vertical: 'top' } },\n]}\n```\n\nКолоночный `mergedCellsAlign` может быть и функцией `(row) => MergedCellsAlign`\nпо данным строки блока — так разные блоки одной колонки получают разное\nвыравнивание. Это единственный способ управлять выравниванием поблочно в\nmerged-видах группировки и subRows, где границы блоков решает таблица, а не\nпотребитель.\n\n```tsx\ncolumnConfig={[\n { key: 'dept', mergedCellsAlign: (row) =>\n row.critical ? { vertical: 'top' } : { vertical: 'center' } },\n]}\n```\n\n### Свой рендер в блоке\n\nВыравнивание действует на текстовый контент. Кастомный `renderCell` получает весь\nпрямоугольник блока и выравнивает содержимое сам — через свойства своих\nконтейнеров.\n\nУ колонок со своим рендером есть неочевидность: предпросмотр значения (по\nдвойному клику на ячейке без редактирования) у них по умолчанию выключен.\nСо стороны это выглядит как «у блоков не открывается предпросмотр», хотя дело в\nколонке, а не в объединении. Включается настройкой колонки:\n\n```tsx\n{ key: 'dept', renderCell: ..., renderCellPreview: 'cellEditorAsPreview' }\n```\n\n## Что не работает и почему\n\nСводный список ограничений. Если «что-то не рисуется» — сначала сюда.\n\n### Во всех способах\n\n- Все ячейки блока обязаны нести одинаковые данные — это контракт\n `mergeByCellValues` (значения реально повторяются в строках) и регионов.\n Причина проста: блок показывает верхнюю-левую **видимую** ячейку, а какая\n ячейка окажется верхней-левой — зависит от закрепления и порядка колонок.\n Если данные одинаковые, блок выглядит одинаково при любой перестановке.\n- Попасть «внутрь» блока с клавиатуры нельзя — для таблицы это одна ячейка.\n Это поведение, а не ошибка.\n- Выравнивание пока не поддерживает письмо справа налево (RTL).\n- Горизонтальная протяжка через colSpan-блок не растягивается до границ блока\n (в работе).\n- У колонок со своим `renderCell` по умолчанию выключен предпросмотр значения —\n включается `renderCellPreview: 'cellEditorAsPreview'` (см. «Свой рендер в\n блоке» выше).\n\n### mergedCellsRegions\n\n- Разорванный регион исчезает молча: если после сортировки, перестановки или\n скрытия колонок ключи региона перестали идти подряд, блок просто не рисуется.\n Ошибок и предупреждений нет — следите за порядком сами.\n\n### rowsGrouping (view: 'merged')\n\n- Пагинации нет: чтобы собрать группы, таблице нужны все строки сразу.\n- Отдельная колонка «Группировка» не создаётся, поэтому не действует всё, что к\n ней привязано: `groupedColumnProps`, свой контент ячейки группы\n (`renderGroupCell` у колонки) и кнопка «развернуть всё» (`expandAllBtn`) —\n строк-групп и шевронов в этом виде нет.\n\n### subRows (view: 'merged')\n\n- Встроенные поиск, сортировка и фильтрация к структурному дереву не\n применяются — эти операции делает потребитель над своими данными.\n- `column.subRow` целиком не действует: шеврон (`isColumnWithArrow`), свой\n контент и ключи вложенных уровней (`renderSubRowCell`, `keyOfColumnInSubRow`,\n `parentKeyAsDefault`, `contentFormat`), свой редактор уровня. Листья рисуются\n как обычные строки — работают их обычные `renderCell`, `contentFormat` и\n `editingCell`.\n- `expandedIdsState` и сворачивание не действуют: раскрывать нечего, дерево\n показано целиком.\n\nЭто осознанное поведение: один и тот же конфиг `subRows` или `rowsGrouping`\nможно переключать между `view: 'tree'` и `view: 'merged'` — лишние настройки\nдругого вида не мешают. Пометки «работает только в виде дерева» есть и в\nподсказках типов.\n\n> Подробнее о типах — [CellsMerging API](?path=/docs/локальные-компоненты-tablecanvas-cellsmerging-api--docs)",
52136
- "apiDocs": "# CellsMerging API\n\n## tableConfig.mergeCells\n\nТочка входа для объединения ячеек тела. Все поля опциональны:\n\n```ts\nmergeCells?: {\n /** Колонки, объединяемые по подряд идущим одинаковым значениям. */\n mergeByCellValues?: Array<string | { colKey: string; value: (row) => unknown }>;\n /** Управляемый список объединений по ключам строк и колонок. */\n mergedCellsRegions?: MergedCellsRegion[];\n /** Нужен для mergedCellsRegions: сопоставляет rowKeys со строками. */\n rowKeyGetter?: (row) => string | number;\n /** Общий (табличный) дефолт выравнивания контента в блоках. */\n mergedCellsAlign?: MergedCellsAlign;\n};\n```\n\n## MergedCellsRegion\n\nОдин управляемый регион: ключи строк, ключи колонок и точечное выравнивание.\n\n```typescript\ntype MergedCellsRegion = {\n rowKeys: Array<string | number>;\n colKeys: string[];\n /** Выравнивание контента этого блока. Важнее колоночного и общего. */\n mergedCellsAlign?: MergedCellsAlign;\n};\n```\n\n## MergedCellsAlign\n\nВыравнивание контента в блоке. Задаётся на трёх уровнях: `mergedCellsAlign` региона,\n`columnConfig[].mergedCellsAlign` (колонка), `mergeCells.mergedCellsAlign` или\n`rowsGrouping.mergedCellsAlign` (дефолт). Точечное важнее общего.\n\nКолоночный `mergedCellsAlign` — это `MergedCellsAlign` (одно на все блоки колонки) или\nфункция `(row) => MergedCellsAlign | undefined` по данным верхней строки блока. Функция\nдаёт разное выравнивание разным блокам, включая merged-виды группировки/subRows, где\nграницы блоков решает таблица.\n\n```tsx\ncolumnConfig={[\n { key: 'dept', mergedCellsAlign: (row) =>\n row.critical ? { vertical: 'top' } : { vertical: 'center' } },\n]}\n```\n\n```typescript\ntype MergedCellsAlign = {\n /** По горизонтали. @default из `contentAlign` колонки, иначе 'left' */\n horizontal?: 'left' | 'center' | 'right';\n /** По вертикали. @default 'center' */\n vertical?: 'top' | 'center' | 'bottom';\n};\n```\n\n## rowsGrouping (merged-вид)\n\nПоля группировки, относящиеся к merged-виду: `view: 'merged'`,\n`mergedCellsAlign`, `disableGroupColumnsSort`.\n\n```typescript\ntype RowsGrouping<\n RowType extends ObjectForExtending,\n SummaryRowType = unknown,\n ColumnConfig extends LocalColumnInstance = LocalColumnInstance,\n> = {\n /**\n * массив группированных колонок и его setter\n */\n groupByState: [string[], React.Dispatch<React.SetStateAction<string[]>>];\n /**\n * Как показывать группировку.\n * 'tree' (по умолчанию) — дерево с раскрытием (шевроны) и колонкой группировки.\n * 'merged' — плоский вид: строки идут по группам, а группирующие колонки\n * показаны объединёнными ячейками. Раскрытия нет; чекбокс и номер — на всю\n * группу верхнего уровня.\n * @default 'tree'\n */\n view?: 'tree' | 'merged';\n /**\n * Только для view: 'merged'. Выравнивание по умолчанию в объединённых ячейках\n * группирующих колонок. Колоночный mergedCellsAlign важнее.\n */\n mergedCellsAlign?: MergedCellsAlign;\n /**\n * Только для view: 'merged'. Запретить сортировку по группирующим колонкам\n * (как в дереве). По остальным колонкам сортировка остаётся.\n * @default false\n */\n disableGroupColumnsSort?: boolean;\n /**\n * Функция определения уникального id строки\n */\n rowKeyGetter: (row: RowType) => string | number;\n /**\n * Показывать ли кнопку «Группировать» в controlBlock.\n * При `false` кнопка скрыта и не участвует в компрессии,\n * но группировка строк продолжает работать от внешнего `groupByState`.\n * @default true\n */\n showInControl?: boolean;\n /**\n * Настройки колонки «Группировка» (имя, ширина, свои рендеры). Работает только\n * в виде дерева: при view: 'merged' эта колонка не создаётся, а сгруппированные\n * колонки остаются на своих местах.\n * @default 'Группировка'\n */\n groupedColumnProps?: Partial<Pick<ColumnConfig, 'name' | 'width'>> & {\n renderCell?: (\n props: CellInfoGlideInstance<RowType, SummaryRowType> & {\n parentGroupKey: string | undefined;\n groupByArr: string[];\n },\n ) => CanvasContent;\n rowsGrouping?: Pick<\n ColumnRowsGrouping<RowType, ColumnConfig>,\n 'renderGroupCell'\n >;\n };\n /** Кнопка «развернуть всё». Работает только в виде дерева: при view: 'merged' шевронов нет. */\n expandAllBtn?: {\n /**\n * Функция для расчета состояния открытости всех раскрываемых строк. Функция должна быть чистой.\n * @returns boolean\n */\n expandedAll: (p: {\n /**\n * allRowsIds - уникальные идентификаторы всех строк (группировок и обычных)\n */\n allRowsIds: Set<string | number> | null;\n /**\n * shownRows - представленные прямо сейчас строки (группировки и обычные). Или видимые строки - видимые не во viewport-е, а которые должны быть показаны из-за раскрытий)\n */\n shownRows: readonly RowType[];\n expandedRowsIds: Set<string | number>;\n }) => boolean;\n };\n /**\n * `groupButton` - свойство для кастомизации кнопки с выпадающим списком\n */\n groupButton?: {\n getGroupedCount?: (props: {\n /**\n * высчитанное автоматически количество активных группировок.\n */\n currCount: number;\n /**\n * активные группировки.\n */\n groupedCols: string[];\n columns: {\n /**\n * `visible` - видимые в выпадающем списке колонки-группировки.\n */\n visible: string[];\n /**\n * `hidden` - невидимые или не участвующие в группировке колонки\n *\n * (columnConfig.rowsGrouping=undefined ||\n * columnConfig.rowsGrouping.groupByColumn=false).\n */\n hidden: string[];\n };\n }) => number;\n /**\n * `defaultCustomItems` - свойство для добавления ключей группировки, которых нет в таблице.\n *\n * `DropdownItemOption.value` - необходимо заполнять ключом, который существует в данных.\n */\n defaultCustomItems?: DropdownItemOption[];\n /**\n * `onItemSelect` - свойство для полного контроля над изменением группировки при выборе опций.\n *\n * `DropdownItemOption.value` - необходимо заполнять ключом, который существует в данных.\n */\n onItemSelect?: (props: {\n item: DropdownItemOption;\n setGroupedCols: React.Dispatch<React.SetStateAction<string[]>>;\n columns: {\n visible: string[];\n hidden: string[];\n };\n }) => void;\n };\n /**\n * `groupRowReplaceTo` - свойство для изменения данных сгруппированных строк. Может понадобиться в редких случаях.\n *\n * @param groupRow данные сгруппированной строки\n * @returns измененная группировка или строка без группировки — строка, которые заменит groupRow\n */\n groupRowReplaceTo?: (\n groupRow: GroupRow<RowType>,\n ) => GroupRow<RowType> | RowType;\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n domMetadata?: DomMetadata;\n};\n\nexport type RenderGroupCellProps<\n RowType extends ObjectForExtending,\n ColumnConfig extends LocalColumnInstance = LocalColumnInstance,\n> = {\n column: ColumnConfig;\n tabIndex: number;\n theme?: Theme;\n // TODO isExpanded: boolean;\n // TODO toggleGroup: () => void;\n} & GroupRow<RowType>;\n\nexport type ColumnRowsGrouping<\n RowType extends ObjectForExtending,\n ColumnConfig extends LocalColumnInstance,\n> = {\n /**\n * @default true - при наличии ColumnConfig.rowsGrouping\n */\n groupByColumn?: boolean;\n /**\n * @default ColumnConfig.key\n */\n columnGroupLabel?: string;\n /**\n * Свой контент ячейки строки-группы. Работает только в виде дерева: при\n * view: 'merged' строк-групп нет (группы показаны объединёнными ячейками),\n * поэтому этот рендер не вызывается.\n */\n renderGroupCell?: (\n props: RenderGroupCellProps<RowType, ColumnConfig>,\n ) => CanvasContent;\n};\n```\n\n## subRows (merged-вид)\n\nПоля subRows, относящиеся к merged-виду: `view: 'merged'` и `mergedColumns`\n(упорядоченный список колонок-предков, индекс = глубина уровня дерева).\n\n```typescript\ntype SubRows<RowType, RowIdType> = {\n /**\n * Возвращает дочерние строки узла (или undefined, если их нет).\n *\n * Функция должна быть стабильной — не менять поведение между рендерами.\n * Если она зависит от чего-то меняющегося, оберните её в useCallback.\n */\n getSubRows: (row: RowType) => RowType[] | undefined;\n /**\n * Возвращает уникальный ключ строки.\n *\n * Функция должна быть стабильной — не менять поведение между рендерами.\n * Если она зависит от чего-то меняющегося, оберните её в useCallback.\n */\n rowKeyGetter: (row: RowType) => RowIdType;\n /**\n * Внешний стейт развёрнутых строк.\n * Если не задан — используется внутренний useState.\n * При view: 'merged' не используется: сворачивания в этом виде нет.\n */\n expandedIdsState?: [\n Set<string | number>,\n (\n newV:\n | Set<string | number>\n | ((prev: Set<string | number>) => Set<string | number>),\n ) => void,\n ];\n /**\n * Как показывать дерево.\n * 'tree' (по умолчанию) — узлы с раскрытием (шевроны) и отступом по уровню.\n * 'merged' — дерево разворачивается в листья, а колонки-предки показаны\n * объединёнными ячейками. Структуру задаёт потребитель через getSubRows;\n * данные (пагинация, сортировка, поиск) остаются на его стороне.\n */\n view?: 'tree' | 'merged';\n /**\n * Только для view: 'merged'. Колонки-предки по порядку уровней:\n * mergedColumns[0] — верхний уровень, дальше глубже. Каждая такая колонка\n * показывает значение своего узла-предка (узел должен нести поле с этим именем)\n * и объединяется по его границам. Верхний уровень задаёт чекбокс и номер блока.\n */\n mergedColumns?: string[];\n};\n```",
52479
+ "docs": "# CellsMerging (TableCanvas)\n\nОбъединение ячеек тела таблицы: по строкам (rowSpan), по колонкам (colSpan) и\nпрямоугольными блоками. Несколько одинаковых ячеек рисуются одной большой, а всё\nвзаимодействие — клики, выделение, навигация, копирование, вставка, протяжка,\nредактирование — обращается с блоком как с одной ячейкой.\n\nЭта страница — обзор: как выбрать способ и с чего начать, плюс живые примеры.\nПодробности (совмещение способов, работа с деревом, выравнивание, сводные\nограничения) — в\n[Справочнике](?path=/docs/локальные-компоненты-tablecanvas-cellsmerging-справочник--docs),\nтипы — в\n[API](?path=/docs/локальные-компоненты-tablecanvas-cellsmerging-api--docs).\n\n## Как это устроено\n\nГлавная идея простая: объединение — это способ показа, а не способ хранения.\n\n- В данных значение повторяется в каждой строке блока. Если «Отдел А» тянется на\n три строки, то во всех трёх строках в поле отдела записано «Отдел А».\n- Таблица замечает повторы (или получает границы блока явно) и вместо трёх\n одинаковых ячеек рисует одну высокую. Содержимое берётся из верхней-левой\n ячейки блока.\n- Данные при этом не меняются. Уберите объединение — увидите те же строки с теми\n же значениями.\n\nОтсюда следует и поведение, знакомое по Excel: клик в любую точку блока выделяет\nблок целиком, правка блока меняет значение во всех его строках, копирование\nотдаёт значение один раз.\n\n## Три способа включить объединение\n\nМеханика под всеми способами одна. Отличие — кто вычисляет границы блоков:\nпотребитель или таблица. Способы можно совмещать в одной таблице — правила в\nСправочнике, глава «Если включено несколько способов сразу».\n\n### 1. mergeCells.mergedCellsRegions — блоки, заданные снаружи\n\n«Слей вот эти конкретные ячейки». Список блоков по стабильным ключам строк и\nколонок; списком владеет потребитель, как выделением. Таблица переводит ключи в\nтекущие видимые позиции. Если сортировка, перестановка или скрытие колонки\nразорвали блок — он не рисуется (как ограничение сортировки в Excel).\n\n```tsx\ntableConfig={{\n mergeCells: {\n mergedCellsRegions: [\n { rowKeys: ['r1', 'r2'], colKeys: ['dept'] },\n { rowKeys: ['r4', 'r5'], colKeys: ['plan', 'fact'] }, // прямоугольник 2×2\n ],\n rowKeyGetter: (row) => row.id,\n },\n}}\n```\n\nПримеры — стори с префиксом `mergedCellsRegions:` ниже.\n\n### 2. mergeCells.mergeByCellValues — по одинаковым значениям\n\n«В этих колонках сливай подряд идущие одинаковые значения». Границы блоков\nтаблица вычисляет сама из данных; после сортировки или фильтра блоки\nпересобираются.\n\n```tsx\ntableConfig={{\n mergeCells: {\n mergeByCellValues: [\n 'dept', // по значению колонки\n { colKey: 'role', value: (row) => row.roleGroup }, // по своей функции\n ],\n },\n}}\n```\n\nОдинаковые названия в разных ветках иерархии могут ложно слиться — лечится\nсоставным ключом, разбор в Справочнике, глава «Объединение по значению: где\nпроходит граница». Примеры — стори с префиксом `mergeByCellValues:` ниже.\n\n### 3. Merged-виды группировки и subRows — полный автомат\n\nПотребитель включает вид — всю работу с блоками делает таблица: строки\nупорядочиваются по группам, колонки уровней сливаются по границам групп, чекбокс\nи нумерация работают по верхней группе.\n\nЧерез группировку (структуру задают значения группирующих колонок):\n\n```tsx\ntableConfig={{\n rowsGrouping: {\n view: 'merged',\n groupByState: [groupBy, setGroupBy], // например ['dept', 'role']\n rowKeyGetter: (row) => row.id,\n },\n}}\n```\n\nЧерез subRows (структуру задаёт готовое дерево потребителя):\n\n```tsx\ntableConfig={{\n subRows: {\n view: 'merged',\n mergedColumns: ['dept', 'role'], // колонки уровней дерева\n getSubRows: (row) => row.children,\n rowKeyGetter: (row) => row.id,\n },\n}}\n```\n\nПримеры — «subRows: дерево с пагинацией» и «rowsGrouping: группировка\nпользователем» в конце страницы.\n\n## Какой способ выбрать\n\nКартинка у способов похожая, поэтому выбирать стоит не по внешнему виду, а по\nтому, кто владеет данными и что нужно пользователю.\n\n### Дерево приходит с сервера, нужна постраничная загрузка — subRows\n\nЕсли данные уже иерархические (дивизион, управление, команда, сотрудники) и\nприходят от сервера частями, берите `subRows` с `view: 'merged'`. Дерево остаётся\nу вас: вы отдаёте таблице страницу дерева, она разворачивает её в строки и сама\nсливает колонки-предки. Именно поэтому здесь работает пагинация по верхним\nблокам — таблице не нужно видеть все данные сразу.\n\nОбратная сторона: раз данными владеете вы, то поиск, сортировка и фильтрация\nдерева — тоже на вашей стороне. Формат дерева, пагинация и возврат правок —\nв Справочнике, глава «Дерево через subRows».\n\n### Плоские строки, пользователь сам выбирает группировку — rowsGrouping\n\nЕсли строки плоские, а пользователь должен на лету решать, по каким колонкам\nгруппировать, — берите `rowsGrouping` с `view: 'merged'`. Состав группировки живёт\nв `groupByState`, а с настройкой `groupButton` в блоке управления появляется\nкнопка: пользователь сам выбирает колонки, таблица пересобирает блоки. Встроенные\nпоиск, сортировка и фильтры работают — таблица применяет их до сборки групп.\n\nОбратная сторона: пагинации в этом виде нет — таблице нужны все строки сразу.\nНе действует и всё, что привязано к строкам-групп и шевронам дерева\n(`groupedColumnProps`, `renderGroupCell`, `expandAllBtn`) — полный список в\nСправочнике, глава «Что не работает и почему».\n\n### Плоские строки, группировка фиксированная, всё считает сервер — mergeByCellValues\n\nЕсли структура известна заранее и не меняется пользователем, а данные (включая\nстраницы, сортировку и фильтры) готовит сервер, — самый прямой путь это\n`mergeByCellValues`. Вы упорядочиваете строки как нужно, таблица сливает соседние\nодинаковые значения. Никакой лишней механики: ни кнопок, ни дерева.\n\n### Отдельные ручные блоки — mergedCellsRegions\n\nШапки секций внутри таблицы, нестандартные прямоугольники, объединение по кнопке\nили из контекстного меню — всё, что не выводится из значений, делается регионами.\nПотребитель добавляет блок в свой список — таблица его рисует.\n\n## Смежные разделы\n\n- [Справочник](?path=/docs/локальные-компоненты-tablecanvas-cellsmerging-справочник--docs) —\n совмещение способов, составные ключи, дерево, выравнивание, сводные ограничения.\n- [CellsMerging API](?path=/docs/локальные-компоненты-tablecanvas-cellsmerging-api--docs) —\n типы.\n- Объединение ячеек шапки — раздел ColumnsGrouping (`squashEmptyCells`).\n\n## Полные примеры\n\nТри больших примера ниже собраны как заготовки для продуктов: в каждом —\nобъединение ячеек в связке с поиском, сортировкой, фильтрами, пагинацией,\nредактированием и выделением. Различаются они тем, кто владеет данными, поэтому\nи код обвязки разный. Полный код каждого примера открывается кнопкой «Show code»\nи снабжён комментариями по ключевым местам.\n\n### mergeByCellValues: пример с серверными данными\n\nДанные плоские, всё считает «сервер» (в примере его заменяет функция\n`selectPage`), таблица только рисует полученную страницу.\n\nЧто здесь показано:\n\n- поиск, фильтры, сортировка и пагинация в `manual`-режиме — считает потребитель;\n- составные ключи пути (`divPath` / `unitPath` / `teamPath`) против ложного\n слияния одинаковых имён из разных веток;\n- сортировка внутри команды — блоки не рассыпаются;\n- закрепление колонок вместе с групповой шапкой;\n- редактирование с возвратом правок страницы в полный набор.\n\n<Canvas of={CellsMergingExamples.Showcase} />\n\n### subRows: дерево с пагинацией\n\nДанные — дерево, и оно остаётся у потребителя: таблице отдаётся страница целых\nподдеревьев.\n\nЧто здесь показано:\n\n- пагинация по верхним блокам (дивизионам) со своим списком «показывать по»;\n- `manual`-поиск, сортировка и фильтры, посчитанные по дереву\n (функция `selectTreePage`);\n- сортировка показателей внутри команды и перестановка веток по имени;\n- возврат правок листьев обратно в дерево.\n\n<Canvas of={CellsMergingExamples.SubRowsMerged} />\n\n### rowsGrouping: группировка пользователем\n\nДанные плоские и передаются целиком, остальное делает таблица. Самый короткий\nкод из трёх.\n\nЧто здесь показано:\n\n- встроенные поиск, сортировка и фильтры — применяются до сборки групп;\n- выбор состава группировки пользователем (кнопка `groupButton`);\n- полный стейт фильтров: ключ на каждый фильтр из колонок;\n- без пагинации — чтобы собрать группы, таблице нужны все строки сразу.\n\n<Canvas of={CellsMergingExamples.GroupingMerged} />\n\n## Как перенести пример к себе\n\n1. Замените данные и типы строк на свои. Сохраните стабильный `id` строки — на\n нём держатся выделение и возврат правок, между страницами он меняться не\n должен.\n2. Замените `selectPage` / `selectTreePage` реальным запросом к серверу. Контракт\n тот же: параметры выборки на входе, страница и общее количество на выходе.\n3. Проверьте, что в `filtering.state` есть ключ каждого фильтра из колонок (со\n значением «показать всё»), — селект-фильтр без своего ключа молча отсеет все\n строки.\n4. Для `mergeByCellValues` заведите составные ключи пути, если одинаковые\n названия возможны в разных ветках иерархии.\n5. Уберите фичи, которые вам не нужны, — настройки в примерах независимы друг от\n друга: пагинация, закрепление, чекбоксы, редактирование отключаются по\n отдельности.\n\n# CellsMerging: справочник\n\nПодробности объединения ячеек: совмещение способов, составные ключи, работа с\nдеревом, взаимодействие с остальными фичами таблицы, выравнивание и сводный\nсписок ограничений. Обзор способов и живые примеры — на странице\n[Docs](?path=/docs/локальные-компоненты-tablecanvas-cellsmerging--docs), типы —\nна странице\n[API](?path=/docs/локальные-компоненты-tablecanvas-cellsmerging-api--docs).\n\n## Если включено несколько способов сразу\n\nСпособы можно совмещать в одной таблице — правила простые и считаются по колонке:\n\n- Если колонка входит хотя бы в один регион из `mergedCellsRegions`, её\n объединения описывают только регионы. `mergeByCellValues` на этой колонке не\n действует.\n- Колонка merged-вида (группировки или subRows) сливается по границам групп.\n Пользовательский `mergeByCellValues` на той же колонке не действует — иначе два\n механизма спорили бы за одни ячейки.\n- В остальных случаях работает `mergeByCellValues`.\n- Разные колонки живут независимо: регион на одной колонке и слияние по значению\n на другой — обычная рабочая комбинация.\n\nПример: таблица с группировкой по «Отделу» (merged-вид) может дополнительно\nсливать колонку «Статус» через `mergeByCellValues`, а строки-заголовки секций\nрисовать регионами на всю ширину — все три способа уживаются, потому что заняты\nразными колонками.\n\n## Объединение по значению: где проходит граница\n\nУ `mergeByCellValues` есть классическая ловушка. Допустим, регионы «Север» и «Юг»,\nи в каждом есть «Команда 1» и «Команда 2»:\n\n```\nСевер | Команда 1 | Иванов\nСевер | Команда 2 | Петров\nЮг | Команда 2 | Сидоров\nЮг | Команда 1 | Смирнов\n```\n\nЕсли сливать колонку команды по её значению, «Команда 2» из Севера и «Команда 2»\nиз Юга стоят рядом — и сольются в один блок через границу региона. Визуально это\nвыглядит как ошибка: одна команда, а на деле две разные.\n\nРешение — сливать не по тексту в ячейке, а по составному ключу, в котором зашит\nпуть от корня:\n\n```tsx\nmergeCells: {\n mergeByCellValues: [\n 'region',\n // Сравнивается результат функции, а не текст в ячейке.\n { colKey: 'team', value: (row) => `${row.region} / ${row.team}` },\n ],\n}\n```\n\nТеперь у «Команды 2» из Севера ключ «Север / Команда 2», а у южной —\n«Юг / Команда 2». Ключи разные, слияние останавливается на границе региона само,\nбез какой-либо отдельной логики. В ячейке при этом показывается обычное значение\nколонки — функция влияет только на сравнение.\n\nВ полном примере (стори «mergeByCellValues: пример с серверными данными») такие\nключи собраны заранее в полях строки: `divPath`, `unitPath`, `teamPath` — по\nодному на каждый уровень иерархии.\n\nMerged-виды группировки и subRows строят такие ключи сами — там об этой ловушке\nдумать не нужно.\n\n## Дерево через subRows: как передавать данные\n\nРазберём подробнее самый ёмкий сценарий — `subRows` с `view: 'merged'`.\n\n### Какое дерево ждёт таблица\n\nВ `rows` передаются корневые узлы, детей таблица достаёт через `getSubRows`.\nРоли узлов распределены так:\n\n- **Внутренние узлы** (дивизион, управление, команда) — ярлыки уровней. Каждый\n несёт поле с именем своей колонки из `mergedColumns`: узел дивизиона — поле\n `division`, узел управления — поле `unit`, и так далее.\n- **Листья** — строки данных. Именно они становятся строками таблицы со своими\n показателями; внутренние узлы отдельными строками не показываются.\n\n```tsx\nconst tree = [\n {\n id: 'd1',\n division: 'Розничный бизнес', // узел уровня 0\n subRows: [\n {\n id: 'u1',\n unit: 'Управление продаж', // узел уровня 1\n subRows: [\n {\n id: 't1',\n team: 'Команда Север', // узел уровня 2\n subRows: [\n { id: 'e1', employee: 'Иванов', plan: 100, fact: 90 }, // лист\n { id: 'e2', employee: 'Петров', plan: 80, fact: 85 },\n ],\n },\n ],\n },\n ],\n },\n];\n```\n\n```tsx\ntableConfig={{\n subRows: {\n view: 'merged',\n mergedColumns: ['division', 'unit', 'team'], // порядок = уровни дерева\n getSubRows: (row) => row.subRows,\n rowKeyGetter: (row) => row.id,\n },\n}}\n```\n\n`mergedColumns` — это соответствие уровней дерева и колонок: первый элемент\nпоказывает узлы верхнего уровня, второй — следующего, и так далее. Колонка\n`division` возьмёт значение из узла дивизиона и сольётся на все его листья,\n`unit` — на листья своего управления, вложенно.\n\nСворачивания в этом виде нет: таблица показывает всё переданное дерево целиком.\nХотите меньше строк на экране — передайте меньший кусок дерева (следующий\nраздел).\n\n### Пагинация по верхним блокам\n\nДерево у вас, поэтому страницы нарезаете вы — по верхним узлам. Таблице отдаётся\nсрез дерева, а в `pagination.count` — общее число верхних узлов:\n\n```tsx\nconst [page, setPage] = useState(1);\nconst [perPage, setPerPage] = useState(2); // дивизионов на страницу\nconst pageTree = tree.slice((page - 1) * perPage, page * perPage);\n\ntableConfig={{\n pagination: {\n count: tree.length, // всего верхних узлов, не листьев\n perPage,\n perPageList: [1, 2, 3], // варианты «показывать по» — в блоках\n value: page,\n onChange: (nextPage, nextPerPage) => {\n if (typeof nextPerPage === 'number' && nextPerPage !== perPage) {\n setPerPage(nextPerPage);\n setPage(1);\n } else if (typeof nextPage === 'number') {\n setPage(nextPage);\n }\n },\n },\n subRows: { /* как выше */ },\n}}\n// ...\nrows={pageTree}\n```\n\nСтраница «2 дивизиона» может содержать разное число строк-листьев — это нормально:\nединица пагинации здесь блок, а не строка. По той же причине настройте селектор\n«Показывать по»: его стандартные варианты (20/50/100) рассчитаны на строки и для\nблоков не имеют смысла — задайте свой список `perPageList` в блоках, как выше,\nлибо спрячьте селектор (`hasPerPage: false`). Если дерево приходит с сервера\nчастями, вместо `slice` будет запрос следующей страницы — контракт тот же.\n\n### Редактирование: правки возвращаются листьями\n\nРедактируются листья. В `editing.onRowsChange` приходят изменённые строки-листья —\nзаписать их обратно в своё дерево должен потребитель, например по `id`:\n\n```tsx\nediting: {\n rowKeyGetter: (r) => r.id,\n onRowsChange: (updatedLeaves) => {\n const byId = new Map(updatedLeaves.map((r) => [r.id, r]));\n // Обойдите дерево и замените листья с совпавшими id.\n setTree((prev) => writeLeavesBack(prev, byId));\n },\n},\n```\n\nЭто следствие владения данными: таблица не знает, как устроено ваше дерево,\nпоэтому отдаёт плоский результат, а раскладываете его вы.\n\n### Что остаётся на вашей стороне\n\n- **Поиск, сортировка, фильтрация** — встроенные механизмы к структурному дереву\n пока не применяются. Отфильтровали или отсортировали своё дерево — передали\n результат в `rows`, таблица показала.\n- **Выделение** при этом работает из коробки: один чекбокс на верхний блок, клик\n выделяет все его листья (подробнее — в разделе про выделение ниже).\n\nЖивой пример всего вместе — стори «subRows: дерево с пагинацией» на странице\n[Docs](?path=/docs/локальные-компоненты-tablecanvas-cellsmerging--docs).\n\n## Объединение и остальные возможности таблицы\n\nБлоки — не отдельный мир: выделение, сортировка, буфер обмена и редактирование\nпродолжают работать. Здесь собрано, как именно.\n\n### Выделение, нумерация и навигация\n\nВыделение настраивается как обычно — `selecting` со стейтом и `rowKeyGetter`.\nА вот ведёт оно себя по-разному в зависимости от способа объединения:\n\n- **Плоский вид с mergeByCellValues** — чекбокс у каждой строки, номер у каждой\n строки. Объединение колонок на выделение не влияет: в стори\n «mergeByCellValues: пример с серверными данными» можно выделить одного\n сотрудника внутри слитого блока.\n- **Merged-виды группировки и subRows** — один чекбокс и один номер на группу\n верхнего уровня. Клик по чекбоксу выделяет все строки группы разом, повторный —\n снимает. «Выделить всё» в шапке тоже работает. Счётчик выбранного внизу\n считает строки, а не группы: выделили дивизион из 12 сотрудников — внизу\n «выбрано 12».\n\nСпециально настраивать групповое поведение не нужно: таблица включает его сама,\nкогда активен merged-вид.\n\nНавигация тоже понимает блоки: клик в любую точку блока выделяет его целиком,\nрамка фокуса рисуется вокруг всего блока, один шаг стрелкой перепрыгивает блок.\nПопасть «внутрь» блока с клавиатуры нельзя — для таблицы это одна ячейка.\n\n### Сортировка, фильтрация, поиск и пагинация\n\nВозможности зависят от того, кто владеет данными.\n\n**mergeByCellValues (плоский вид).** Встроенные сортировка, фильтр и поиск\nработают как обычно, а блоки пересобираются после каждого изменения порядка —\nобъединение всегда отражает текущий видимый список строк. Если данные приходят с\nсервера постранично, следите, чтобы сортировка на сервере не разрывала группы:\nполовина группы на одной странице и половина на другой будут выглядеть как два\nотдельных блока.\n\n**rowsGrouping (view: 'merged').** Встроенные поиск, сортировка и фильтры\nработают: таблица применяет их к строкам до сборки групп, поэтому группы всегда\nсобираются из уже отфильтрованного списка. Пагинации нет: группировке нужны все\nстроки сразу. Сортировку по группирующим колонкам можно снять настройкой\n`disableGroupColumnsSort` — как в дереве, где сгруппированные колонки не\nсортируются.\n\nЧастая ошибка при встроенных фильтрах (не только в этом виде): в стейте\n`filtering.state` должен быть ключ каждого фильтра, объявленного в колонках.\nSelect-фильтр без своего ключа получит пустое значение вместо «показать всё» и\nможет отсеять все строки — таблица окажется пустой без единой ошибки.\n\n**subRows (view: 'merged').** Дерево у потребителя, поэтому пагинация по верхним\nблокам работает: отдаёте страницу дерева — таблица её показывает. Встроенные\nпоиск, сортировка и фильтрация к структурному дереву пока не применяются — эти\nоперации делаются на стороне потребителя над его данными.\n\n### Копирование, вставка и протяжка\n\n- Копирование отдаёт значение в позиции верхней-левой ячейки блока, остальные\n ячейки блока в буфере пустые — как в Excel.\n- Вставка пишет во весь блок: значение попадает во все его строки.\n- Протяжка (fill) растягивается только до целых блоков — залить пол-блока нельзя;\n пунктирная рамка протяжки сама прилипает к границам блоков.\n\n### Редактирование\n\n- Правка ячейки блока записывает значение во все его строки — данные под блоком\n всегда совпадают с тем, что на экране.\n- При объединении по значению правка пересобирает блоки: изменили «Отдел» у\n блока — он разъедется или сольётся с соседним, потому что объединение выводится\n из данных.\n- У редактируемых Select-ячеек редактор открывается по выравниванию блока: текст\n прижат к низу — редактор откроется у нижнего края, а выпадающий список\n раскроется вверх.\n\n## Выравнивание контента в блоке\n\nПо умолчанию контент блока выравнивается по горизонтали как обычная ячейка\nэтой колонки — из `contentFormat.alignContent` (у числового формата это правый\nкрай), иначе слева. По вертикали — по центру: у обычной ячейки вертикального\nвыравнивания нет, это чисто блочная настройка. Настраивается лестницей «точечное важнее\nобщего»:\n\n- `mergedCellsAlign` конкретного региона (только для `mergedCellsRegions`);\n- `mergedCellsAlign` на колонке — все блоки этой колонки, работает для всех\n способов включения;\n- дефолт фичи: `mergeCells.mergedCellsAlign` или `rowsGrouping.mergedCellsAlign`.\n\n```tsx\ncolumnConfig={[\n { key: 'dept', name: 'Отдел', mergedCellsAlign: { horizontal: 'center', vertical: 'top' } },\n]}\n```\n\nКолоночный `mergedCellsAlign` может быть и функцией `(row) => MergedCellsAlign`\nпо данным строки блока — так разные блоки одной колонки получают разное\nвыравнивание. Это единственный способ управлять выравниванием поблочно в\nmerged-видах группировки и subRows, где границы блоков решает таблица, а не\nпотребитель.\n\n```tsx\ncolumnConfig={[\n { key: 'dept', mergedCellsAlign: (row) =>\n row.critical ? { vertical: 'top' } : { vertical: 'center' } },\n]}\n```\n\n### Свой рендер в блоке\n\nВыравнивание действует на текстовый контент. Кастомный `renderCell` получает весь\nпрямоугольник блока и выравнивает содержимое сам — через свойства своих\nконтейнеров.\n\nУ колонок со своим рендером есть неочевидность: предпросмотр значения (по\nдвойному клику на ячейке без редактирования) у них по умолчанию выключен.\nСо стороны это выглядит как «у блоков не открывается предпросмотр», хотя дело в\nколонке, а не в объединении. Включается настройкой колонки:\n\n```tsx\n{ key: 'dept', renderCell: ..., renderCellPreview: 'cellEditorAsPreview' }\n```\n\n## Что не работает и почему\n\nСводный список ограничений. Если «что-то не рисуется» — сначала сюда.\n\n### Во всех способах\n\n- Все ячейки блока обязаны нести одинаковые данные — это контракт\n `mergeByCellValues` (значения реально повторяются в строках) и регионов.\n Причина проста: блок показывает верхнюю-левую **видимую** ячейку, а какая\n ячейка окажется верхней-левой — зависит от закрепления и порядка колонок.\n Если данные одинаковые, блок выглядит одинаково при любой перестановке.\n- Попасть «внутрь» блока с клавиатуры нельзя — для таблицы это одна ячейка.\n Это поведение, а не ошибка.\n- Выравнивание пока не поддерживает письмо справа налево (RTL).\n- Горизонтальная протяжка через colSpan-блок не растягивается до границ блока\n (в работе).\n- У колонок со своим `renderCell` по умолчанию выключен предпросмотр значения —\n включается `renderCellPreview: 'cellEditorAsPreview'` (см. «Свой рендер в\n блоке» выше).\n\n### mergedCellsRegions\n\n- Разорванный регион исчезает молча: если после сортировки, перестановки или\n скрытия колонок ключи региона перестали идти подряд, блок просто не рисуется.\n Ошибок и предупреждений нет — следите за порядком сами.\n\n### rowsGrouping (view: 'merged')\n\n- Пагинации нет: чтобы собрать группы, таблице нужны все строки сразу.\n- Отдельная колонка «Группировка» не создаётся, поэтому не действует всё, что к\n ней привязано: `groupedColumnProps`, свой контент ячейки группы\n (`renderGroupCell` у колонки) и кнопка «развернуть всё» (`expandAllBtn`) —\n строк-групп и шевронов в этом виде нет.\n\n### subRows (view: 'merged')\n\n- Встроенные поиск, сортировка и фильтрация к структурному дереву не\n применяются — эти операции делает потребитель над своими данными.\n- `column.subRow` целиком не действует: шеврон (`isColumnWithArrow`), свой\n контент и ключи вложенных уровней (`renderSubRowCell`, `keyOfColumnInSubRow`,\n `parentKeyAsDefault`, `contentFormat`), свой редактор уровня. Листья рисуются\n как обычные строки — работают их обычные `renderCell`, `contentFormat` и\n `editingCell`.\n- `expandedIdsState` и сворачивание не действуют: раскрывать нечего, дерево\n показано целиком.\n\nЭто осознанное поведение: один и тот же конфиг `subRows` или `rowsGrouping`\nможно переключать между `view: 'tree'` и `view: 'merged'` — лишние настройки\nдругого вида не мешают. Пометки «работает только в виде дерева» есть и в\nподсказках типов.\n\n> Подробнее о типах — [CellsMerging API](?path=/docs/локальные-компоненты-tablecanvas-cellsmerging-api--docs)",
52480
+ "apiDocs": "# CellsMerging API\n\n## tableConfig.mergeCells\n\nТочка входа для объединения ячеек тела. Все поля опциональны:\n\n```ts\nmergeCells?: {\n /** Колонки, объединяемые по подряд идущим одинаковым значениям. */\n mergeByCellValues?: Array<string | { colKey: string; value: (row) => unknown }>;\n /** Управляемый список объединений по ключам строк и колонок. */\n mergedCellsRegions?: MergedCellsRegion[];\n /** Нужен для mergedCellsRegions: сопоставляет rowKeys со строками. */\n rowKeyGetter?: (row) => string | number;\n /** Общий (табличный) дефолт выравнивания контента в блоках. */\n mergedCellsAlign?: MergedCellsAlign;\n};\n```\n\n## MergedCellsRegion\n\nОдин управляемый регион: ключи строк, ключи колонок и точечное выравнивание.\n\n```typescript\ntype MergedCellsRegion = {\n rowKeys: Array<string | number>;\n colKeys: string[];\n /** Выравнивание контента этого блока. Важнее колоночного и общего. */\n mergedCellsAlign?: MergedCellsAlign;\n};\n```\n\n## MergedCellsAlign\n\nВыравнивание контента в блоке. Задаётся на трёх уровнях: `mergedCellsAlign` региона,\n`columnConfig[].mergedCellsAlign` (колонка), `mergeCells.mergedCellsAlign` или\n`rowsGrouping.mergedCellsAlign` (дефолт). Точечное важнее общего.\n\nКолоночный `mergedCellsAlign` — это `MergedCellsAlign` (одно на все блоки колонки) или\nфункция `(row) => MergedCellsAlign | undefined` по данным верхней строки блока. Функция\nдаёт разное выравнивание разным блокам, включая merged-виды группировки/subRows, где\nграницы блоков решает таблица.\n\n```tsx\ncolumnConfig={[\n { key: 'dept', mergedCellsAlign: (row) =>\n row.critical ? { vertical: 'top' } : { vertical: 'center' } },\n]}\n```\n\n```typescript\ntype MergedCellsAlign = {\n /** По горизонтали. @default из `contentFormat.alignContent` колонки, иначе 'left' */\n horizontal?: 'left' | 'center' | 'right';\n /** По вертикали. @default 'center' */\n vertical?: 'top' | 'center' | 'bottom';\n};\n```\n\n## rowsGrouping (merged-вид)\n\nПоля группировки, относящиеся к merged-виду: `view: 'merged'`,\n`mergedCellsAlign`, `disableGroupColumnsSort`.\n\n```typescript\ntype RowsGrouping<\n RowType extends ObjectForExtending,\n SummaryRowType = unknown,\n ColumnConfig extends LocalColumnInstance = LocalColumnInstance,\n> = {\n /**\n * массив группированных колонок и его setter\n */\n groupByState: [string[], React.Dispatch<React.SetStateAction<string[]>>];\n /**\n * Как показывать группировку.\n * 'tree' (по умолчанию) — дерево с раскрытием (шевроны) и колонкой группировки.\n * 'merged' — плоский вид: строки идут по группам, а группирующие колонки\n * показаны объединёнными ячейками. Раскрытия нет; чекбокс и номер — на всю\n * группу верхнего уровня.\n * @default 'tree'\n */\n view?: 'tree' | 'merged';\n /**\n * Только для view: 'merged'. Выравнивание по умолчанию в объединённых ячейках\n * группирующих колонок. Колоночный mergedCellsAlign важнее.\n */\n mergedCellsAlign?: MergedCellsAlign;\n /**\n * Только для view: 'merged'. Запретить сортировку по группирующим колонкам\n * (как в дереве). По остальным колонкам сортировка остаётся.\n * @default false\n */\n disableGroupColumnsSort?: boolean;\n /**\n * Функция определения уникального id строки\n */\n rowKeyGetter: (row: RowType) => string | number;\n /**\n * Показывать ли кнопку «Группировать» в controlBlock.\n * При `false` кнопка скрыта и не участвует в компрессии,\n * но группировка строк продолжает работать от внешнего `groupByState`.\n * @default true\n */\n showInControl?: boolean;\n /**\n * Настройки колонки «Группировка» (имя, ширина, свои рендеры). Работает только\n * в виде дерева: при view: 'merged' эта колонка не создаётся, а сгруппированные\n * колонки остаются на своих местах.\n * @default 'Группировка'\n */\n groupedColumnProps?: Partial<Pick<ColumnConfig, 'name' | 'width'>> & {\n renderCell?: (\n props: CellInfoGlideInstance<RowType, SummaryRowType> & {\n parentGroupKey: string | undefined;\n groupByArr: string[];\n },\n ) => CanvasContent;\n rowsGrouping?: Pick<\n ColumnRowsGrouping<RowType, ColumnConfig>,\n 'renderGroupCell'\n >;\n };\n /** Кнопка «развернуть всё». Работает только в виде дерева: при view: 'merged' шевронов нет. */\n expandAllBtn?: {\n /**\n * Функция для расчета состояния открытости всех раскрываемых строк. Функция должна быть чистой.\n * @returns boolean\n */\n expandedAll: (p: {\n /**\n * allRowsIds - уникальные идентификаторы всех строк (группировок и обычных)\n */\n allRowsIds: Set<string | number> | null;\n /**\n * shownRows - представленные прямо сейчас строки (группировки и обычные). Или видимые строки - видимые не во viewport-е, а которые должны быть показаны из-за раскрытий)\n */\n shownRows: readonly RowType[];\n expandedRowsIds: Set<string | number>;\n }) => boolean;\n };\n /**\n * `groupButton` - свойство для кастомизации кнопки с выпадающим списком\n */\n groupButton?: {\n getGroupedCount?: (props: {\n /**\n * высчитанное автоматически количество активных группировок.\n */\n currCount: number;\n /**\n * активные группировки.\n */\n groupedCols: string[];\n columns: {\n /**\n * `visible` - видимые в выпадающем списке колонки-группировки.\n */\n visible: string[];\n /**\n * `hidden` - невидимые или не участвующие в группировке колонки\n *\n * (columnConfig.rowsGrouping=undefined ||\n * columnConfig.rowsGrouping.groupByColumn=false).\n */\n hidden: string[];\n };\n }) => number;\n /**\n * `defaultCustomItems` - свойство для добавления ключей группировки, которых нет в таблице.\n *\n * `DropdownItemOption.value` - необходимо заполнять ключом, который существует в данных.\n */\n defaultCustomItems?: DropdownItemOption[];\n /**\n * `onItemSelect` - свойство для полного контроля над изменением группировки при выборе опций.\n *\n * `DropdownItemOption.value` - необходимо заполнять ключом, который существует в данных.\n */\n onItemSelect?: (props: {\n item: DropdownItemOption;\n setGroupedCols: React.Dispatch<React.SetStateAction<string[]>>;\n columns: {\n visible: string[];\n hidden: string[];\n };\n }) => void;\n };\n /**\n * `groupRowReplaceTo` - свойство для изменения данных сгруппированных строк. Может понадобиться в редких случаях.\n *\n * @param groupRow данные сгруппированной строки\n * @returns измененная группировка или строка без группировки — строка, которые заменит groupRow\n */\n groupRowReplaceTo?: (\n groupRow: GroupRow<RowType>,\n ) => GroupRow<RowType> | RowType;\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n domMetadata?: DomMetadata;\n};\n\nexport type RenderGroupCellProps<\n RowType extends ObjectForExtending,\n ColumnConfig extends LocalColumnInstance = LocalColumnInstance,\n> = {\n column: ColumnConfig;\n tabIndex: number;\n theme?: Theme;\n // TODO isExpanded: boolean;\n // TODO toggleGroup: () => void;\n} & GroupRow<RowType>;\n\nexport type ColumnRowsGrouping<\n RowType extends ObjectForExtending,\n ColumnConfig extends LocalColumnInstance,\n> = {\n /**\n * @default true - при наличии ColumnConfig.rowsGrouping\n */\n groupByColumn?: boolean;\n /**\n * @default ColumnConfig.key\n */\n columnGroupLabel?: string;\n /**\n * Свой контент ячейки строки-группы. Работает только в виде дерева: при\n * view: 'merged' строк-групп нет (группы показаны объединёнными ячейками),\n * поэтому этот рендер не вызывается.\n */\n renderGroupCell?: (\n props: RenderGroupCellProps<RowType, ColumnConfig>,\n ) => CanvasContent;\n};\n```\n\n## subRows (merged-вид)\n\nПоля subRows, относящиеся к merged-виду: `view: 'merged'` и `mergedColumns`\n(упорядоченный список колонок-предков, индекс = глубина уровня дерева).\n\n```typescript\ntype SubRows<RowType, RowIdType> = {\n /**\n * Возвращает дочерние строки узла (или undefined, если их нет).\n *\n * Функция должна быть стабильной — не менять поведение между рендерами.\n * Если она зависит от чего-то меняющегося, оберните её в useCallback.\n */\n getSubRows: (row: RowType) => RowType[] | undefined;\n /**\n * Возвращает уникальный ключ строки.\n *\n * Функция должна быть стабильной — не менять поведение между рендерами.\n * Если она зависит от чего-то меняющегося, оберните её в useCallback.\n */\n rowKeyGetter: (row: RowType) => RowIdType;\n /**\n * Внешний стейт развёрнутых строк.\n * Если не задан — используется внутренний useState.\n * При view: 'merged' не используется: сворачивания в этом виде нет.\n */\n expandedIdsState?: [\n Set<string | number>,\n (\n newV:\n | Set<string | number>\n | ((prev: Set<string | number>) => Set<string | number>),\n ) => void,\n ];\n /**\n * Как показывать дерево.\n * 'tree' (по умолчанию) — узлы с раскрытием (шевроны) и отступом по уровню.\n * 'merged' — дерево разворачивается в листья, а колонки-предки показаны\n * объединёнными ячейками. Структуру задаёт потребитель через getSubRows;\n * данные (пагинация, сортировка, поиск) остаются на его стороне.\n */\n view?: 'tree' | 'merged';\n /**\n * Только для view: 'merged'. Колонки-предки по порядку уровней:\n * mergedColumns[0] — верхний уровень, дальше глубже. Каждая такая колонка\n * показывает значение своего узла-предка (узел должен нести поле с этим именем)\n * и объединяется по его границам. Верхний уровень задаёт чекбокс и номер блока.\n */\n mergedColumns?: string[];\n};\n```",
52137
52481
  "api": [
52138
52482
  {
52139
52483
  "typeName": "MergedCellsRegion",
@@ -52141,7 +52485,7 @@
52141
52485
  },
52142
52486
  {
52143
52487
  "typeName": "MergedCellsAlign",
52144
- "source": "type MergedCellsAlign = {\n /** По горизонтали. @default из `contentAlign` колонки, иначе 'left' */\n horizontal?: 'left' | 'center' | 'right';\n /** По вертикали. @default 'center' */\n vertical?: 'top' | 'center' | 'bottom';\n};"
52488
+ "source": "type MergedCellsAlign = {\n /** По горизонтали. @default из `contentFormat.alignContent` колонки, иначе 'left' */\n horizontal?: 'left' | 'center' | 'right';\n /** По вертикали. @default 'center' */\n vertical?: 'top' | 'center' | 'bottom';\n};"
52145
52489
  },
52146
52490
  {
52147
52491
  "typeName": "RowsGrouping",
@@ -52301,12 +52645,16 @@
52301
52645
  "feature": "ColumnsControl",
52302
52646
  "legacy": false,
52303
52647
  "summary": "*tableConfig.columnsControl**",
52304
- "docs": "# ColumnsControl (TableCanvas)\n\n**tableConfig.columnsControl**\n\nНастройка колонок таблицы: скрытие, закрепление, изменение порядка (через Aside-панель и drag в header).\n\n## Ключевые особенности\n\n- Активация через `enable: true` — включает все подфичи по умолчанию\n- Скрытие колонок через свитчи в Aside (`hiding`)\n- Закрепление колонок (`pinning`)\n- Перетаскивание колонок в Aside (`reorderingAside`) и через header (`reorderingHeader`)\n- Дефолтные состояния при первом рендере (`pinnedDefault`, `hiddenDefault`, `orderDefault`)\n- Переопределение названий колонок в Aside (`columnsLabel`)\n- Колбэк при применении настроек (`onConfirm`)\n\n## Подфичи\n\nКаждая подфича по умолчанию наследует значение `enable`. Можно отключить отдельно:\n\n- **`hiding`** — скрытие/показ колонок через свитчи. `disableHiding` исключает конкретные колонки\n- **`pinning`** — закрепление колонок слева. `disablePinning` исключает конкретные колонки\n- **`reorderingAside`** — drag-and-drop порядка колонок в Aside-панели\n- **`reorderingHeader`** — drag-and-drop заголовков колонок прямо в таблице. `onReorderingHeader` — callback с новым порядком\n\n## Дефолтные состояния\n\n- **`pinnedDefault`** — массив ключей колонок, закреплённых при первом рендере\n- **`hiddenDefault`** — массив ключей скрытых колонок при первом рендере\n- **`orderDefault`** — массив ключей, определяющий начальный порядок колонок\n\n## onConfirm\n\nCallback вызывается при нажатии «Применить» в Aside. Получает текущее состояние (`pinned`, `order`, `hidden`, `changed`) и сеттеры для программного управления состоянием.\n\n## Меню закрепления в контрл-блоке (pinningMenu)\n\nКогда включено `pinning`, в правой зоне иконок контрл-блока автоматически появляется нативная кнопка-иконка (пин + шеврон) — быстрый доступ к закреплению выбранных колонок, дополняющий Aside-панель. Задаётся через `controlBlock.pinningMenu`.\n\n- Фича **нативная**: появляется сама при активном `pinning`, отдельно включать не нужно. Отключается `controlBlock.pinningMenu.enable: false`.\n- **Размеры** завязаны на размер контрл-блока (`controlBlock.size`) — в компактном (`xs`) ужимается вместе с остальными иконками.\n- Участвует в **компрессии**: при нехватке места уезжает в overflow-меню `…` вложенным подменю.\n\nПункты меню:\n\n- **Стандартные (из коробки):** «Открепить всё» и «Закрепить столбцы».\n- **Свои пункты** — через `pinningMenu.items` (напр. «Закрепить строки», «Закрепить шапку»). Порядок задаётся `order` (у нативных: `Открепить всё` = 100, `Закрепить столбцы` = 200), разделитель после пункта — `dividerAfter`. Совпадение `value` с нативным = переопределение.\n- Состояние и иконку продуктовых пунктов **контролирует продукт** (иконка — `ReactNode` или функция от `rowSize`, может отражать состояние).\n\nЛевая иконка (кнопка-действие):\n\n- Синеет, когда среди **видимых** колонок есть хотя бы одна закреплённая (скрыли видимость закреплённой — снова обычный цвет).\n- Tooltip и действие зависят от выделения: нет выделения — подсказка выбрать колонки; выбраны незакреплённые — «Закрепить»; выбраны только закреплённые — «Открепить».\n- После закрепления выделение **переезжает** за колонками (закреплённые уезжают влево), соседние сливаются без разделителей.\n- Клик по действию закрепления **без выделенных колонок** шлёт событие в `tableConfig.notifications` (`type: 'pin'`, `code: 'no-selection'`) — продукт показывает свою подсказку. Подробнее — в разделе [Notifications](?path=/docs/локальные-компоненты-tablecanvas-notifications--docs).\n\nПример добавления своих пунктов — в стори «ColumnsControl: доп. пункты меню закрепления».\n\n> Подробнее о типах и пропсах — [ColumnsControl API](?path=/docs/локальные-компоненты-tablecanvas-columnscontrol-api--docs)",
52305
- "apiDocs": "# ColumnsControl API\n\n## ColumnsControlConfig\n\n```typescript\ntype ColumnsControlConfig = {\n enable: boolean;\n /**\n * @default enable\n */\n hiding?: boolean;\n /**\n * @default enable\n */\n pinning?: boolean;\n /**\n * @default enable\n */\n reorderingAside?: boolean;\n /**\n * reorderingHeader - активация изменения порядка колонок посредством перемещения шапок колонок таблицы\n */\n /**\n * @default enable\n */\n reorderingHeader?: boolean;\n onReorderingHeader?: (params: {\n newOrder: string[];\n sourceKey: string;\n targetKey: string;\n }) => void;\n\n columnsLabel?: Record<\n string,\n ReactNode | ((isHidden: boolean, isPinned: boolean) => ReactNode)\n >;\n\n /**\n * Виртуализация списка колонок в правом сайдбаре: в DOM держатся только\n * видимые строки списка. false — отключить полностью; { minCount } —\n * включать, когда строк в списке не меньше порога.\n * @default { minCount: 30 }\n */\n virtualization?: boolean | { minCount?: number };\n\n orderDefault?: string[];\n\n pinnedDefault?: string[];\n disablePinning?: string[];\n\n hiddenDefault?: string[];\n disableHiding?: string[];\n\n onConfirm?: (\n params: {\n pinned: string[];\n order: string[];\n hidden: string[];\n changed: { pinned?: 'pinned'; order?: 'order'; hidden?: 'hidden' };\n },\n setters: {\n setColumnsOrder: (value: React.SetStateAction<string[]>) => void;\n setPinnedCols: (value: React.SetStateAction<string[]>) => void;\n setHiddenCols: (value: React.SetStateAction<string[]>) => void;\n },\n ) => void;\n /**\n * DomMetadata для кнопок закрепления столбцов\n */\n pinDomMetadata?: DomMetadata;\n /**\n * DomMetadata для свитчеров скрытия/показа столбцов\n */\n switchDomMetadata?: DomMetadata;\n};\n```\n\n## PinningMenuConfig\n\nМеню закрепления в контрл-блоке (`controlBlock.pinningMenu`). Появляется, когда включено `columnsControl.pinning`.\n\n```typescript\ntype PinningMenuConfig = {\n /**\n * Явное вкл/выкл фичи.\n * @default columnsControl.pinning\n */\n enable?: boolean;\n /**\n * Продуктовые пункты меню — мёржатся с нативными (override по value,\n * сортировка по order).\n */\n items?: PinningMenuItem[];\n /**\n * DomMetadata левой кнопки-иконки закрепления. Её `dataAttributes`\n * навешиваются на кнопку-иконку (data-атрибуты для e2e-тестов, аналитики и\n * онбординга — поиск элемента в DOM). Пример:\n * `{ dataAttributes: { 'data-testid': 'pinning-icon' } }`.\n */\n iconDomMetadata?: DomMetadata;\n};\n```\n\n## PinningMenuItem\n\nПункт меню закрепления — нативный или добавленный продуктом.\n\n```typescript\ntype PinningMenuItem = {\n /**\n * Уникальный ключ пункта. Совпадение с value нативного пункта = override\n * (продуктовые поля перекрывают нативные).\n */\n value: string;\n label: string;\n /**\n * Иконка слева в пункте. Узел рендерится как есть, либо функция (ctx),\n * чтобы подстроить размер под rowSize (в т.ч. внутри overflow-дропдауна\n * при компрессии). Стейт/иконку продуктовых пунктов контролирует продукт.\n */\n icon?: FeatureIconRender;\n /**\n * Действие пункта. У нативных пунктов задаётся таблицей; продукт может\n * переопределить.\n */\n onClick?: () => void;\n /**\n * Порядок в списке (по возрастанию). Нативные: reset=100, pin-columns=200.\n * Пункты без order идут в конец, сохраняя исходный порядок.\n */\n order?: number;\n /**\n * Нарисовать разделитель после пункта.\n * @default false\n */\n dividerAfter?: boolean;\n disabled?: boolean;\n};\n```",
52648
+ "docs": "# ColumnsControl (TableCanvas)\n\n**tableConfig.columnsControl**\n\nНастройка колонок таблицы: скрытие, закрепление, изменение порядка (через Aside-панель и drag в header).\n\n## Ключевые особенности\n\n- Активация через `enable: true` — включает все подфичи по умолчанию\n- Скрытие колонок через свитчи в Aside (`hiding`)\n- Закрепление колонок (`pinning`)\n- Перетаскивание колонок в Aside (`reorderingAside`) и через header (`reorderingHeader`)\n- Дефолтные состояния при первом рендере (`pinnedDefault`, `hiddenDefault`, `orderDefault`)\n- Переопределение названий колонок в Aside (`columnsLabel`)\n- Колбэк при применении настроек (`onConfirm`)\n- Синий индикатор скрытых столбцов в шапке (`hiddenColumnsIndicator`)\n\n## Подфичи\n\nКаждая подфича по умолчанию наследует значение `enable`. Можно отключить отдельно:\n\n- **`hiding`** — скрытие/показ колонок через свитчи. `disableHiding` исключает конкретные колонки\n- **`pinning`** — закрепление колонок слева. `disablePinning` исключает конкретные колонки\n- **`reorderingAside`** — drag-and-drop порядка колонок в Aside-панели\n- **`reorderingHeader`** — drag-and-drop заголовков колонок прямо в таблице. `onReorderingHeader` — callback с новым порядком\n\n## Дефолтные состояния\n\n- **`pinnedDefault`** — массив ключей колонок, закреплённых при первом рендере\n- **`hiddenDefault`** — массив ключей скрытых колонок при первом рендере\n- **`orderDefault`** — массив ключей, определяющий начальный порядок колонок\n\n## onConfirm\n\nCallback вызывается при нажатии «Применить» в Aside. Получает текущее состояние (`pinned`, `order`, `hidden`, `changed`) и сеттеры для программного управления состоянием.\n\n## Индикатор скрытых столбцов (hiddenColumnsIndicator)\n\nКогда между двумя видимыми колонками спрятаны столбцы, на границе в шапке вместо обычного бордера рисуется толстая синяя полосатая линия. Так пользователь видит, что тут есть скрытый промежуток, и может быстро его раскрыть.\n\n- Фича **нативная**: включается сама вместе с `hiding`. Отдельно управляется флагом `hiddenColumnsIndicator` (по умолчанию `true` при активном `hiding`). Отключается `hiddenColumnsIndicator: false`.\n- **Одна полоса на весь промежуток**: сколько бы столбцов ни было скрыто подряд, линия одна. Двойной клик раскрывает сразу весь промежуток.\n- **Наведение** на линию показывает тултип «Дважды нажмите, чтобы развернуть».\n- **Ресайз** соседней колонки за эту же границу работает как обычно (тянем перетаскиванием), меняется только двойной клик: он раскрывает промежуток вместо автосайза. Если полоса высокая, тянуть за ресайз можно по всей её высоте, а не только в листовом ряду.\n- **Края таблицы**: если скрыт первый или последний столбец, линия прижимается к левому или правому краю.\n- **Сгруппированная шапка**: фича относится только к колонкам, сами группы не скрываются, а высота полосы подстраивается под то, что скрыто. Если спрятаны только листья внутри групп, полоса низкая (в листовом ряду). Если среди скрытых есть большая колонка верхнего уровня, полоса тянется вверх на всю высоту шапки. Высоту дополнительно ограничивает общая группа видимых соседей: пока они под одной группой, полоса не поднимается выше её низа.\n\n### onHiddenColumnsIndicatorExpand\n\nКолбэк-уведомление о раскрытии промежутка двойным кликом. Само раскрытие (снятие скрытия) делает обёртка; колбэк нужен, чтобы продукт мог подписаться на это событие. В него приходит объект с полями: `keys` (ключи раскрываемых столбцов), `leftKey` и `rightKey` (видимые соседи слева и справа от линии, `undefined` на краю таблицы).\n\nСрабатывает **только** на двойной клик по линии индикатора. Обычное изменение видимости через панель настройки колонок (Aside) или контекстное меню продукта его не вызывает: для этих сценариев есть общий стейт скрытых колонок и `onConfirm`.\n\nПримеры: стори «ColumnsControl: индикатор скрытых столбцов» и рядом (по бокам, выключен, в группе, в скваш-колонках).\n\n## Меню закрепления в контрл-блоке (pinningMenu)\n\nКогда включено `pinning`, в правой зоне иконок контрл-блока автоматически появляется нативная кнопка-иконка (пин + шеврон) — быстрый доступ к закреплению выбранных колонок, дополняющий Aside-панель. Задаётся через `controlBlock.pinningMenu`.\n\n- Фича **нативная**: появляется сама при активном `pinning`, отдельно включать не нужно. Отключается `controlBlock.pinningMenu.enable: false`.\n- **Размеры** завязаны на размер контрл-блока (`controlBlock.size`) — в компактном (`xs`) ужимается вместе с остальными иконками.\n- Участвует в **компрессии**: при нехватке места уезжает в overflow-меню `…` вложенным подменю.\n\nПункты меню:\n\n- **Стандартные (из коробки):** «Открепить всё» и «Закрепить столбцы».\n- **Свои пункты** — через `pinningMenu.items` (напр. «Закрепить строки», «Закрепить шапку»). Порядок задаётся `order` (у нативных: `Открепить всё` = 100, `Закрепить столбцы` = 200), разделитель после пункта — `dividerAfter`. Совпадение `value` с нативным = переопределение.\n- Состояние и иконку продуктовых пунктов **контролирует продукт** (иконка — `ReactNode` или функция от `rowSize`, может отражать состояние).\n\nЛевая иконка (кнопка-действие):\n\n- Синеет, когда среди **видимых** колонок есть хотя бы одна закреплённая (скрыли видимость закреплённой — снова обычный цвет).\n- Tooltip и действие зависят от выделения: нет выделения — подсказка выбрать колонки; выбраны незакреплённые — «Закрепить»; выбраны только закреплённые — «Открепить».\n- После закрепления выделение **переезжает** за колонками (закреплённые уезжают влево), соседние сливаются без разделителей.\n- Клик по действию закрепления **без выделенных колонок** шлёт событие в `tableConfig.notifications` (`type: 'pin'`, `code: 'no-selection'`) — продукт показывает свою подсказку. Подробнее — в разделе [Notifications](?path=/docs/локальные-компоненты-tablecanvas-notifications--docs).\n\nПример добавления своих пунктов — в стори «ColumnsControl: доп. пункты меню закрепления».\n\n> Подробнее о типах и пропсах — [ColumnsControl API](?path=/docs/локальные-компоненты-tablecanvas-columnscontrol-api--docs)",
52649
+ "apiDocs": "# ColumnsControl API\n\n## ColumnsControlConfig\n\n```typescript\ntype ColumnsControlConfig = {\n enable: boolean;\n /**\n * @default enable\n */\n hiding?: boolean;\n /**\n * @default enable\n */\n pinning?: boolean;\n /**\n * @default enable\n */\n reorderingAside?: boolean;\n /**\n * reorderingHeader - активация изменения порядка колонок посредством перемещения шапок колонок таблицы\n */\n /**\n * @default enable\n */\n reorderingHeader?: boolean;\n onReorderingHeader?: (params: {\n newOrder: string[];\n sourceKey: string;\n targetKey: string;\n }) => void;\n\n columnsLabel?: Record<\n string,\n ReactNode | ((isHidden: boolean, isPinned: boolean) => ReactNode)\n >;\n\n /**\n * Виртуализация списка колонок в правом сайдбаре: в DOM держатся только\n * видимые строки списка. false — отключить полностью; { minCount } —\n * включать, когда строк в списке не меньше порога.\n * @default { minCount: 30 }\n */\n virtualization?: boolean | { minCount?: number };\n\n orderDefault?: string[];\n\n pinnedDefault?: string[];\n disablePinning?: string[];\n\n hiddenDefault?: string[];\n disableHiding?: string[];\n /**\n * Индикатор скрытых столбцов: синяя полосатая линия в шапке на границе, за\n * которой скрыты столбцы. Двойной клик по линии раскрывает весь промежуток,\n * ресайз на этой границе работает как обычно.\n * @default hiding\n */\n hiddenColumnsIndicator?: boolean;\n /**\n * Уведомление о раскрытии промежутка двойным кликом по индикатору скрытых\n * столбцов. Само раскрытие (снятие скрытия) обёртка делает сама; колбэк нужен,\n * чтобы внешний потребитель мог подписаться на это событие и узнать, какие\n * столбцы раскрылись и между какими видимыми колонками стояла линия.\n */\n onHiddenColumnsIndicatorExpand?: (\n info: HiddenColumnsIndicatorExpandInfo,\n ) => void;\n\n onConfirm?: (\n params: {\n pinned: string[];\n order: string[];\n hidden: string[];\n changed: { pinned?: 'pinned'; order?: 'order'; hidden?: 'hidden' };\n },\n setters: {\n setColumnsOrder: (value: React.SetStateAction<string[]>) => void;\n setPinnedCols: (value: React.SetStateAction<string[]>) => void;\n setHiddenCols: (value: React.SetStateAction<string[]>) => void;\n },\n ) => void;\n /**\n * DomMetadata для кнопок закрепления столбцов\n */\n pinDomMetadata?: DomMetadata;\n /**\n * DomMetadata для свитчеров скрытия/показа столбцов\n */\n switchDomMetadata?: DomMetadata;\n};\n```\n\n## HiddenColumnsIndicatorExpandInfo\n\nДанные, которые приходят в колбэк `onHiddenColumnsIndicatorExpand` при раскрытии промежутка двойным кликом по индикатору скрытых столбцов.\n\n```typescript\ntype HiddenColumnsIndicatorExpandInfo = {\n /** Ключи скрытых столбцов, которые раскрываются (весь промежуток за линией). */\n keys: string[];\n /** Видимый сосед слева от линии. undefined, если линия у левого края таблицы. */\n leftKey?: string;\n /** Видимый сосед справа от линии. undefined, если линия у правого края таблицы. */\n rightKey?: string;\n};\n```\n\n## PinningMenuConfig\n\nМеню закрепления в контрл-блоке (`controlBlock.pinningMenu`). Появляется, когда включено `columnsControl.pinning`.\n\n```typescript\ntype PinningMenuConfig = {\n /**\n * Явное вкл/выкл фичи.\n * @default columnsControl.pinning\n */\n enable?: boolean;\n /**\n * Продуктовые пункты меню — мёржатся с нативными (override по value,\n * сортировка по order).\n */\n items?: PinningMenuItem[];\n /**\n * DomMetadata левой кнопки-иконки закрепления. Её `dataAttributes`\n * навешиваются на кнопку-иконку (data-атрибуты для e2e-тестов, аналитики и\n * онбординга — поиск элемента в DOM). Пример:\n * `{ dataAttributes: { 'data-testid': 'pinning-icon' } }`.\n */\n iconDomMetadata?: DomMetadata;\n};\n```\n\n## PinningMenuItem\n\nПункт меню закрепления — нативный или добавленный продуктом.\n\n```typescript\ntype PinningMenuItem = {\n /**\n * Уникальный ключ пункта. Совпадение с value нативного пункта = override\n * (продуктовые поля перекрывают нативные).\n */\n value: string;\n label: string;\n /**\n * Иконка слева в пункте. Узел рендерится как есть, либо функция (ctx),\n * чтобы подстроить размер под rowSize (в т.ч. внутри overflow-дропдауна\n * при компрессии). Стейт/иконку продуктовых пунктов контролирует продукт.\n */\n icon?: FeatureIconRender;\n /**\n * Действие пункта. У нативных пунктов задаётся таблицей; продукт может\n * переопределить.\n */\n onClick?: () => void;\n /**\n * Порядок в списке (по возрастанию). Нативные: reset=100, pin-columns=200.\n * Пункты без order идут в конец, сохраняя исходный порядок.\n */\n order?: number;\n /**\n * Нарисовать разделитель после пункта.\n * @default false\n */\n dividerAfter?: boolean;\n disabled?: boolean;\n};\n```",
52306
52650
  "api": [
52307
52651
  {
52308
52652
  "typeName": "ColumnsControlConfig",
52309
- "source": "type ColumnsControlConfig = {\n enable: boolean;\n /**\n * @default enable\n */\n hiding?: boolean;\n /**\n * @default enable\n */\n pinning?: boolean;\n /**\n * @default enable\n */\n reorderingAside?: boolean;\n /**\n * reorderingHeader - активация изменения порядка колонок посредством перемещения шапок колонок таблицы\n */\n /**\n * @default enable\n */\n reorderingHeader?: boolean;\n onReorderingHeader?: (params: {\n newOrder: string[];\n sourceKey: string;\n targetKey: string;\n }) => void;\n\n columnsLabel?: Record<\n string,\n ReactNode | ((isHidden: boolean, isPinned: boolean) => ReactNode)\n >;\n\n /**\n * Виртуализация списка колонок в правом сайдбаре: в DOM держатся только\n * видимые строки списка. false — отключить полностью; { minCount } —\n * включать, когда строк в списке не меньше порога.\n * @default { minCount: 30 }\n */\n virtualization?: boolean | { minCount?: number };\n\n orderDefault?: string[];\n\n pinnedDefault?: string[];\n disablePinning?: string[];\n\n hiddenDefault?: string[];\n disableHiding?: string[];\n\n onConfirm?: (\n params: {\n pinned: string[];\n order: string[];\n hidden: string[];\n changed: { pinned?: 'pinned'; order?: 'order'; hidden?: 'hidden' };\n },\n setters: {\n setColumnsOrder: (value: React.SetStateAction<string[]>) => void;\n setPinnedCols: (value: React.SetStateAction<string[]>) => void;\n setHiddenCols: (value: React.SetStateAction<string[]>) => void;\n },\n ) => void;\n /**\n * DomMetadata для кнопок закрепления столбцов\n */\n pinDomMetadata?: DomMetadata;\n /**\n * DomMetadata для свитчеров скрытия/показа столбцов\n */\n switchDomMetadata?: DomMetadata;\n};"
52653
+ "source": "type ColumnsControlConfig = {\n enable: boolean;\n /**\n * @default enable\n */\n hiding?: boolean;\n /**\n * @default enable\n */\n pinning?: boolean;\n /**\n * @default enable\n */\n reorderingAside?: boolean;\n /**\n * reorderingHeader - активация изменения порядка колонок посредством перемещения шапок колонок таблицы\n */\n /**\n * @default enable\n */\n reorderingHeader?: boolean;\n onReorderingHeader?: (params: {\n newOrder: string[];\n sourceKey: string;\n targetKey: string;\n }) => void;\n\n columnsLabel?: Record<\n string,\n ReactNode | ((isHidden: boolean, isPinned: boolean) => ReactNode)\n >;\n\n /**\n * Виртуализация списка колонок в правом сайдбаре: в DOM держатся только\n * видимые строки списка. false — отключить полностью; { minCount } —\n * включать, когда строк в списке не меньше порога.\n * @default { minCount: 30 }\n */\n virtualization?: boolean | { minCount?: number };\n\n orderDefault?: string[];\n\n pinnedDefault?: string[];\n disablePinning?: string[];\n\n hiddenDefault?: string[];\n disableHiding?: string[];\n /**\n * Индикатор скрытых столбцов: синяя полосатая линия в шапке на границе, за\n * которой скрыты столбцы. Двойной клик по линии раскрывает весь промежуток,\n * ресайз на этой границе работает как обычно.\n * @default hiding\n */\n hiddenColumnsIndicator?: boolean;\n /**\n * Уведомление о раскрытии промежутка двойным кликом по индикатору скрытых\n * столбцов. Само раскрытие (снятие скрытия) обёртка делает сама; колбэк нужен,\n * чтобы внешний потребитель мог подписаться на это событие и узнать, какие\n * столбцы раскрылись и между какими видимыми колонками стояла линия.\n */\n onHiddenColumnsIndicatorExpand?: (\n info: HiddenColumnsIndicatorExpandInfo,\n ) => void;\n\n onConfirm?: (\n params: {\n pinned: string[];\n order: string[];\n hidden: string[];\n changed: { pinned?: 'pinned'; order?: 'order'; hidden?: 'hidden' };\n },\n setters: {\n setColumnsOrder: (value: React.SetStateAction<string[]>) => void;\n setPinnedCols: (value: React.SetStateAction<string[]>) => void;\n setHiddenCols: (value: React.SetStateAction<string[]>) => void;\n },\n ) => void;\n /**\n * DomMetadata для кнопок закрепления столбцов\n */\n pinDomMetadata?: DomMetadata;\n /**\n * DomMetadata для свитчеров скрытия/показа столбцов\n */\n switchDomMetadata?: DomMetadata;\n};"
52654
+ },
52655
+ {
52656
+ "typeName": "HiddenColumnsIndicatorExpandInfo",
52657
+ "source": "type HiddenColumnsIndicatorExpandInfo = {\n /** Ключи скрытых столбцов, которые раскрываются (весь промежуток за линией). */\n keys: string[];\n /** Видимый сосед слева от линии. undefined, если линия у левого края таблицы. */\n leftKey?: string;\n /** Видимый сосед справа от линии. undefined, если линия у правого края таблицы. */\n rightKey?: string;\n};"
52310
52658
  },
52311
52659
  {
52312
52660
  "typeName": "PinningMenuConfig",
@@ -52335,6 +52683,36 @@
52335
52683
  "displayName": "ID",
52336
52684
  "type": "full-code",
52337
52685
  "code": "import { ColumnConfig, TableCanvas } from '@daisforge/ui/components/TableCanvas';\n\n() => {\n const [rows] = useState(createRows);\n\n const columnConfig = useMemo<readonly ColumnConfig<Row>[]>(\n () => [\n {\n key: 'id',\n name: 'ID',\n },\n {\n key: 'task',\n name: 'Title',\n },\n {\n key: 'priority',\n name: 'Priority',\n },\n {\n key: 'issueType',\n name: 'Issue Type',\n },\n {\n key: 'developer',\n name: 'Developer',\n },\n {\n key: 'tr1',\n name: 'TR',\n },\n {\n key: 'complete',\n name: '% Complete',\n },\n ],\n [],\n );\n\n const selectingRowStateAndSetter = useState(\n (): ReadonlySet<string | number> => new Set(),\n );\n\n return (\n <TableCanvas\n tableConfig={{\n selecting: {\n rowCheckboxDisabled: (row) => row.id === 2,\n rowShowCheckbox: (row) => row.id !== 3,\n state: selectingRowStateAndSetter,\n rowKeyGetter: (r) => r.id + r.issueType,\n showDefault: false,\n },\n containerStyle: { height: 700 },\n columnsControl: {\n enable: true,\n hiding: true,\n disableHiding: ['id'],\n pinning: true,\n disablePinning: ['developer'],\n reorderingAside: true,\n reorderingHeader: true,\n columnsLabel: {\n task: 'Задачи',\n },\n orderDefault: ['id', 'issueType', 'task'],\n hiddenDefault: ['tr1'],\n pinnedDefault: ['complete'],\n onConfirm: ({ order, hidden, pinned }, _setters) => {\n // eslint-disable-next-line no-alert\n alert(`\n order: ${order.join(', ')}\n pinned: ${pinned.join(', ')}\n hidden: ${hidden.join(', ')}\n `);\n },\n },\n }}\n columnConfig={columnConfig}\n rows={rows}\n />\n );\n }"
52686
+ },
52687
+ {
52688
+ "exportName": "HiddenColumnsIndicator",
52689
+ "displayName": "ColumnsControl: индикатор скрытых столбцов",
52690
+ "type": "full-code",
52691
+ "code": "import { ColumnConfig, TableCanvas } from '@daisforge/ui/components/TableCanvas';\n\n() => {\n const [rows] = useState(createRows);\n\n return (\n <TableCanvas\n tableConfig={{\n containerStyle: { height: 420 },\n rowMarkers: { startIndex: 1 },\n columnsControl: {\n enable: true,\n hiding: true,\n hiddenDefault: ['priority', 'developer', 'tr1'],\n },\n }}\n columnConfig={INDICATOR_COLS}\n rows={rows}\n />\n );\n }"
52692
+ },
52693
+ {
52694
+ "exportName": "HiddenColumnsIndicatorEdges",
52695
+ "displayName": "ColumnsControl: индикатор скрытых столбцов по бокам",
52696
+ "type": "full-code",
52697
+ "code": "import { ColumnConfig, TableCanvas } from '@daisforge/ui/components/TableCanvas';\n\n() => {\n const [rows] = useState(createRows);\n\n return (\n <TableCanvas\n tableConfig={{\n containerStyle: { height: 420 },\n rowMarkers: { startIndex: 1 },\n columnsControl: {\n enable: true,\n hiding: true,\n pinning: true,\n pinnedDefault: ['task'],\n hiddenDefault: ['id', 'complete'],\n },\n }}\n columnConfig={INDICATOR_COLS}\n rows={rows}\n />\n );\n }"
52698
+ },
52699
+ {
52700
+ "exportName": "HiddenColumnsIndicatorDisabled",
52701
+ "displayName": "ColumnsControl: индикатор скрытых столбцов выключен",
52702
+ "type": "full-code",
52703
+ "code": "import { ColumnConfig, TableCanvas } from '@daisforge/ui/components/TableCanvas';\n\n() => {\n const [rows] = useState(createRows);\n\n return (\n <TableCanvas\n tableConfig={{\n containerStyle: { height: 420 },\n rowMarkers: { startIndex: 1 },\n columnsControl: {\n enable: true,\n hiding: true,\n hiddenColumnsIndicator: false,\n hiddenDefault: ['priority'],\n },\n }}\n columnConfig={INDICATOR_COLS}\n rows={rows}\n />\n );\n }"
52704
+ },
52705
+ {
52706
+ "exportName": "HiddenColumnsIndicatorGrouped",
52707
+ "displayName": "ColumnsControl: индикатор скрытых столбцов в группе",
52708
+ "type": "full-code",
52709
+ "code": "import { ColumnConfig, TableCanvas } from '@daisforge/ui/components/TableCanvas';\n\n() => {\n const [rows] = useState(createRows);\n\n const columnConfig: ColumnOrColumnGroupConfig<Row>[] = [\n { key: 'id', name: 'ID', width: 120 },\n {\n key: 'metrics',\n name: 'Показатели',\n children: [\n { key: 'task', name: 'План', width: 130 },\n { key: 'priority', name: 'Факт', width: 130 },\n { key: 'issueType', name: 'Прогноз', width: 130 },\n ],\n },\n {\n key: 'grade',\n name: 'Оценка',\n children: [\n { key: 'developer', name: 'Инд', width: 130 },\n { key: 'complete', name: 'Итог', width: 130 },\n ],\n },\n ];\n\n return (\n <TableCanvas\n tableConfig={{\n containerStyle: { height: 420 },\n rowMarkers: { startIndex: 1 },\n columnsControl: {\n enable: true,\n hiding: true,\n hiddenDefault: ['priority', 'developer'],\n },\n }}\n columnConfig={columnConfig}\n rows={rows}\n />\n );\n }"
52710
+ },
52711
+ {
52712
+ "exportName": "HiddenColumnsIndicatorSquashed",
52713
+ "displayName": "ColumnsControl: индикатор скрытых столбцов в скваш-колонках",
52714
+ "type": "full-code",
52715
+ "code": "import { ColumnConfig, TableCanvas } from '@daisforge/ui/components/TableCanvas';\n\n() => {\n const [rows] = useState(createRows);\n\n const columnConfig: ColumnOrColumnGroupConfig<Row>[] = [\n { key: 'id', name: 'ID', width: 100 },\n {\n key: 'deep',\n name: 'Глубокая',\n children: [\n {\n key: 'sub',\n name: 'Подгруппа',\n children: [\n { key: 'task', name: 'A', width: 110 },\n { key: 'priority', name: 'B', width: 110 },\n { key: 'issueType', name: 'B1', width: 110 },\n ],\n },\n ],\n },\n { key: 'developer', name: 'Ср', width: 130 },\n {\n key: 'shallow',\n name: 'Мелкая',\n children: [{ key: 'complete', name: 'C', width: 160 }],\n },\n ];\n\n return (\n <TableCanvas\n tableConfig={{\n containerStyle: { height: 420 },\n rowMarkers: { startIndex: 1 },\n columnsGrouping: { squashEmptyCells: true },\n columnsControl: {\n enable: true,\n hiding: true,\n hiddenDefault: ['issueType', 'developer'],\n },\n }}\n columnConfig={columnConfig}\n rows={rows}\n />\n );\n }"
52338
52716
  }
52339
52717
  ]
52340
52718
  },
@@ -52779,7 +53157,7 @@
52779
53157
  "legacy": false,
52780
53158
  "summary": "*tableConfig.\\*.domMetadata**",
52781
53159
  "docs": "# DomMetadata\n\n**tableConfig.\\*.domMetadata**\n\nМетки для автоматизированного тестирования, аналитики и онбординга.\n\n`DomMetadata` позволяет навешивать CSS-классы, data-атрибуты и обработчики кликов на интерактивные элементы таблицы.\nЭто нужно для:\n\n- **Аналитики** — трекинг кликов по кнопкам таблицы\n- **Автотестов** — поиск элементов по `data-testid`\n- **Онбординга** — привязка подсказок к конкретным элементам\n\n## Поддерживаемые элементы (className, dataAttributes)\n\nСледующие элементы поддерживают `className` и `dataAttributes` через `domMetadata`:\n\n**Control Block (панель управления):**\n\n- **Редактирование** — `tableConfig.editing.domMetadata`\n- **Полноэкранный режим** — `tableConfig.fullScreenEnabled.domMetadata`\n- **Размер строки** — `tableConfig.rowSize.domMetadata`\n- **Переключение вида** (строки/карточки) — `tableConfig.view.domMetadata`\n- **Группировка строк** — `tableConfig.rowsGrouping.domMetadata`\n- **Поиск** — `tableConfig.searching.domMetadata`\n- **Итоговые строки** — `tableConfig.summaryRows.domMetadata`\n- **KeyText** (controlBlock) — `tableConfig.keyText.controlBlock.domMetadata`\n- **KeyText** (sidebar) — `tableConfig.keyText.sidebar.domMetadata`\n\n**Selecting (выбор строк):**\n\n- **Чекбокс \"Выбрать все\"** (controlBlock) — `tableConfig.selecting.controlBlock.domMetadata`\n- **Свитч в сайдбаре** — `tableConfig.selecting.sidebar.domMetadata`\n\n**Sidebar (правая панель):**\n\n- **Табы сайдбара** — `tableConfig.sidebarConfig.defaultTabs[].domMetadata`\n- **Подтабы настроек** (Фильтры, Столбцы) — `tableConfig.sidebarConfig.defaultTabs[{id:'filtering'|'columns'}].domMetadata`\n\n**Другие:**\n\n- **Кнопка сворачивания таблицы** — `tableConfig.collapse.domMetadata`\n\n## Элементы с расширенным onClick (className, dataAttributes, onClick + detail)\n\nВ дополнение к `className` и `dataAttributes`, следующие элементы поддерживают `onClick` с контекстом `detail`:\n\n- **Группировать** (чекбоксы, сброс) — `tableConfig.rowsGrouping.domMetadata` — actions: `toggle-group`, `reset-groups`, `custom-item-select`\n- **Кнопка размера строки** — `tableConfig.rowSize.domMetadata` — action: `change-row-size`\n- **Шестеренка настроек** — `tableConfig.sidebarConfig.defaultTabs[{id:'tableSettings'}].domMetadata` — action: `toggle-sidebar-tab`\n- **Крестик закрыть сайдбар** — тот же `domMetadata` таба — action: `close-sidebar`\n- **Закрепить столбец** — `tableConfig.columnsControl.pinDomMetadata` — actions: `pin-column`, `unpin-column`\n- **Свитчер видимости столбца** — `tableConfig.columnsControl.switchDomMetadata` — actions: `show-column`, `hide-column`\n\n## onClick\n\nОбработчик `onClick` вызывается **после** основной логики элемента. Он не мешает работе кнопки и не вызывает `stopPropagation`.\n\n```tsx\nonClick?: (\n e?: React.MouseEvent<HTMLElement>, // MouseEvent (undefined для элементов внутри Dropdown)\n detail?: Record<string, unknown> // контекст: action, columnKey, size и др.\n) => void;\n```\n\n### Примеры detail\n\n```ts\n// Группировка\n{ action: 'toggle-group', columnKey: 'status' }\n{ action: 'reset-groups' }\n\n// Размер строки\n{ action: 'change-row-size', size: 'medium' }\n\n// Сайдбар\n{ action: 'toggle-sidebar-tab', tabId: 'tableSettings' }\n{ action: 'close-sidebar' }\n\n// Столбцы\n{ action: 'pin-column', columnKey: 'name' }\n{ action: 'unpin-column', columnKey: 'name' }\n{ action: 'hide-column', columnKey: 'name' }\n{ action: 'show-column', columnKey: 'name' }\n```\n\nПодробнее о типах — в разделе [API](?path=/docs/локальные-компоненты-tablecanvas-dommetadata-api--docs).",
52782
- "apiDocs": "# DomMetadata API\n\n## DomMetadata\n\n```typescript\ntype DomMetadata = {\n /**\n * CSS класс для стилизации и поиска элемента\n *\n * @example 'user-profile-card'\n * @example 'onboarding-step-1'\n */\n className?: string;\n /**\n * Data-атрибуты для тестирования, аналитики и онбординга\n *\n * @example { 'data-testid': 'submit-button', 'data-analytics': 'click-event' }\n */\n dataAttributes?: DataAttributes;\n /**\n * Обработчик клика для аналитики и трекинга\n *\n * Вызывается вместе с основным обработчиком элемента (не заменяет его).\n * Не вызывает stopPropagation — оригинальная логика кнопки сохраняется.\n *\n * @param e - MouseEvent (может быть undefined для элементов внутри Dropdown)\n * @param detail - контекст действия: action, columnKey, size и др.\n *\n * @example onClick: (e, detail) => analytics.track(detail?.action, detail)\n */\n onClick?: (\n e?: React.MouseEvent<HTMLElement>,\n detail?: Record<string, unknown>,\n ) => void;\n};\n```\n\n## DOM_METADATA_ACTIONS\n\n```typescript\nexport const DOM_METADATA_ACTIONS = {\n /** Включение/выключение группировки по столбцу. detail.columnKey — ключ столбца */\n TOGGLE_GROUP: 'toggle-group',\n /** Сброс всех группировок */\n RESET_GROUPS: 'reset-groups',\n /** Выбор пункта в кастомном onItemSelect группировки. detail.columnKey — ключ */\n CUSTOM_ITEM_SELECT: 'custom-item-select',\n /** Переключение размера строки. detail.size — новый размер ('small' | 'medium' | 'big') */\n CHANGE_ROW_SIZE: 'change-row-size',\n /** Клик по табу сайдбара (шестерёнка и др.). detail.tabId — id таба */\n TOGGLE_SIDEBAR_TAB: 'toggle-sidebar-tab',\n /** Закрытие сайдбара (крестик) */\n CLOSE_SIDEBAR: 'close-sidebar',\n /** Закрепление столбца. detail.columnKey — ключ столбца */\n PIN_COLUMN: 'pin-column',\n /** Открепление столбца. detail.columnKey — ключ столбца */\n UNPIN_COLUMN: 'unpin-column',\n /** Скрытие столбца. detail.columnKey — ключ столбца */\n HIDE_COLUMN: 'hide-column',\n /** Показ столбца. detail.columnKey — ключ столбца */\n SHOW_COLUMN: 'show-column',\n} as const;\n```\n\n## DomMetadataAction\n\n```typescript\ntype DomMetadataAction =\n (typeof DOM_METADATA_ACTIONS)[keyof typeof DOM_METADATA_ACTIONS];\n```\n\n## ColumnsControlConfig\n\n```typescript\ntype ColumnsControlConfig = {\n enable: boolean;\n /**\n * @default enable\n */\n hiding?: boolean;\n /**\n * @default enable\n */\n pinning?: boolean;\n /**\n * @default enable\n */\n reorderingAside?: boolean;\n /**\n * reorderingHeader - активация изменения порядка колонок посредством перемещения шапок колонок таблицы\n */\n /**\n * @default enable\n */\n reorderingHeader?: boolean;\n onReorderingHeader?: (params: {\n newOrder: string[];\n sourceKey: string;\n targetKey: string;\n }) => void;\n\n columnsLabel?: Record<\n string,\n ReactNode | ((isHidden: boolean, isPinned: boolean) => ReactNode)\n >;\n\n /**\n * Виртуализация списка колонок в правом сайдбаре: в DOM держатся только\n * видимые строки списка. false — отключить полностью; { minCount } —\n * включать, когда строк в списке не меньше порога.\n * @default { minCount: 30 }\n */\n virtualization?: boolean | { minCount?: number };\n\n orderDefault?: string[];\n\n pinnedDefault?: string[];\n disablePinning?: string[];\n\n hiddenDefault?: string[];\n disableHiding?: string[];\n\n onConfirm?: (\n params: {\n pinned: string[];\n order: string[];\n hidden: string[];\n changed: { pinned?: 'pinned'; order?: 'order'; hidden?: 'hidden' };\n },\n setters: {\n setColumnsOrder: (value: React.SetStateAction<string[]>) => void;\n setPinnedCols: (value: React.SetStateAction<string[]>) => void;\n setHiddenCols: (value: React.SetStateAction<string[]>) => void;\n },\n ) => void;\n /**\n * DomMetadata для кнопок закрепления столбцов\n */\n pinDomMetadata?: DomMetadata;\n /**\n * DomMetadata для свитчеров скрытия/показа столбцов\n */\n switchDomMetadata?: DomMetadata;\n};\n```",
53160
+ "apiDocs": "# DomMetadata API\n\n## DomMetadata\n\n```typescript\ntype DomMetadata = {\n /**\n * CSS класс для стилизации и поиска элемента\n *\n * @example 'user-profile-card'\n * @example 'onboarding-step-1'\n */\n className?: string;\n /**\n * Data-атрибуты для тестирования, аналитики и онбординга\n *\n * @example { 'data-testid': 'submit-button', 'data-analytics': 'click-event' }\n */\n dataAttributes?: DataAttributes;\n /**\n * Обработчик клика для аналитики и трекинга\n *\n * Вызывается вместе с основным обработчиком элемента (не заменяет его).\n * Не вызывает stopPropagation — оригинальная логика кнопки сохраняется.\n *\n * @param e - MouseEvent (может быть undefined для элементов внутри Dropdown)\n * @param detail - контекст действия: action, columnKey, size и др.\n *\n * @example onClick: (e, detail) => analytics.track(detail?.action, detail)\n */\n onClick?: (\n e?: React.MouseEvent<HTMLElement>,\n detail?: Record<string, unknown>,\n ) => void;\n};\n```\n\n## DOM_METADATA_ACTIONS\n\n```typescript\nexport const DOM_METADATA_ACTIONS = {\n /** Включение/выключение группировки по столбцу. detail.columnKey — ключ столбца */\n TOGGLE_GROUP: 'toggle-group',\n /** Сброс всех группировок */\n RESET_GROUPS: 'reset-groups',\n /** Выбор пункта в кастомном onItemSelect группировки. detail.columnKey — ключ */\n CUSTOM_ITEM_SELECT: 'custom-item-select',\n /** Переключение размера строки. detail.size — новый размер ('small' | 'medium' | 'big') */\n CHANGE_ROW_SIZE: 'change-row-size',\n /** Клик по табу сайдбара (шестерёнка и др.). detail.tabId — id таба */\n TOGGLE_SIDEBAR_TAB: 'toggle-sidebar-tab',\n /** Закрытие сайдбара (крестик) */\n CLOSE_SIDEBAR: 'close-sidebar',\n /** Закрепление столбца. detail.columnKey — ключ столбца */\n PIN_COLUMN: 'pin-column',\n /** Открепление столбца. detail.columnKey — ключ столбца */\n UNPIN_COLUMN: 'unpin-column',\n /** Скрытие столбца. detail.columnKey — ключ столбца */\n HIDE_COLUMN: 'hide-column',\n /** Показ столбца. detail.columnKey — ключ столбца */\n SHOW_COLUMN: 'show-column',\n} as const;\n```\n\n## DomMetadataAction\n\n```typescript\ntype DomMetadataAction =\n (typeof DOM_METADATA_ACTIONS)[keyof typeof DOM_METADATA_ACTIONS];\n```\n\n## ColumnsControlConfig\n\n```typescript\ntype ColumnsControlConfig = {\n enable: boolean;\n /**\n * @default enable\n */\n hiding?: boolean;\n /**\n * @default enable\n */\n pinning?: boolean;\n /**\n * @default enable\n */\n reorderingAside?: boolean;\n /**\n * reorderingHeader - активация изменения порядка колонок посредством перемещения шапок колонок таблицы\n */\n /**\n * @default enable\n */\n reorderingHeader?: boolean;\n onReorderingHeader?: (params: {\n newOrder: string[];\n sourceKey: string;\n targetKey: string;\n }) => void;\n\n columnsLabel?: Record<\n string,\n ReactNode | ((isHidden: boolean, isPinned: boolean) => ReactNode)\n >;\n\n /**\n * Виртуализация списка колонок в правом сайдбаре: в DOM держатся только\n * видимые строки списка. false — отключить полностью; { minCount } —\n * включать, когда строк в списке не меньше порога.\n * @default { minCount: 30 }\n */\n virtualization?: boolean | { minCount?: number };\n\n orderDefault?: string[];\n\n pinnedDefault?: string[];\n disablePinning?: string[];\n\n hiddenDefault?: string[];\n disableHiding?: string[];\n /**\n * Индикатор скрытых столбцов: синяя полосатая линия в шапке на границе, за\n * которой скрыты столбцы. Двойной клик по линии раскрывает весь промежуток,\n * ресайз на этой границе работает как обычно.\n * @default hiding\n */\n hiddenColumnsIndicator?: boolean;\n /**\n * Уведомление о раскрытии промежутка двойным кликом по индикатору скрытых\n * столбцов. Само раскрытие (снятие скрытия) обёртка делает сама; колбэк нужен,\n * чтобы внешний потребитель мог подписаться на это событие и узнать, какие\n * столбцы раскрылись и между какими видимыми колонками стояла линия.\n */\n onHiddenColumnsIndicatorExpand?: (\n info: HiddenColumnsIndicatorExpandInfo,\n ) => void;\n\n onConfirm?: (\n params: {\n pinned: string[];\n order: string[];\n hidden: string[];\n changed: { pinned?: 'pinned'; order?: 'order'; hidden?: 'hidden' };\n },\n setters: {\n setColumnsOrder: (value: React.SetStateAction<string[]>) => void;\n setPinnedCols: (value: React.SetStateAction<string[]>) => void;\n setHiddenCols: (value: React.SetStateAction<string[]>) => void;\n },\n ) => void;\n /**\n * DomMetadata для кнопок закрепления столбцов\n */\n pinDomMetadata?: DomMetadata;\n /**\n * DomMetadata для свитчеров скрытия/показа столбцов\n */\n switchDomMetadata?: DomMetadata;\n};\n```",
52783
53161
  "api": [
52784
53162
  {
52785
53163
  "typeName": "DomMetadata",
@@ -52795,7 +53173,7 @@
52795
53173
  },
52796
53174
  {
52797
53175
  "typeName": "ColumnsControlConfig",
52798
- "source": "type ColumnsControlConfig = {\n enable: boolean;\n /**\n * @default enable\n */\n hiding?: boolean;\n /**\n * @default enable\n */\n pinning?: boolean;\n /**\n * @default enable\n */\n reorderingAside?: boolean;\n /**\n * reorderingHeader - активация изменения порядка колонок посредством перемещения шапок колонок таблицы\n */\n /**\n * @default enable\n */\n reorderingHeader?: boolean;\n onReorderingHeader?: (params: {\n newOrder: string[];\n sourceKey: string;\n targetKey: string;\n }) => void;\n\n columnsLabel?: Record<\n string,\n ReactNode | ((isHidden: boolean, isPinned: boolean) => ReactNode)\n >;\n\n /**\n * Виртуализация списка колонок в правом сайдбаре: в DOM держатся только\n * видимые строки списка. false — отключить полностью; { minCount } —\n * включать, когда строк в списке не меньше порога.\n * @default { minCount: 30 }\n */\n virtualization?: boolean | { minCount?: number };\n\n orderDefault?: string[];\n\n pinnedDefault?: string[];\n disablePinning?: string[];\n\n hiddenDefault?: string[];\n disableHiding?: string[];\n\n onConfirm?: (\n params: {\n pinned: string[];\n order: string[];\n hidden: string[];\n changed: { pinned?: 'pinned'; order?: 'order'; hidden?: 'hidden' };\n },\n setters: {\n setColumnsOrder: (value: React.SetStateAction<string[]>) => void;\n setPinnedCols: (value: React.SetStateAction<string[]>) => void;\n setHiddenCols: (value: React.SetStateAction<string[]>) => void;\n },\n ) => void;\n /**\n * DomMetadata для кнопок закрепления столбцов\n */\n pinDomMetadata?: DomMetadata;\n /**\n * DomMetadata для свитчеров скрытия/показа столбцов\n */\n switchDomMetadata?: DomMetadata;\n};"
53176
+ "source": "type ColumnsControlConfig = {\n enable: boolean;\n /**\n * @default enable\n */\n hiding?: boolean;\n /**\n * @default enable\n */\n pinning?: boolean;\n /**\n * @default enable\n */\n reorderingAside?: boolean;\n /**\n * reorderingHeader - активация изменения порядка колонок посредством перемещения шапок колонок таблицы\n */\n /**\n * @default enable\n */\n reorderingHeader?: boolean;\n onReorderingHeader?: (params: {\n newOrder: string[];\n sourceKey: string;\n targetKey: string;\n }) => void;\n\n columnsLabel?: Record<\n string,\n ReactNode | ((isHidden: boolean, isPinned: boolean) => ReactNode)\n >;\n\n /**\n * Виртуализация списка колонок в правом сайдбаре: в DOM держатся только\n * видимые строки списка. false — отключить полностью; { minCount } —\n * включать, когда строк в списке не меньше порога.\n * @default { minCount: 30 }\n */\n virtualization?: boolean | { minCount?: number };\n\n orderDefault?: string[];\n\n pinnedDefault?: string[];\n disablePinning?: string[];\n\n hiddenDefault?: string[];\n disableHiding?: string[];\n /**\n * Индикатор скрытых столбцов: синяя полосатая линия в шапке на границе, за\n * которой скрыты столбцы. Двойной клик по линии раскрывает весь промежуток,\n * ресайз на этой границе работает как обычно.\n * @default hiding\n */\n hiddenColumnsIndicator?: boolean;\n /**\n * Уведомление о раскрытии промежутка двойным кликом по индикатору скрытых\n * столбцов. Само раскрытие (снятие скрытия) обёртка делает сама; колбэк нужен,\n * чтобы внешний потребитель мог подписаться на это событие и узнать, какие\n * столбцы раскрылись и между какими видимыми колонками стояла линия.\n */\n onHiddenColumnsIndicatorExpand?: (\n info: HiddenColumnsIndicatorExpandInfo,\n ) => void;\n\n onConfirm?: (\n params: {\n pinned: string[];\n order: string[];\n hidden: string[];\n changed: { pinned?: 'pinned'; order?: 'order'; hidden?: 'hidden' };\n },\n setters: {\n setColumnsOrder: (value: React.SetStateAction<string[]>) => void;\n setPinnedCols: (value: React.SetStateAction<string[]>) => void;\n setHiddenCols: (value: React.SetStateAction<string[]>) => void;\n },\n ) => void;\n /**\n * DomMetadata для кнопок закрепления столбцов\n */\n pinDomMetadata?: DomMetadata;\n /**\n * DomMetadata для свитчеров скрытия/показа столбцов\n */\n switchDomMetadata?: DomMetadata;\n};"
52799
53177
  }
52800
53178
  ],
52801
53179
  "stories": [
@@ -52975,11 +53353,11 @@
52975
53353
  "legacy": false,
52976
53354
  "summary": "*tableConfig.filtering**",
52977
53355
  "docs": "# Filtering\n\n**tableConfig.filtering**\n\nФильтрация данных таблицы с поддержкой автоматического и ручного режимов.\n\n## Ключевые особенности\n\n- Три типа фильтров: `input`, `select`, `custom`\n- Автоматическая фильтрация по умолчанию, ручная через `manualFiltering: true`\n- Отображение активных фильтров в виде chip-элементов\n- Поддержка фильтрации через sidebar с настройкой порядка и глобальных фильтров\n- Кастомизация chip-стилей и лейблов\n\n## Типы фильтров\n\n### Input\n\nТекстовый фильтр с режимами: `'includes'`, `'startWith'`, `'equal'` или кастомная функция.\n\n### Select\n\nФильтр выбором из списка. Поддержка одиночного (`'single'`) и множественного (`'multiple'`) выбора.\n\n### Custom\n\nПолностью кастомный компонент фильтра через `customRender`.\n\n## Конфигурация FilteringConfig\n\n- **`state`** `[T, setState]` — стейт фильтров (обязательный)\n- **`manualFiltering`** `boolean` — ручная фильтрация (данные не фильтруются таблицей)\n- **`filtersInfo`** `Record<keyof T, { label, clearedValue }>` — метки и дефолтные значения фильтров\n- **`sidebarConfig`** `{ order?, items }` — конфигурация sidebar с фильтрами\n- **`chipStyle`** `(itemOrGroup, item) => CSSObject` — кастомные стили для chip-элементов\n- **`renderGroupLabel`** `(group) => string` — кастомный заголовок группы чипсов\n- **`renderChipLabel`** `(group, item) => string` — кастомный текст чипса\n\n## Кастомизация чипсов\n\n### chipStyle\n\nПозволяет динамически задавать стили для каждого чипа фильтра в зависимости от его типа и содержимого.\n\n### renderGroupLabel\n\nФорматтер заголовка группы чипсов. Полезен для i18n или добавления счётчика выбранных элементов.\n\n### renderChipLabel\n\nФорматтер текста внутри чипса. Полезен при серверной пагинации, когда в стейте хранится только `value`, а `label` подставляется из кэша.\n\n## Особенности\n\n- При `manualFiltering: true` таблица не фильтрует данные — ожидается внешняя логика (серверная)\n- `sidebarConfig` позволяет добавлять глобальные фильтры, не привязанные к колонкам\n- `filtersInfo` задаёт лейблы и значения по умолчанию для каждого фильтра\n\n> Подробнее о типах — [Filtering API](?path=/docs/локальные-компоненты-tablecanvas-filtering-api--docs)",
52978
- "apiDocs": "# Filtering API\n\n## FilteringConfig\n\n```typescript\ntype FilteringConfig<T> = {\n state: [T, React.Dispatch<React.SetStateAction<T>>];\n /**\n * @deprecated Использовать filtersInfo\n *\n * clearedValue - состояние фильтров после очистки. Используется для сравнения:\n * Например, был ли фильтр конкретной колонки изменен рассчитывается посредством сравнения текущего значения фильтра и значения фильтра в clearedValue.\n * Если они равны, то фильтр считается не измененным.\n */\n clearedValue?: T;\n /**\n * Информация о фильтрах для каждой колонки.\n * Используется для:\n * 1. Хранения меток (label) фильтров для отображения в UI\n * 2. Хранения значений по умолчанию (clearedValue) для каждого фильтра\n * 3. Определения, был ли фильтр изменен (сравнение текущего значения с clearedValue)\n */\n filtersInfo?: Record<\n keyof T,\n {\n label: string;\n clearedValue: T[keyof T];\n }\n >;\n /**\n * manualFiltering - пропс, активирующий ручную-кастомную (или на стороне бэка) фильтрацию.\n * @remarks\n * Для автоматической фильтрации (когда не используется manualFiltering в tableConfig):\n * - Для всех типов фильтров обязательно должен быть указан `valueInRow`\n * - Для component: 'select' дополнительно должен быть указан `filteringType`\n * - Для component: 'input' с кастомным фильтром (когда filter - функция)\n * функция фильтрации должна быть передана явно\n *\n * Если используется manualFiltering, эти параметры не обязательны,\n * так как вся логика фильтрации реализуется извне.\n */\n manualFiltering?: boolean;\n /**\n * Конфигурация для отображения фильтров в правом сайдбаре.\n *\n * Позволяет:\n * 1. Добавлять глобальные фильтры (не привязанные к конкретной колонке)\n * 2. Управлять порядком отображения фильтров\n * 3. Переопределять рендер и заголовки колоночных фильтров\n *\n * Логика работы:\n * - По умолчанию в сайдбаре отображаются все колоночные фильтры (из columnConfig)\n * - Ключом фильтра считается `key` колонки, если его нет, то пытаемся взять `keyInFilterState` (если указан), иначе это не будет работать\n * - Заголовком фильтра по умолчанию является `name` колонки или ключ фильтра (name || key)\n * - Глобальные фильтры добавляются через `items` с уникальными ключами\n *\n * Особенности:\n * 1. Порядок отображения:\n * - Сначала фильтры из `order` (в указанной последовательности)\n * - Затем остальные колоночные фильтры (в порядке columnConfig)\n * - В конце - глобальные фильтры (в алфавитном порядке ключей)\n *\n * 2. Переопределение колоночных фильтров:\n * - Чтобы изменить заголовок: укажите ключ колонки в `items` с новым `label`\n * - Чтобы заменить рендер: укажите ключ колонки с `customRenderFn`\n * - Оригинальный фильтр из колонки будет проигнорирован\n *\n * 3. Глобальные фильтры:\n * - Ключ не должен совпадать с ключами колонок\n * - Обязательно указать `label` и `customRenderFn`\n * - Отображаются после всех колоночных фильтров, если не переопределены в order\n *\n * @example\n * // Добавление глобального фильтра и изменение порядка\n * sidebarConfig: {\n * order: ['status', 'tasks', 'type'], // Сначала статус, затем глобальный поиск\n * items: {\n * tasks: { // Уникальный ключ\n * label: 'Поиск по всем полям',\n * customRenderFn: () => <TaskComponent />\n * },\n * status: { // Переопределение колоночного фильтра\n * label: 'Статус заявки', // Новый заголовок\n * customRenderFn: () => <CustomStatusFilter /> // Кастомный рендер\n * }\n * type: { // Переопределение только Label колоночного фильтра\n * label: 'Тип', // Новый заголовок\n * }\n * }\n * }\n */\n sidebarConfig?: {\n /**\n * Определяет порядок отображения фильтров.\n * - Указываются ключи фильтров (колоночных или глобальных)\n * - Не указанные в order фильтры отображаются после\n * - Если order пуст, сохраняется порядок: глобальные фильтры + columnConfig фильтры в конце\n */\n order?: string[];\n /**\n * Конфигурация фильтров для сайдбара.\n * Ключом может быть:\n * - Ключ колонки (для переопределения колоночного фильтра)\n * - Уникальный ключ (для добавления глобального фильтра)\n */\n items: Partial<\n Record<\n keyof T,\n {\n /** Заголовок фильтра (обязателен для глобальных фильтров), можно использовать для переопределения для локальных фильтров */\n label: string;\n /**\n * Функция рендера компонента фильтра.\n * Для колоночных фильтров переопределяет оригинальный рендер.\n * Для глобальных фильтров обязательна.\n */\n customRenderFn?: (\n filters: T,\n setFilters: React.Dispatch<React.SetStateAction<T>>,\n ) => React.ReactNode;\n }\n >\n >;\n };\n /**\n * Callback для кастомизации стилей чипсов (фильтров) в списке\n *\n * @param {ItemOrGroup} itemOrGroup - Текущий элемент или группа фильтров\n * @param {Item | undefined} item - Конкретный элемент фильтра (если есть)\n * @returns {CSSObject} Объект стилей, который будет применен к чипсу\n *\n * @description\n * Позволяет динамически задавать стили для каждого чипса в зависимости от его типа и содержимого.\n * Вызывается для каждого отображаемого чипса (как для отдельных элементов, так и для элементов внутри групп).\n *\n * @example\n * // Пример 1: Стилизация чипсов по типу\n * chipStyle: (itemOrGroup, item) => {\n * if (isGroup(itemOrGroup)) {\n * return { backgroundColor: '#f0f0f0' };\n * }\n * return { backgroundColor: '#e0e0e0' };\n * }\n *\n * @example\n * // Пример 2: Стилизация по значению фильтра\n * chipStyle: (itemOrGroup, item) => {\n * if (item?.label === 'Высокий приоритет') {\n * return {\n * backgroundColor: '#ffebee',\n * color: '#d32f2f'\n * };\n * }\n * return {};\n * }\n *\n * @example\n * // Пример 3: Разные стили для элементов в группе и одиночных\n * chipStyle: (itemOrGroup, item) => {\n * if (item) {\n * // Стиль для элемента внутри группы\n * return { maxWidth: 180 };\n * }\n * // Стиль для одиночного чипа\n * return { maxWidth: 150 };\n * }\n */\n chipStyle?: (itemOrGroup: ItemOrGroup, item: Item | undefined) => CSSObject;\n /**\n * Пользовательский форматтер заголовка группы чипсов.\n *\n * Используется в блоке активных фильтров для подмены текста заголовка\n * группы (например, “Статус”, “Тип”, “Автор”). Полезно, когда нужно\n * динамически менять подпись (добавить счётчик, i18n и т.п.).\n *\n * @param {ItemOrGroup} itemOrGroup Объект группы (тип Group). Вызов происходит только для групп,\n * поэтому безопасно кастовать к Group.\n * @returns {string} Текст заголовка группы чипсов.\n *\n * @default Возвращается `group.groupLabel`.\n *\n * @remarks\n * - Функция должна быть чистой и быстрой (без сетевых запросов и побочных эффектов).\n * - Возвращайте ТОЛЬКО строку — чипы отображают текстовое значение.\n * - Для длинных строк применяется усечение (overflow с многоточием) на уровне компонента.\n *\n * @example\n * // Добавить двоеточие и количество выбранных элементов\n * renderGroupLabel: (group) => `${group.groupLabel}: ${group.items.length}`\n *\n * @example\n * // Локализация заголовка группы\n * const i18n = { status: 'Статус', type: 'Тип' };\n * renderGroupLabel: (group) => i18n[group.groupId] ?? group.groupLabel\n */\n renderGroupLabel?: (group: Group) => string;\n\n /**\n * Пользовательский форматтер текста чипса (элемента внутри группы или одиночного фильтра).\n *\n * Позволяет управлять тем, что именно отображается внутри каждого чипса. Особенно полезен\n * при серверной пагинации/ленивой загрузке, когда в состоянии фильтра хранится только value,\n * а label необходимо подставить из локального кэша.\n *\n * @param {Group | null } group Группа, внутри которой рендерится чип (или null).\n * @param {Item} item Сам элемент чипса. В группах передаётся конкретный `Item`,\n * для одиночного чипа может быть `undefined`.\n * @returns {string} Текст, который будет показан в чипсе.\n *\n * @default Используется `item?.label.toString()` (или строковое представление value).\n *\n * @remarks\n * - Функция должна быть чистой и быстрой;\n * - Возвращайте ТОЛЬКО строку.\n *\n * @example\n * // 1) Отображение label из кэша при серверной пагинации\n * const labelsCacheRef = useRef(new Map<string, string>());\n * renderChipLabel: (group, item) => {\n * if (item?.id != null) {\n * const key = String(item.id);\n * const fromCache = labelsCacheRef.current.get(key);\n * if (fromCache) return fromCache; // красивый label, если уже загрузили\n * return String(item.label ?? key); // фоллбэк: временно показываем value/label из item\n * }\n * return ''; // безопасный фоллбэк для одиночных случаев\n * }\n *\n * @example\n * // 2) Нормализация отображения числовых значений\n * renderChipLabel: (_group, item) => {\n * const v = Number(item?.label);\n * return Number.isFinite(v) ? v.toLocaleString('ru-RU') : String(item?.label ?? '');\n * }\n *\n * @example\n * // 3) Префикс по типу группы\n * renderChipLabel: (group, item) => {\n * const prefix = group.groupId === 'status' ? '' : '#';\n * return `${prefix}${item?.label ?? item?.id ?? ''}`;\n * }\n */\n renderChipLabel?: (group: Group | null, item: Item) => string;\n};\n\nexport type DefaultSidebarTabIds = 'columns' | 'tableSettings' | 'filtering';\n\n/**\n * Конфигурация sidebar\n */\nexport type SidebarConfig = {\n /**\n * Включен ли sidebar. Отвечает только за UI. Не влияет на перерасчёт фичей.\n * @default true\n */\n enabled?: boolean;\n /**\n * Открыт ли sidebar при первом рендере (uncontrolled-режим).\n * Игнорируется, если передан openState.\n * @default false\n */\n defaultOpen?: boolean;\n /**\n * Внешний контроль открытия/закрытия sidebar.\n * Если передан — источник истины, defaultOpen игнорируется.\n */\n openState?: [boolean, React.Dispatch<React.SetStateAction<boolean>>];\n /**\n * id вкладки, выбранной по умолчанию (актуально при открытом сайдбаре).\n * Если id не найден или у вкладки showInSidebar=false — используется первая доступная.\n */\n defaultActiveTabId?: string;\n /**\n * Внешний контроль активной вкладки (controlled-режим).\n * Если передан — источник истины, defaultActiveTabId игнорируется.\n */\n activeTabState?: [\n string | null,\n React.Dispatch<React.SetStateAction<string | null>>,\n ];\n /**\n * Колбэк смены активной вкладки. Вызывается и в uncontrolled-режиме.\n * При закрытии сайдбара приходит null.\n */\n onActiveTabChange?: (tabId: string | null, tab?: SidebarTab) => void;\n /**\n * Кастомные табы\n */\n customTabs?: Array<\n Omit<SidebarTab, 'id'> & {\n id: Exclude<string, DefaultSidebarTabIds>;\n }\n >;\n /**\n * Порядок отображения кастомных вкладок\n */\n customTabsOrder?: Array<Exclude<string, DefaultSidebarTabIds>>;\n defaultTabs?: Array<\n | {\n id: 'filtering' | 'columns';\n /** название таба в рамках горизонтального табов внутри таба настройки */\n label?: string;\n /** название таба в рамках вертикальных табов сайдбара (если данный таб окажется единственным табом в настройках) */\n title?: string;\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n domMetadata?: DomMetadata;\n /**\n * Кастомный элемент справа от title в шапке сайдбара\n */\n titleRightSlot?: React.ReactNode;\n /** @default true */\n showInSidebar?: boolean;\n /** тултип иконки шестеренки (для табов с id = filtering и columns - недоступен. Настраивается через таб с id='tableSettings') */\n iconTooltipText?: undefined;\n }\n | {\n id: 'tableSettings';\n /** название таба в рамках горизонтального табов внутри таба настройки */\n label?: string;\n /** название таба в рамках вертикальных табов сайдбара */\n title?: string;\n\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n domMetadata?: DomMetadata;\n /**\n * Кастомный слот для вкладки tableSettings (рендерится после общих настроек)\n * Только дл id: 'tableSettings'\n */\n customGeneralSettingsSlot?: React.ReactNode;\n /**\n * Кастомный элемент справа от title в шапке сайдбара\n */\n titleRightSlot?: React.ReactNode;\n /** @default true */\n showInSidebar?: boolean;\n /** тултип иконки шестеренки @default 'Настройки' */\n iconTooltipText?: string;\n }\n >;\n};\n\nexport function activeViewIs<T extends 'cards' | 'rows'>(\n checkType: T,\n viewState: 'cards' | 'rows',\n view: View,\n): view is ViewMods[T] {\n return checkType === viewState;\n}\n\n/** Размер controlBlock: 'm' и 's' — одинаковые стили, 'xs' — уменьшенный */\nexport type ControlBlockSize = 'm' | 's' | 'xs';\n\nexport type ControlBlockConfig = {\n /**\n * show - наличие controlBlock-а\n * @default true\n */\n show?: boolean;\n /**\n * Размер controlBlock и его элементов (кнопки, иконки, поиск, отступы).\n * 'm' и 's' — стандартные стили, 'xs' — компактный режим.\n * Не влияет на customFeatures и кастомные слоты — они контролируются разработчиком.\n * @default 'm'\n */\n size?: ControlBlockSize;\n /**\n * @deprecated Используйте кастомные кнопки через rightSideInner или customFeatures.\n * leftSideInner - пропс для добавления кнопок в левую часть контролблока.\n * Продолжает работать для обратной совместимости.\n */\n leftSideInner?: ControlBlockButtonProps[];\n /**\n * rightSideInner - пропс для добавления кнопок в правую часть контролблока\n */\n rightSideInner?: ControlBlockButtonProps[];\n /**\n * customFeatures - пропс для добавления кастомных фичей (кнопки-иконки)\n */\n customFeatures?: FeatureItem[];\n /**\n * pinningMenu - нативная фича закрепления столбцов (SplitIconButton с\n * дропдауном) в правой зоне иконок. Появляется, когда активировано\n * закрепление колонок (columnsControl.pinning). Продукт может донастроить\n * и дополнить пункты меню (см. PinningMenuConfig).\n */\n pinningMenu?: PinningMenuConfig;\n /**\n * Пропсы для компонента dropdown в котором будут скрыты левые фичи при адаптивной компрессии\n */\n leftSideDropdownProps?: TableDropdownConfigProps;\n /**\n * Пропсы для компонента dropdown в котором будут скрыты правые фичи при адаптивной компрессии\n */\n rightSideDropdownProps?: TableDropdownConfigProps;\n /**\n * Активна ли фича компрессии (сжатие ToolsMenu при адаптиве)\n * @default true\n */\n enableAdaptiveCompress?: boolean;\n /**\n * Панель массовых действий\n */\n massActionPanel?: {\n /**\n * Кнопки панели. Размеры кнопок/дропдаунов панель подбирает сама (по `size` панели и компактности) —\n * передавать `size` кнопкам не нужно. Если `size` на кнопке всё же задан — он используется как есть.\n */\n buttons: MassActionButtonProps[];\n /**\n * Пропсы для Dropdown, в который сжались кнопки\n */\n collapsedDropdownProps?: TableDropdownConfigProps;\n /**\n * Отступ панели снизу от контейнера (px)\n * @default 24\n */\n bottom?: number;\n /**\n * Управление отображением панели массовых действий.\n * - `undefined` (по умолчанию) — стандартное поведение (показывается при selecting + выбранных строках)\n * - `false` — панель не рендерится, разработчик управляет действиями самостоятельно\n * - `true` — панель показывается всегда, даже без активного selecting и выбранных строк\n */\n show?: boolean;\n /**\n * Размерная сетка панели внутри таблицы: `m`/`s` — обычный размер, `xs` — уменьшенный (кнопки `xxs`, «ещё» `xs`, счётчик Body XS).\n * Viewport-логика (1280) в таблице не используется.\n * @default 's'\n */\n size?: MassActionsSize;\n };\n};\n\n/** Пропсы кнопки редактирования. onClick исключён — используйте onSave/onCancel/onEnableEditing. */\nexport type EditingButtonProps = Omit<\n Partial<ControlBlockButtonProps>,\n | 'onClick'\n | 'size'\n | 'dropdown'\n | 'isTargetAction'\n | 'skipRightDivider'\n | 'tooltipText'\n>;\n\nexport type EditingConfig<\n RowType extends ObjectForExtending,\n RowIdType,\n SummaryRowType,\n> = {\n /**\n * Функция обработки изменений в редактируемой строке\n */\n onRowsChange: Maybe<\n (rows: RowType[], data: RowsChangeData<RowType, SummaryRowType>) => void\n >;\n /**\n * свойство, необходимое для корректного изменения дочерних строк.\n * Данное свойство обязательно, если ваши дочерние строки установлены не под ключом \"subRows\" внутри строки.\n *\n * Как дочерние строки можно указывать свойство, которые вложено в другое свойство.\n * В таком случае \".\" будет знаком для обозначения сл. уровня вложенности.\n *\n * @example \"child\" или \"uvh367.children\"\n */\n subRowsKey?: string;\n /**\n * Глубокое копирование строк перед применением правки в режиме редактирования.\n *\n * Включите, если строки, передаваемые в таблицу, иммутабельны/заморожены\n * (напр. стейт под управлением Redux Toolkit или Immer — они вызывают\n * Object.freeze в dev). При редактировании дочерней строки таблица записывает\n * изменение ВНУТРЬ объекта родителя; на замороженном объекте это падает с\n * `TypeError: Cannot assign to read only property`.\n *\n * Когда флаг включён, таблица сама делает structuredClone редактируемой строки\n * перед записью — ваш иммутабельный стейт не мутируется, и редактирование\n * дочерних строк работает без действий с вашей стороны.\n *\n * ⚠️ Данные строки должны быть сериализуемыми. Где доступен structuredClone —\n * Date/Map/Set и вложенные структуры копируются корректно; на старых средах\n * без structuredClone используется JSON-фоллбэк (теряет Date/Map/Set, undefined\n * и функции). Не включайте без необходимости — глубокое копирование добавляет\n * накладные расходы.\n *\n * @default false\n */\n deepCloneRows?: boolean;\n /**\n * Функция определения уникального id строки\n * @param row\n * @returns\n */\n rowKeyGetter: (row: RowType) => RowIdType;\n /**\n * Функция определения возможности редактирования строки\n * @param row\n * @returns\n */\n rowEditable?: (row: RowType) => boolean;\n /**\n * defaultEnabled - пропс, отвечающий за то, будет ли активен режим редактирования или нет. По умолчанию - не активно.\n * @default false\n */\n defaultEnabled?: boolean;\n /**\n * enabled - необходим для управления режимом редактирования снаружи компонента Таблицы.\n * По умолчанию, управление происходит в компоненте.\n * Приоритетнее, чем defaultEnabled.\n *\n * @type boolean - если НЕ нужно переключение в самой таблице\n * @type [boolean, React.Dispatch<React.SetStateAction<boolean>>] - если нужно переключение в самой таблице\n *\n */\n enabled?: boolean | [boolean, React.Dispatch<React.SetStateAction<boolean>>];\n /**\n * Cостояние скрытия/раскрытия кнопки включения/выключения фичи\n * @default true\n */\n showButtons?: boolean;\n /**\n * Функция, вызывающаяся при включении фичи.\n * @param enableEditorMode - функция включающая режим редактирования\n */\n onEnableEditing?: (enableEditorMode: () => void) => void;\n /**\n * Функция, вызывающаяся при сохранении отредактированного.\n * @param disableEditorMode - функция выключающая режим редактирования\n */\n onSave?: (disableEditorMode: () => void) => void;\n /**\n * Функция, вызывающаяся при отмене отредактированного.\n * @param disableEditorMode - функция выключающая режим редактирования\n */\n onCancel?: (disableEditorMode: () => void) => void;\n /** Пропсы кнопок в controlBlock. */\n buttons?: {\n save?: EditingButtonProps;\n cancel?: EditingButtonProps;\n edit?: EditingButtonProps;\n };\n /**\n * Кастомный слот, отображаемый левее кнопок «Отменить» / «Сохранить».\n * Виден только когда режим редактирования активен (editMode = true).\n * Зона ответственности разработчика — размерная сетка controlBlock не влияет на этот слот.\n */\n editModeLeftSlot?: React.ReactNode;\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n domMetadata?: {\n enableButton?: DomMetadata;\n saveButton?: DomMetadata;\n cancelButton?: DomMetadata;\n };\n};\n\nexport type SummaryRowsConfig = {\n showDefault: boolean;\n showInControl: boolean;\n} & {\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n domMetadata?: DomMetadata;\n};\n\n/**\n * Конфиг тултипа при hover по canvas-элементам.\n * Для активации фичи необходимо заполнить данный конфиг,\n * а также добавить нужные изменения в Canvas-элементах или в конфиге колонки.\n */\nexport type TableConfigTooltip = {\n /**\n * Включить/выключить колоночные и кастомные тултипы (cellTooltip, headerCellTooltip).\n * Внутренние тултипы (drag-иконка в шапке и другие по nodeId) работают всегда.\n * @default false\n */\n enabled?: boolean;\n /** Глобальная задержка перед показом тултипа (мс). Per-node переопределяет. @default 500 */\n mouseEnterDelay?: number;\n /** Глобальная задержка перед скрытием тултипа (мс). Per-node переопределяет. @default 0 */\n mouseLeaveDelay?: number;\n};\n\nexport type InfinityScrollConfig<RowType extends ObjectForExtending> = {\n /** Триггер достижения скроллом зоны подгрузки данных. */\n onTrigger: (rows: RowType[]) => Promise<void> | void;\n /** Состояние загрузки (скелетоны) новых строк. */\n isLoading: boolean;\n /**\n * Флаг, когда все данные загружены — false.\n * @default true\n */\n hasMore?: boolean;\n /**\n * Для mode='region': за сколько строк до конца триггерить загрузку.\n * @default 5\n */\n rowThreshold?: number;\n};\n\nexport type { TableCanvasEmptyStateConfig, TableCanvasErrorStateConfig };\n\n/**\n * Настройка выделения ячеек/колонок/строк в TableCanvas — единый объект.\n * Это отдельная ось взаимодействия — не зависит от `highlightActiveType`.\n */\nexport type CellsSelectionConfig = {\n /**\n * Режим фактического выделения ячеек (нативный glide selection). По нему\n * работают copy/paste, рамка, fill-handle и затемнение шапки/нумерации.\n * @default \"range-cell\"\n */\n mode?: CellsSelectionMode;\n /**\n * Выделение колонок по клику на шапку. Ctrl/Cmd — добавить/убрать колонку,\n * Shift — диапазон колонок. Клик по иконкам сортировки/фильтрации в шапке\n * выделение НЕ вызывает. Поддерживает copy/paste по выделенным колонкам.\n * @default true\n */\n enableColumnSelection?: boolean;\n /**\n * Выделение строк по клику/драгу на колонке нумерации (`rowMarkers`).\n * Ctrl/Cmd — несмежный выбор отдельных строк, драг — смежный диапазон.\n * Поддерживает copy/paste по выделенным строкам. Требует включённой колонки\n * нумерации (`rowMarkers`). При `false` клик по нумерации ничего не выделяет.\n * @default true\n */\n enableRowSelection?: boolean;\n /**\n * Выделение всей таблицы кликом по «нулевой» ячейке — шапке колонки нумерации\n * (левый верхний угол). Выделяет все строки данных по всем колонкам одним\n * диапазоном; поддерживает copy/paste. Требует включённой колонки нумерации\n * (`rowMarkers`) и активного `mode` (≠ `disabled`).\n * @default true\n */\n enableSelectAll?: boolean;\n /**\n * Внешний (controlled) контроль НАТИВНОГО выделения (ячейки/диапазон/смежные\n * строки и колонки). `state` — кортеж `[value, setter]` как у `selecting.state`.\n * Сброс: `setter({ current: undefined, rows: empty, columns: empty })`.\n * Несмежный Ctrl-выбор колонок/строк (own-state) сюда не входит — он внутренний.\n */\n state?: [GridSelection, React.Dispatch<React.SetStateAction<GridSelection>>];\n};\n\n/** Один объединённый блок: какие строки и колонки слить. */\nexport type MergedCellsRegion = {\n rowKeys: Array<string | number>;\n colKeys: string[];\n /** Выравнивание контента этого блока. Важнее колоночного и общего. */\n mergedCellsAlign?: MergedCellsAlign;\n};\n\nexport type TableConfig<\n RowType extends ObjectForExtending,\n SummaryRowType,\n RowIdType extends string | number,\n FilterStateType extends ObjectForExtending,\n // SubRowType\n> = {\n /**\n * Группировка колонок (многоуровневая шапка через `columnConfig.children`):\n * объединение пустых ячеек шапки (`squashEmptyCells`, по умолчанию включено) и\n * дефолт выравнивания в объединённых ячейках (`squashedHeaderAlign`).\n */\n columnsGrouping?: ColumnsGroupingConfig;\n /**\n * Подсветка активной сущности в canvas-таблице.\n * @deprecated Значения `'cell'`/`'range-cell'` устарели — используйте\n * `cellsSelection.mode`. Актуальны `'row'` (подсветка строки) и `'disabled'`.\n */\n highlightActiveType?: HighlightActiveType;\n /**\n * Единый конфиг выделения ячеек: режим (`mode`), оси\n * (`enableColumnSelection`/`enableRowSelection`/`enableSelectAll`) и controlled\n * (`state`). См. {@link CellsSelectionConfig}.\n */\n cellsSelection?: CellsSelectionConfig;\n /**\n * Подсвеченная строка (`highlightActiveType='row'`).\n * `state` (опционально) — controlled-кортеж `[value, setter]`: задан — значением\n * владеешь снаружи (сброс `setter(undefined)`); не задан — таблица крутит\n * подсветку внутренним стейтом, а `onChange` всё равно срабатывает (подписка\n * без владения значением).\n */\n highlightActiveRow?: {\n state?: [\n number | undefined,\n React.Dispatch<React.SetStateAction<number | undefined>>,\n ];\n /**\n * Колбэк смены подсвеченной строки: отдаёт её флэт-индекс и сам объект\n * строки (`rows[index]`). Позволяет открывать данные подсвеченной строки\n * (например, в SplitView) без `onCellClicked`.\n */\n onChange?: (params: {\n index: number | undefined;\n row: RowType | undefined;\n }) => void;\n };\n /**\n * Эффекты при наведении (hover)\n * `row` — подсветка строки под курсором.\n * Независимая визуальная ось: селектинг (`cellsSelection`) и `highlightActiveType='row'`\n * рисуются ПОВЕРХ hover-подсветки и визуально перекрывают её (hover\n * «остаётся под ними» и снова виден после сброса выделения).\n *\n * `{ row: true }` — включить с цветами из темы;\n * `{ row: { color: '#F7F9FB' } }` — переопределить цвет data-ячеек.\n * @default undefined (выключено)\n */\n hoverEffects?: HoverEffectsConfig;\n /**\n * Включает компенсацию тонких canvas-линий при browser zoom ниже 100%, когда devicePixelRatio меньше 1.\n * Влияет только на grid/header/sticky hairline borders.\n * @default false\n */\n enableLowDprHairline?: boolean;\n /**\n * rowSize - размеры строк таблицы\n */\n rowSize?: Prettify<RowSize>;\n /**\n * rowHeight - размер высоты строк таблицы\n */\n rowHeight?: Maybe<number | RowHeightFunc<RowType>>;\n /**\n * sorting - активация сортировки. Условие активации - это наличие данного свойства. Нужно также сконфигурировать колонки.\n *\n * Пример:\n *\n * tableConfig={sorting: {sortingState}}\n *\n * columnConfig=[{sortingType: 'numberSort'}]\n */\n sorting?: {\n state: [\n readonly SortColumn[],\n React.Dispatch<React.SetStateAction<readonly SortColumn[]>>,\n ];\n /**\n * manualSorting - пропс, активирующий ручную-кастомную (или на стороне бэкенда) сортировку\n */\n manualSorting?: boolean;\n };\n /** @deprecated Свойство view не используется и будет удалено в следующей мажорной версии. */\n view?: View;\n /**\n * filtering - активация фильтрации. Условие активации - это наличие данного свойства. Нужно также сконфигурировать колонки.\n *\n * Пример:\n *\n * tableConfig={filtering: {stateAndSetter, ...}}\n *\n * columnConfig=[{filtering: {...}}]\n */\n filtering?: FilteringConfig<FilterStateType>;\n /**\n * Сворачивание / разворачивание таблицы\n */\n collapsing?: TableCollapseConfig;\n /**\n * selecting - активация выбора строк. Условие активации - это наличие данного свойства.\n * Есть поддержка выбора строк с многоуровневой вложенностью.\n *\n * Пример:\n *\n *```jsx\n * import { Table } from '@daisforge/ui';\n *\n * <Table\n * tableConfig={{selecting: {stateAndSetter, rowKeyGetter}}}\n * {...rest}\n * />\n * ```\n */\n selecting?: {\n state: [\n ReadonlySet<RowIdType>,\n React.Dispatch<React.SetStateAction<ReadonlySet<RowIdType>>>,\n ];\n rowKeyGetter: (row: RowType) => RowIdType;\n } & Prettify<SelectingRowConfig<RowType, RowIdType>> & {\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n controlBlock?: {\n domMetadata?: DomMetadata;\n };\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам RightSidebar\n */\n sidebar?: {\n domMetadata?: DomMetadata;\n };\n };\n /**\n * editing - активация редактирования. Условие активации - это наличие данного свойства. Нужно также сконфигурировать колонки.\n *\n * Пример:\n *\n * tableConfig={editing: {onRowsChange, rowKeyGetter}}\n *\n * columnConfig=[{editingCell: {...}}]\n */\n editing?: EditingConfig<RowType, RowIdType, SummaryRowType>;\n\n /**\n * cellTransfer — конфигурация копирования, вставки и fill handle.\n * По умолчанию копирование (Ctrl+C) работает в режиме редактирования.\n * Данные копируются в формате TSV (tab-separated values), совместимом с Excel.\n *\n * Пример:\n *\n * tableConfig={{ cellTransfer: { enabled: true, onBeforeCopy: (data) => data } }}\n */\n cellTransfer?: CellTransferConfig;\n\n /**\n * Объединение ячеек тела таблицы.\n *\n * mergeByCellValues — колонки, в которых подряд идущие одинаковые значения\n * сливаются в один блок (по вертикали). Границы блоков таблица считает сама из\n * данных; сортировка и фильтр их пересобирают. Данные не меняются — значение и\n * так повторяется в строках, объединение лишь показывает его одной ячейкой.\n *\n * mergedCellsRegions — список блоков, заданных снаружи (как выделение): каждый\n * блок описан ключами строк (rowKeys) и колонок (colKeys). Нужен rowKeyGetter.\n * Если после сортировки или скрытия колонок строки/колонки блока перестали идти\n * подряд — блок не рисуется. Важнее mergeByCellValues.\n *\n * Примеры: mergeCells={{ mergeByCellValues: ['dept', 'role'] }},\n * mergeCells={{ mergedCellsRegions, rowKeyGetter: (r) => r.id }}.\n */\n mergeCells?: {\n mergeByCellValues?: Array<\n string | { colKey: string; value: (row: RowType) => unknown }\n >;\n /** Список блоков, заданных снаружи (по ключам строк и колонок). */\n mergedCellsRegions?: MergedCellsRegion[];\n /**\n * Нужен для mergedCellsRegions: находит строку по её ключу. Должна быть\n * стабильной функцией; менять её на лету не нужно — в пересборку таблицы она\n * не входит.\n */\n rowKeyGetter?: (row: RowType) => string | number;\n /**\n * Выравнивание по умолчанию для всех блоков. Колоночный mergedCellsAlign и\n * выравнивание конкретного региона важнее.\n */\n mergedCellsAlign?: MergedCellsAlign;\n };\n\n /**\n * Модуль нотификаций: стандартизированный канал событий для внешних\n * потребителей. Таблица UI не рисует — вызывает `onNotification`, потребитель\n * показывает тост/модалку на своей стороне. Сейчас эмитятся ошибки copy/paste\n * (в т.ч. multi-range 2D-разброс, readonly/overflow-abort, пропуск валидацией).\n */\n notifications?: TableNotificationsConfig;\n\n /**\n * subRows - активация иерархии, отображения вложенных строк. Условие активации - наличие данного свойства. Нужно также сконфигурировать колонки.\n *\n * Пример:\n *\n * tableConfig={subRows: {getSubRows, rowKeyGetter}}\n *\n * columnConfig=[{subRow: {...}}]\n */\n subRows?: SubRows<RowType, RowIdType>;\n /**\n * Столбец с нумерацией строк.\n * Активируется наличием этого свойства. Поддерживает `subRows` любой глубины.\n *\n * @see {@link RowMarkersTableConfig} — полное описание конфигурации и примеры.\n */\n rowMarkers?: RowMarkersTableConfig<RowType>;\n rowsGrouping?: RowsGrouping<RowType, SummaryRowType>;\n\n /**\n * resizableColumn - активация изменения ширины колонки с помощью курсора. Условие активации - resizableColumn: true. Нужно также сконфигурировать колонки.\n *\n * Пример:\n *\n * tableConfig={resizableColumn: true}\n *\n * columnConfig=[{resizable: true}]\n */\n resizableColumn?: boolean;\n /**\n * style - inline-стили. Для стилей самой таблицы (без вложенности).\n *\n * Исключены свойства 'width' | 'height' | 'minWidth' | 'minHeight' | 'maxWidth' | 'maxHeight'. Их следует стилизовать через свойства containerStyle.\n */\n style?: Omit<\n CSSProperties,\n 'width' | 'height' | 'minWidth' | 'minHeight' | 'maxWidth' | 'maxHeight'\n >;\n /**\n * css - для стилей простых и сложных(например, для стилизации cell, headerCell, ...).\n *\n * Пример:\n *\n * ```css\n * & > .rdg-header-row > .rdgCell {\n * background-color: red;\n * }\n * ```\n *\n */\n css?: string | CSSObject;\n\n summaryRows?: SummaryRowsConfig;\n /**\n * controlBlock - пропс для активации, кастомизации контролблока.\n */\n controlBlock?: ControlBlockConfig;\n /**\n * containerStyle - инлайновые стили контейнера таблицы и контролблока. высоту и ширину для таблицы рекомендуется задавать в этом пропсе.\n * Пример:\n *\n * ```tsx\n tableConfig={{ containerStyle: { height: '70vh' } }}\n * ```\n */\n containerStyle?: CSSProperties | undefined;\n /**\n * containerCss - стили для контейнера таблицы и контролблока.\n * Через этот пропс можно дополнительно кастомизировать контейнер и все его дочерние элементы.\n */\n containerCss?: string | CSSObject | undefined;\n /**\n * containerId - html-атрибут id контейнера таблицы.\n */\n containerId?: string | undefined;\n\n /**\n * unstickyHeader - откреплённая шапка. Header уезжает вместе со скроллом контента.\n * @default false\n */\n unstickyHeader?: boolean;\n\n /** Тултип при hover по canvas-элементам.\n * Для активации фичи необходимо заполнить данный конфиг,\n * а также добавить нужные изменения в Canvas-элементах или в конфиге колонки.\n */\n tooltip?: TableConfigTooltip;\n\n /**\n * infinityScroll - бесконечная подгрузка данных при скролле.\n *\n * Условие активации - наличие самого пропса infinityScroll.\n *\n * При активации infinityScroll отключается дефолтная сортировка и фильтрация.\n * (Предполагается, что если есть infinityScroll,\n * то в таблице представлен не весь объем данных,\n * по этой причине дефолтная сортировка и фильтрация не подходят и будут отображать некорректные данные)\n *\n */\n infinityScroll?: InfinityScrollConfig<RowType>;\n /**\n * @isLoading - состояние загрузки данных для таблицы.\n */\n isLoading?: boolean | { boolean: boolean; skeletonRowsCount: number };\n /**\n * loadingOverlay - конфигурация для отображения оверлея загрузки.\n * Показывает индикатор загрузки поверх таблицы с возможностью кастомизации.\n */\n loadingOverlay?: {\n /**\n * Активен ли оверлей загрузки\n * @default true\n */\n active?: boolean;\n /**\n * Кастомный компонент спиннера\n * @default <Spinner view=\"secondary\" size=\"36\" /> (внутренний компонент)\n */\n spinner?: ReactNode;\n /**\n * Основной заголовок оверлея\n * @default \"Загрузка таблицы\"\n */\n title?: string;\n /**\n * Подзаголовок, который появится после задержки, пустая строка - значит он не появится\n * @default \"\"\n */\n subtitle?: string;\n /**\n * Задержка перед показом подзаголовка (мс)\n * @default 10000 (10 секунд)\n */\n showSubtitleDelay?: number;\n };\n /**\n * Empty state внутри content-области canvas-таблицы.\n * Не заменяет control block, header или pagination.\n */\n emptyState?: TableCanvasEmptyStateConfig;\n /**\n * Error state внутри content-области canvas-таблицы.\n * Не заменяет control block, header или pagination.\n */\n errorState?: TableCanvasErrorStateConfig;\n // FIXME:\n // noRowsFallback?: boolean | { custom: ReactNode };\n columnsControl?: ColumnsControlConfig;\n // FIXME:\n // rowDetailPanel?: RowDetailConfig<RowType>;\n // FIXME: Временно комментирую использование, пока не адаптируем TableCanvas\n // rowInstruments?: {\n // getRowDropdownConfig: RowInstrumentsType<RowType>;\n // /**\n // * @default false\n // */\n // defaultOpened?: boolean;\n // /**\n // * @default true\n // */\n // showInControl?: boolean;\n // /**\n // * Внешний стейт видимости\n // */\n // openedState?: [boolean, React.Dispatch<React.SetStateAction<boolean>>];\n // };\n fullScreenEnabled?: FullScreen;\n /**\n * Переносит портал editor overlay внутрь контейнера таблицы вместо document.body.\n * Решает проблему focus trap и сдвига координат при рендере таблицы в модалке с CSS transform.\n * @default undefined (overlay рендерится в document.body — стандартное поведение)\n */\n editorOverlayPortal?: 'inside';\n keyText?: boolean | KeyTextConfig;\n /**\n * pagination - пропс для пагинации.\n *\n * Условие активации - наличие самого пропса pagination.\n *\n * При активации pagination отключается дефолтные поиск, сортировка и фильтрация.\n * (поиск работает на уровне с фильтрацией и сортировкой, сначала поиск, затем фильтрация, затем сортировка)\n *\n */\n pagination?: PaginationProps;\n /**\n * searching - пропс для поиска по таблицу.\n *\n * Условие активации - наличие searching.enabled: true\n *\n */\n /**\n * Конфигурация табов в сайдбаре\n */\n sidebarConfig?: SidebarConfig;\n searching?: SearchingProps;\n /**\n * onHeaderContextMenu - callback открытия контекстного меню.\n */\n onHeaderContextMenu?: TableGlideInstanceProps<\n RowType,\n SummaryRowType\n >['onHeaderContextMenu'];\n onHeaderContextMenuDropdown?: TableGlideInstanceProps<\n RowType,\n SummaryRowType\n >['onHeaderContextMenuDropdown'];\n onCellContextMenuDropdown?: TableGlideInstanceProps<\n RowType,\n SummaryRowType\n >['onCellContextMenuDropdown'];\n onCellContextMenu?: TableGlideInstanceProps<\n RowType,\n SummaryRowType\n >['onCellContextMenu'];\n /**\n * Обработчик клика по ячейке.\n *\n * Получает `cell` readonly [colIndex, rowIndex] от glide, и `info` обогащённый объект\n * с row, column, ctxs, refTable (аналогично onCellContextMenu).\n */\n onCellClicked?: (\n cell: readonly [number, number],\n info: TableInfoWithRow<RowType, SummaryRowType>,\n ) => void;\n} & GlideInstanceOmitted<RowType, SummaryRowType>;\n\ntype GlideInstanceOmitted<\n RowType extends ObjectForExtending,\n SummaryRowType,\n> = Pick<\n Omit<\n TableGlideInstanceProps<RowType, SummaryRowType>,\n | keyof TableGlideCustomProps<RowType, SummaryRowType>\n | 'CellReadOnlyEditor' /* CellReadOnlyEditor - свойство только для GlideInstance */\n >,\n | 'className'\n | 'columnSelect'\n | 'minColumnWidth'\n | 'maxColumnWidth'\n | 'maxColumnAutoWidth'\n | 'onVisibleRegionChanged'\n | 'onCellClicked'\n // | 'CellReadOnlyEditor'\n // | 'onGroupHeaderClicked'\n | 'onHeaderClicked'\n | 'onItemHovered'\n | 'trapFocus'\n | 'onColumnResize'\n>;\nexport type CellReadOnlyEditorProps<\n RowType extends ObjectForExtending,\n SummaryRowType,\n> = CellReadOnlyEditorGlideInstanceStaticProps &\n EditingCellInfo<RowType, SummaryRowType>;\n\n// & Pick<\n// DataGridPropsDefault<RowType, SummaryRowType, RowIdType>,\n// | 'summaryRowHeight'\n// | 'onFill'\n// | 'onCopy'\n// | 'onPaste'\n// | 'onCellClick'\n// | 'onCellDoubleClick'\n// | 'onCellContextMenu'\n// | 'onCellKeyDown'\n// | 'onSelectedCellChange'\n// | 'onScroll'\n// | 'onColumnResize'\n// | 'onColumnsReorder'\n// | 'enableVirtualization'\n// | 'rowClass'\n// | 'data-testid'\n// | 'headerRowHeight'\n// >;\n\n/**\n * Конфигурация фичи rowMarkers (столбец с нумерацией строк).\n *\n * Столбец frozen, вставляется первым, исключён из reorder/pin/hide/sort/grouping.\n * Поддерживает плоский и древовидный (`subRows`) режимы любой глубины вложенности.\n *\n * **Дефолтное поведение** (без `getRowMarker`): root-only нумерация —\n * корневые строки получают номер (`startIndex + rootIndex`), дочерние — пустую строку.\n *\n * @example\n * ```tsx\n * // Минимальная конфигурация\n * tableConfig={{ rowMarkers: { startIndex: 1 } }}\n *\n * // Сквозная стабильная нумерация\n * tableConfig={{ rowMarkers: { getRowMarker: ({ flatIndex }) => flatIndex + 1 } }}\n * ```\n */\nexport type RowMarkersTableConfig<\n RowType extends ObjectForExtending = ObjectForExtending,\n> = {\n /**\n * Стартовый индекс нумерации (для дефолтной логики без `getRowMarker`).\n * @default 1\n */\n startIndex?: number;\n\n /**\n * Ширина столбца с нумерацией (в px).\n * Если задан `size` — он приоритетнее.\n+ * Если ни `size`, ни `width` не заданы — ширина подстраивается\n+ * под глобальный `tableConfig.rowSize` (small=20, medium=32, big=48).\n * @default 32\n */\n width?: number;\n /**\n * Размер столбца. Приоритетнее `width`.\n * - `xs` = 20px\n * - `s` = 32px\n * - `m` = 48px\n */\n size?: 'xs' | 's' | 'm';\n /**\n * Кастомная функция нумерации. Полностью переопределяет дефолтную root-only логику.\n * Вызывается при рендере каждой ячейки столбца нумерации.\n *\n * ⚠️ Вызывается не только при полной отрисовке таблицы, но и при ховере/скролле —\n * для **одной** ячейки. Не используйте внешние переменные-счётчики —\n * используйте аргументы (`siblingPath`, `flatIndex` и др.), они всегда актуальны.\n *\n * @example\n * // Сквозная стабильная нумерация (все строки, номера не прыгают при сворачивании)\n * getRowMarker: ({ flatIndex }) => flatIndex + 1\n *\n * @example\n * // Корневые — номер, дочерние — прочерк\n * getRowMarker: ({ isSubRow, flatIndex }) => isSubRow ? '—' : flatIndex + 1\n *\n * @example\n * // Иерархическая нумерация любой глубины: 1, 1.1, 1.1.1, 1.2, 2\n * getRowMarker: ({ siblingPath }) => siblingPath.map(i => i + 1).join('.')\n */\n getRowMarker?: (args: {\n /** Данные текущей строки. */\n row: RowType;\n /** Уровень строки в дереве: `0` — корневая, `1` — дочерняя, `2` — внучка, и т.д. */\n level: number;\n /** `true`, если строка дочерняя (`level > 0`). */\n isSubRow: boolean;\n /**\n * Индекс строки в **видимых** строках.\n * **Нестабильный** — меняется при сворачивании и разворачивании веток.\n */\n rowIndex: number;\n /**\n * Стабильный 0-based индекс строки в **полном** дереве (включая скрытые/свёрнутые).\n * Не меняется при collapse/expand — подходит для сквозной нумерации.\n */\n flatIndex: number;\n /**\n * Порядковый номер среди siblings одного родителя (0-based).\n * Для корневых строк — порядковый номер среди всех корневых.\n * Для дочерних — порядковый номер среди children одного `parentKey`.\n */\n siblingIndex: number;\n /**\n * Путь siblingIndex-ов от корня до текущей строки (каждый элемент 0-based).\n *\n * Примеры:\n * - корневая строка (2-я): `[1]`\n * - дочерняя (3-й ребёнок 2-го корня): `[1, 2]`\n * - внучка (1-й ребёнок 1-го ребёнка 1-го корня): `[0, 0, 0]`\n *\n * Для иерархической нумерации: `siblingPath.map(i => i + 1).join('.')` → `\"1.1.1\"`\n *\n * Для плоской таблицы (без subRows): всегда `[siblingIndex]` (один элемент).\n */\n siblingPath: number[];\n /**\n * Ключ родительской строки (`rowKeyGetter(parent)`).\n * `null` для корневых строк. Работает для **любой** глубины вложенности.\n */\n parentKey: string | number | null;\n /** Текущий видимый `flattened` массив строк. */\n rows: readonly RowType[];\n }) => string | number;\n};\n```\n\n## FilterComponentInPopoverProps\n\nПропсы, доступные в кастомном компоненте фильтра (`component: 'custom'`).\n\n```typescript\ntype FilterComponentInPopoverProps<\n FilterStateType extends ObjectForExtending,\n ColumnConfig,\n> = {\n popoverIsOpen: boolean;\n setPopoverIsOpen: React.Dispatch<React.SetStateAction<boolean>>;\n columnConfig: ColumnConfig;\n tabIndex: number;\n headerContextState: HeaderContextValueTypeInstance<FilterStateType> &\n FiltersVariables &\n HeaderContextValueTypeInstance<ObjectForExtending>;\n /**\n * Источник открытия фильтра: из шапки таблицы или из сайдбара\n * Полезно для условной логики в customRender (например, alwaysOpened для combobox)\n */\n filterSource?: 'header' | 'sidebar';\n};\n```",
53356
+ "apiDocs": "# Filtering API\n\n## FilteringConfig\n\n```typescript\ntype FilteringConfig<T> = {\n state: [T, React.Dispatch<React.SetStateAction<T>>];\n /**\n * @deprecated Использовать filtersInfo\n *\n * clearedValue - состояние фильтров после очистки. Используется для сравнения:\n * Например, был ли фильтр конкретной колонки изменен рассчитывается посредством сравнения текущего значения фильтра и значения фильтра в clearedValue.\n * Если они равны, то фильтр считается не измененным.\n */\n clearedValue?: T;\n /**\n * Информация о фильтрах для каждой колонки.\n * Используется для:\n * 1. Хранения меток (label) фильтров для отображения в UI\n * 2. Хранения значений по умолчанию (clearedValue) для каждого фильтра\n * 3. Определения, был ли фильтр изменен (сравнение текущего значения с clearedValue)\n */\n filtersInfo?: Record<\n keyof T,\n {\n label: string;\n clearedValue: T[keyof T];\n }\n >;\n /**\n * manualFiltering - пропс, активирующий ручную-кастомную (или на стороне бэка) фильтрацию.\n * @remarks\n * Для автоматической фильтрации (когда не используется manualFiltering в tableConfig):\n * - Для всех типов фильтров обязательно должен быть указан `valueInRow`\n * - Для component: 'select' дополнительно должен быть указан `filteringType`\n * - Для component: 'input' с кастомным фильтром (когда filter - функция)\n * функция фильтрации должна быть передана явно\n *\n * Если используется manualFiltering, эти параметры не обязательны,\n * так как вся логика фильтрации реализуется извне.\n */\n manualFiltering?: boolean;\n /**\n * Конфигурация для отображения фильтров в правом сайдбаре.\n *\n * Позволяет:\n * 1. Добавлять глобальные фильтры (не привязанные к конкретной колонке)\n * 2. Управлять порядком отображения фильтров\n * 3. Переопределять рендер и заголовки колоночных фильтров\n *\n * Логика работы:\n * - По умолчанию в сайдбаре отображаются все колоночные фильтры (из columnConfig)\n * - Ключом фильтра считается `key` колонки, если его нет, то пытаемся взять `keyInFilterState` (если указан), иначе это не будет работать\n * - Заголовком фильтра по умолчанию является `name` колонки или ключ фильтра (name || key)\n * - Глобальные фильтры добавляются через `items` с уникальными ключами\n *\n * Особенности:\n * 1. Порядок отображения:\n * - Сначала фильтры из `order` (в указанной последовательности)\n * - Затем остальные колоночные фильтры (в порядке columnConfig)\n * - В конце - глобальные фильтры (в алфавитном порядке ключей)\n *\n * 2. Переопределение колоночных фильтров:\n * - Чтобы изменить заголовок: укажите ключ колонки в `items` с новым `label`\n * - Чтобы заменить рендер: укажите ключ колонки с `customRenderFn`\n * - Оригинальный фильтр из колонки будет проигнорирован\n *\n * 3. Глобальные фильтры:\n * - Ключ не должен совпадать с ключами колонок\n * - Обязательно указать `label` и `customRenderFn`\n * - Отображаются после всех колоночных фильтров, если не переопределены в order\n *\n * @example\n * // Добавление глобального фильтра и изменение порядка\n * sidebarConfig: {\n * order: ['status', 'tasks', 'type'], // Сначала статус, затем глобальный поиск\n * items: {\n * tasks: { // Уникальный ключ\n * label: 'Поиск по всем полям',\n * customRenderFn: () => <TaskComponent />\n * },\n * status: { // Переопределение колоночного фильтра\n * label: 'Статус заявки', // Новый заголовок\n * customRenderFn: () => <CustomStatusFilter /> // Кастомный рендер\n * }\n * type: { // Переопределение только Label колоночного фильтра\n * label: 'Тип', // Новый заголовок\n * }\n * }\n * }\n */\n sidebarConfig?: {\n /**\n * Определяет порядок отображения фильтров.\n * - Указываются ключи фильтров (колоночных или глобальных)\n * - Не указанные в order фильтры отображаются после\n * - Если order пуст, сохраняется порядок: глобальные фильтры + columnConfig фильтры в конце\n */\n order?: string[];\n /**\n * Конфигурация фильтров для сайдбара.\n * Ключом может быть:\n * - Ключ колонки (для переопределения колоночного фильтра)\n * - Уникальный ключ (для добавления глобального фильтра)\n */\n items: Partial<\n Record<\n keyof T,\n {\n /** Заголовок фильтра (обязателен для глобальных фильтров), можно использовать для переопределения для локальных фильтров */\n label: string;\n /**\n * Функция рендера компонента фильтра.\n * Для колоночных фильтров переопределяет оригинальный рендер.\n * Для глобальных фильтров обязательна.\n */\n customRenderFn?: (\n filters: T,\n setFilters: React.Dispatch<React.SetStateAction<T>>,\n ) => React.ReactNode;\n }\n >\n >;\n };\n /**\n * Callback для кастомизации стилей чипсов (фильтров) в списке\n *\n * @param {ItemOrGroup} itemOrGroup - Текущий элемент или группа фильтров\n * @param {Item | undefined} item - Конкретный элемент фильтра (если есть)\n * @returns {CSSObject} Объект стилей, который будет применен к чипсу\n *\n * @description\n * Позволяет динамически задавать стили для каждого чипса в зависимости от его типа и содержимого.\n * Вызывается для каждого отображаемого чипса (как для отдельных элементов, так и для элементов внутри групп).\n *\n * @example\n * // Пример 1: Стилизация чипсов по типу\n * chipStyle: (itemOrGroup, item) => {\n * if (isGroup(itemOrGroup)) {\n * return { backgroundColor: '#f0f0f0' };\n * }\n * return { backgroundColor: '#e0e0e0' };\n * }\n *\n * @example\n * // Пример 2: Стилизация по значению фильтра\n * chipStyle: (itemOrGroup, item) => {\n * if (item?.label === 'Высокий приоритет') {\n * return {\n * backgroundColor: '#ffebee',\n * color: '#d32f2f'\n * };\n * }\n * return {};\n * }\n *\n * @example\n * // Пример 3: Разные стили для элементов в группе и одиночных\n * chipStyle: (itemOrGroup, item) => {\n * if (item) {\n * // Стиль для элемента внутри группы\n * return { maxWidth: 180 };\n * }\n * // Стиль для одиночного чипа\n * return { maxWidth: 150 };\n * }\n */\n chipStyle?: (itemOrGroup: ItemOrGroup, item: Item | undefined) => CSSObject;\n /**\n * Пользовательский форматтер заголовка группы чипсов.\n *\n * Используется в блоке активных фильтров для подмены текста заголовка\n * группы (например, “Статус”, “Тип”, “Автор”). Полезно, когда нужно\n * динамически менять подпись (добавить счётчик, i18n и т.п.).\n *\n * @param {ItemOrGroup} itemOrGroup Объект группы (тип Group). Вызов происходит только для групп,\n * поэтому безопасно кастовать к Group.\n * @returns {string} Текст заголовка группы чипсов.\n *\n * @default Возвращается `group.groupLabel`.\n *\n * @remarks\n * - Функция должна быть чистой и быстрой (без сетевых запросов и побочных эффектов).\n * - Возвращайте ТОЛЬКО строку — чипы отображают текстовое значение.\n * - Для длинных строк применяется усечение (overflow с многоточием) на уровне компонента.\n *\n * @example\n * // Добавить двоеточие и количество выбранных элементов\n * renderGroupLabel: (group) => `${group.groupLabel}: ${group.items.length}`\n *\n * @example\n * // Локализация заголовка группы\n * const i18n = { status: 'Статус', type: 'Тип' };\n * renderGroupLabel: (group) => i18n[group.groupId] ?? group.groupLabel\n */\n renderGroupLabel?: (group: Group) => string;\n\n /**\n * Пользовательский форматтер текста чипса (элемента внутри группы или одиночного фильтра).\n *\n * Позволяет управлять тем, что именно отображается внутри каждого чипса. Особенно полезен\n * при серверной пагинации/ленивой загрузке, когда в состоянии фильтра хранится только value,\n * а label необходимо подставить из локального кэша.\n *\n * @param {Group | null } group Группа, внутри которой рендерится чип (или null).\n * @param {Item} item Сам элемент чипса. В группах передаётся конкретный `Item`,\n * для одиночного чипа может быть `undefined`.\n * @returns {string} Текст, который будет показан в чипсе.\n *\n * @default Используется `item?.label.toString()` (или строковое представление value).\n *\n * @remarks\n * - Функция должна быть чистой и быстрой;\n * - Возвращайте ТОЛЬКО строку.\n *\n * @example\n * // 1) Отображение label из кэша при серверной пагинации\n * const labelsCacheRef = useRef(new Map<string, string>());\n * renderChipLabel: (group, item) => {\n * if (item?.id != null) {\n * const key = String(item.id);\n * const fromCache = labelsCacheRef.current.get(key);\n * if (fromCache) return fromCache; // красивый label, если уже загрузили\n * return String(item.label ?? key); // фоллбэк: временно показываем value/label из item\n * }\n * return ''; // безопасный фоллбэк для одиночных случаев\n * }\n *\n * @example\n * // 2) Нормализация отображения числовых значений\n * renderChipLabel: (_group, item) => {\n * const v = Number(item?.label);\n * return Number.isFinite(v) ? v.toLocaleString('ru-RU') : String(item?.label ?? '');\n * }\n *\n * @example\n * // 3) Префикс по типу группы\n * renderChipLabel: (group, item) => {\n * const prefix = group.groupId === 'status' ? '' : '#';\n * return `${prefix}${item?.label ?? item?.id ?? ''}`;\n * }\n */\n renderChipLabel?: (group: Group | null, item: Item) => string;\n};\n\nexport type DefaultSidebarTabIds = 'columns' | 'tableSettings' | 'filtering';\n\n/**\n * Конфигурация sidebar\n */\nexport type SidebarConfig = {\n /**\n * Включен ли sidebar. Отвечает только за UI. Не влияет на перерасчёт фичей.\n * @default true\n */\n enabled?: boolean;\n /**\n * Открыт ли sidebar при первом рендере (uncontrolled-режим).\n * Игнорируется, если передан openState.\n * @default false\n */\n defaultOpen?: boolean;\n /**\n * Внешний контроль открытия/закрытия sidebar.\n * Если передан — источник истины, defaultOpen игнорируется.\n */\n openState?: [boolean, React.Dispatch<React.SetStateAction<boolean>>];\n /**\n * id вкладки, выбранной по умолчанию (актуально при открытом сайдбаре).\n * Если id не найден или у вкладки showInSidebar=false — используется первая доступная.\n */\n defaultActiveTabId?: string;\n /**\n * Внешний контроль активной вкладки (controlled-режим).\n * Если передан — источник истины, defaultActiveTabId игнорируется.\n */\n activeTabState?: [\n string | null,\n React.Dispatch<React.SetStateAction<string | null>>,\n ];\n /**\n * Колбэк смены активной вкладки. Вызывается и в uncontrolled-режиме.\n * При закрытии сайдбара приходит null.\n */\n onActiveTabChange?: (tabId: string | null, tab?: SidebarTab) => void;\n /**\n * Кастомные табы\n */\n customTabs?: Array<\n Omit<SidebarTab, 'id'> & {\n id: Exclude<string, DefaultSidebarTabIds>;\n }\n >;\n /**\n * Порядок отображения кастомных вкладок\n */\n customTabsOrder?: Array<Exclude<string, DefaultSidebarTabIds>>;\n defaultTabs?: Array<\n | {\n id: 'filtering' | 'columns';\n /** название таба в рамках горизонтального табов внутри таба настройки */\n label?: string;\n /** название таба в рамках вертикальных табов сайдбара (если данный таб окажется единственным табом в настройках) */\n title?: string;\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n domMetadata?: DomMetadata;\n /**\n * Кастомный элемент справа от title в шапке сайдбара\n */\n titleRightSlot?: React.ReactNode;\n /** @default true */\n showInSidebar?: boolean;\n /** тултип иконки шестеренки (для табов с id = filtering и columns - недоступен. Настраивается через таб с id='tableSettings') */\n iconTooltipText?: undefined;\n }\n | {\n id: 'tableSettings';\n /** название таба в рамках горизонтального табов внутри таба настройки */\n label?: string;\n /** название таба в рамках вертикальных табов сайдбара */\n title?: string;\n\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n domMetadata?: DomMetadata;\n /**\n * Кастомный слот для вкладки tableSettings (рендерится после общих настроек)\n * Только дл id: 'tableSettings'\n */\n customGeneralSettingsSlot?: React.ReactNode;\n /**\n * Кастомный элемент справа от title в шапке сайдбара\n */\n titleRightSlot?: React.ReactNode;\n /** @default true */\n showInSidebar?: boolean;\n /** тултип иконки шестеренки @default 'Настройки' */\n iconTooltipText?: string;\n }\n >;\n};\n\nexport function activeViewIs<T extends 'cards' | 'rows'>(\n checkType: T,\n viewState: 'cards' | 'rows',\n view: View,\n): view is ViewMods[T] {\n return checkType === viewState;\n}\n\n/** Размер controlBlock: 'm' и 's' — одинаковые стили, 'xs' — уменьшенный */\nexport type ControlBlockSize = 'm' | 's' | 'xs';\n\nexport type ControlBlockConfig = {\n /**\n * show - наличие controlBlock-а\n * @default true\n */\n show?: boolean;\n /**\n * Размер controlBlock и его элементов (кнопки, иконки, поиск, отступы).\n * 'm' и 's' — стандартные стили, 'xs' — компактный режим.\n * Не влияет на customFeatures и кастомные слоты — они контролируются разработчиком.\n * @default 'm'\n */\n size?: ControlBlockSize;\n /**\n * @deprecated Используйте кастомные кнопки через rightSideInner или customFeatures.\n * leftSideInner - пропс для добавления кнопок в левую часть контролблока.\n * Продолжает работать для обратной совместимости.\n */\n leftSideInner?: ControlBlockButtonProps[];\n /**\n * rightSideInner - пропс для добавления кнопок в правую часть контролблока\n */\n rightSideInner?: ControlBlockButtonProps[];\n /**\n * customFeatures - пропс для добавления кастомных фичей (кнопки-иконки)\n */\n customFeatures?: FeatureItem[];\n /**\n * pinningMenu - нативная фича закрепления столбцов (SplitIconButton с\n * дропдауном) в правой зоне иконок. Появляется, когда активировано\n * закрепление колонок (columnsControl.pinning). Продукт может донастроить\n * и дополнить пункты меню (см. PinningMenuConfig).\n */\n pinningMenu?: PinningMenuConfig;\n /**\n * Пропсы для компонента dropdown в котором будут скрыты левые фичи при адаптивной компрессии\n */\n leftSideDropdownProps?: TableDropdownConfigProps;\n /**\n * Пропсы для компонента dropdown в котором будут скрыты правые фичи при адаптивной компрессии\n */\n rightSideDropdownProps?: TableDropdownConfigProps;\n /**\n * Активна ли фича компрессии (сжатие ToolsMenu при адаптиве)\n * @default true\n */\n enableAdaptiveCompress?: boolean;\n /**\n * Панель массовых действий\n */\n massActionPanel?: {\n /**\n * Кнопки панели. Размеры кнопок/дропдаунов панель подбирает сама (по `size` панели и компактности) —\n * передавать `size` кнопкам не нужно. Если `size` на кнопке всё же задан — он используется как есть.\n */\n buttons: MassActionButtonProps[];\n /**\n * Пропсы для Dropdown, в который сжались кнопки\n */\n collapsedDropdownProps?: TableDropdownConfigProps;\n /**\n * Отступ панели снизу от контейнера (px)\n * @default 24\n */\n bottom?: number;\n /**\n * Управление отображением панели массовых действий.\n * - `undefined` (по умолчанию) — стандартное поведение (показывается при selecting + выбранных строках)\n * - `false` — панель не рендерится, разработчик управляет действиями самостоятельно\n * - `true` — панель показывается всегда, даже без активного selecting и выбранных строк\n */\n show?: boolean;\n /**\n * Размерная сетка панели внутри таблицы: `m`/`s` — обычный размер, `xs` — уменьшенный (кнопки `xxs`, «ещё» `xs`, счётчик Body XS).\n * Viewport-логика (1280) в таблице не используется.\n * @default 's'\n */\n size?: MassActionsSize;\n };\n};\n\n/** Пропсы кнопки редактирования. onClick исключён — используйте onSave/onCancel/onEnableEditing. */\nexport type EditingButtonProps = Omit<\n Partial<ControlBlockButtonProps>,\n | 'onClick'\n | 'size'\n | 'dropdown'\n | 'isTargetAction'\n | 'skipRightDivider'\n | 'tooltipText'\n>;\n\nexport type EditingConfig<\n RowType extends ObjectForExtending,\n RowIdType,\n SummaryRowType,\n> = {\n /**\n * Функция обработки изменений в редактируемой строке\n */\n onRowsChange: Maybe<\n (rows: RowType[], data: RowsChangeData<RowType, SummaryRowType>) => void\n >;\n /**\n * свойство, необходимое для корректного изменения дочерних строк.\n * Данное свойство обязательно, если ваши дочерние строки установлены не под ключом \"subRows\" внутри строки.\n *\n * Как дочерние строки можно указывать свойство, которые вложено в другое свойство.\n * В таком случае \".\" будет знаком для обозначения сл. уровня вложенности.\n *\n * @example \"child\" или \"uvh367.children\"\n */\n subRowsKey?: string;\n /**\n * Глубокое копирование строк перед применением правки в режиме редактирования.\n *\n * Включите, если строки, передаваемые в таблицу, иммутабельны/заморожены\n * (напр. стейт под управлением Redux Toolkit или Immer — они вызывают\n * Object.freeze в dev). При редактировании дочерней строки таблица записывает\n * изменение ВНУТРЬ объекта родителя; на замороженном объекте это падает с\n * `TypeError: Cannot assign to read only property`.\n *\n * Когда флаг включён, таблица сама делает structuredClone редактируемой строки\n * перед записью — ваш иммутабельный стейт не мутируется, и редактирование\n * дочерних строк работает без действий с вашей стороны.\n *\n * ⚠️ Данные строки должны быть сериализуемыми. Где доступен structuredClone —\n * Date/Map/Set и вложенные структуры копируются корректно; на старых средах\n * без structuredClone используется JSON-фоллбэк (теряет Date/Map/Set, undefined\n * и функции). Не включайте без необходимости — глубокое копирование добавляет\n * накладные расходы.\n *\n * @default false\n */\n deepCloneRows?: boolean;\n /**\n * Функция определения уникального id строки\n * @param row\n * @returns\n */\n rowKeyGetter: (row: RowType) => RowIdType;\n /**\n * Функция определения возможности редактирования строки\n * @param row\n * @returns\n */\n rowEditable?: (row: RowType) => boolean;\n /**\n * defaultEnabled - пропс, отвечающий за то, будет ли активен режим редактирования или нет. По умолчанию - не активно.\n * @default false\n */\n defaultEnabled?: boolean;\n /**\n * enabled - необходим для управления режимом редактирования снаружи компонента Таблицы.\n * По умолчанию, управление происходит в компоненте.\n * Приоритетнее, чем defaultEnabled.\n *\n * @type boolean - если НЕ нужно переключение в самой таблице\n * @type [boolean, React.Dispatch<React.SetStateAction<boolean>>] - если нужно переключение в самой таблице\n *\n */\n enabled?: boolean | [boolean, React.Dispatch<React.SetStateAction<boolean>>];\n /**\n * Cостояние скрытия/раскрытия кнопки включения/выключения фичи\n * @default true\n */\n showButtons?: boolean;\n /**\n * Функция, вызывающаяся при включении фичи.\n * @param enableEditorMode - функция включающая режим редактирования\n */\n onEnableEditing?: (enableEditorMode: () => void) => void;\n /**\n * Функция, вызывающаяся при сохранении отредактированного.\n * @param disableEditorMode - функция выключающая режим редактирования\n */\n onSave?: (disableEditorMode: () => void) => void;\n /**\n * Функция, вызывающаяся при отмене отредактированного.\n * @param disableEditorMode - функция выключающая режим редактирования\n */\n onCancel?: (disableEditorMode: () => void) => void;\n /** Пропсы кнопок в controlBlock. */\n buttons?: {\n save?: EditingButtonProps;\n cancel?: EditingButtonProps;\n edit?: EditingButtonProps;\n };\n /**\n * Кастомный слот, отображаемый левее кнопок «Отменить» / «Сохранить».\n * Виден только когда режим редактирования активен (editMode = true).\n * Зона ответственности разработчика — размерная сетка controlBlock не влияет на этот слот.\n */\n editModeLeftSlot?: React.ReactNode;\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n domMetadata?: {\n enableButton?: DomMetadata;\n saveButton?: DomMetadata;\n cancelButton?: DomMetadata;\n };\n};\n\nexport type SummaryRowsConfig = {\n showDefault: boolean;\n showInControl: boolean;\n} & {\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n domMetadata?: DomMetadata;\n};\n\n/**\n * Конфиг тултипа при hover по canvas-элементам.\n * Для активации фичи необходимо заполнить данный конфиг,\n * а также добавить нужные изменения в Canvas-элементах или в конфиге колонки.\n */\nexport type TableConfigTooltip = {\n /**\n * Включить/выключить колоночные и кастомные тултипы (cellTooltip, headerCellTooltip).\n * Внутренние тултипы (drag-иконка в шапке и другие по nodeId) работают всегда.\n * @default false\n */\n enabled?: boolean;\n /** Глобальная задержка перед показом тултипа (мс). Per-node переопределяет. @default 500 */\n mouseEnterDelay?: number;\n /** Глобальная задержка перед скрытием тултипа (мс). Per-node переопределяет. @default 0 */\n mouseLeaveDelay?: number;\n /**\n * Минимальная ширина тултипа. Число трактуется как px, строка с единицей\n * (например '20rem', '50%') отдаётся как есть. Действует на все canvas-тултипы,\n * включая авто-тултип Canvas.Text. Если ширина задана на самом тултипе\n * (per-node), приоритет у неё.\n */\n minWidth?: number | string;\n /**\n * Максимальная ширина тултипа. Число трактуется как px, строка с единицей\n * (например '20rem', '50%') отдаётся как есть. Действует на все canvas-тултипы,\n * включая авто-тултип Canvas.Text. Если ширина задана на самом тултипе\n * (per-node), приоритет у неё.\n */\n maxWidth?: number | string;\n};\n\nexport type InfinityScrollConfig<RowType extends ObjectForExtending> = {\n /** Триггер достижения скроллом зоны подгрузки данных. */\n onTrigger: (rows: RowType[]) => Promise<void> | void;\n /** Состояние загрузки (скелетоны) новых строк. */\n isLoading: boolean;\n /**\n * Флаг, когда все данные загружены — false.\n * @default true\n */\n hasMore?: boolean;\n /**\n * Для mode='region': за сколько строк до конца триггерить загрузку.\n * @default 5\n */\n rowThreshold?: number;\n};\n\nexport type { TableCanvasEmptyStateConfig, TableCanvasErrorStateConfig };\n\n/**\n * Настройка выделения ячеек/колонок/строк в TableCanvas — единый объект.\n * Это отдельная ось взаимодействия — не зависит от `highlightActiveType`.\n */\nexport type CellsSelectionConfig = {\n /**\n * Режим фактического выделения ячеек (нативный glide selection). По нему\n * работают copy/paste, рамка, fill-handle и затемнение шапки/нумерации.\n * @default \"range-cell\"\n */\n mode?: CellsSelectionMode;\n /**\n * Выделение колонок по клику на шапку. Ctrl/Cmd — добавить/убрать колонку,\n * Shift — диапазон колонок. Клик по иконкам сортировки/фильтрации в шапке\n * выделение НЕ вызывает. Поддерживает copy/paste по выделенным колонкам.\n * @default true\n */\n enableColumnSelection?: boolean;\n /**\n * Выделение строк по клику/драгу на колонке нумерации (`rowMarkers`).\n * Ctrl/Cmd — несмежный выбор отдельных строк, драг — смежный диапазон.\n * Поддерживает copy/paste по выделенным строкам. Требует включённой колонки\n * нумерации (`rowMarkers`). При `false` клик по нумерации ничего не выделяет.\n * @default true\n */\n enableRowSelection?: boolean;\n /**\n * Выделение всей таблицы кликом по «нулевой» ячейке — шапке колонки нумерации\n * (левый верхний угол). Выделяет все строки данных по всем колонкам одним\n * диапазоном; поддерживает copy/paste. Требует включённой колонки нумерации\n * (`rowMarkers`) и активного `mode` (≠ `disabled`).\n * @default true\n */\n enableSelectAll?: boolean;\n /**\n * Внешний (controlled) контроль НАТИВНОГО выделения (ячейки/диапазон/смежные\n * строки и колонки). `state` — кортеж `[value, setter]` как у `selecting.state`.\n * Сброс: `setter({ current: undefined, rows: empty, columns: empty })`.\n * Несмежный Ctrl-выбор колонок/строк (own-state) сюда не входит — он внутренний.\n */\n state?: [GridSelection, React.Dispatch<React.SetStateAction<GridSelection>>];\n};\n\n/** Один объединённый блок: какие строки и колонки слить. */\nexport type MergedCellsRegion = {\n rowKeys: Array<string | number>;\n colKeys: string[];\n /** Выравнивание контента этого блока. Важнее колоночного и общего. */\n mergedCellsAlign?: MergedCellsAlign;\n};\n\nexport type TableConfig<\n RowType extends ObjectForExtending,\n SummaryRowType,\n RowIdType extends string | number,\n FilterStateType extends ObjectForExtending,\n // SubRowType\n> = {\n /**\n * Группировка колонок (многоуровневая шапка через `columnConfig.children`):\n * объединение пустых ячеек шапки (`squashEmptyCells`, по умолчанию включено) и\n * дефолт выравнивания в объединённых ячейках (`squashedHeaderAlign`).\n */\n columnsGrouping?: ColumnsGroupingConfig;\n /**\n * Подсветка активной сущности в canvas-таблице.\n * @deprecated Значения `'cell'`/`'range-cell'` устарели — используйте\n * `cellsSelection.mode`. Актуальны `'row'` (подсветка строки) и `'disabled'`.\n */\n highlightActiveType?: HighlightActiveType;\n /**\n * Единый конфиг выделения ячеек: режим (`mode`), оси\n * (`enableColumnSelection`/`enableRowSelection`/`enableSelectAll`) и controlled\n * (`state`). См. {@link CellsSelectionConfig}.\n */\n cellsSelection?: CellsSelectionConfig;\n /**\n * Подсвеченная строка (`highlightActiveType='row'`).\n * `state` (опционально) — controlled-кортеж `[value, setter]`: задан — значением\n * владеешь снаружи (сброс `setter(undefined)`); не задан — таблица крутит\n * подсветку внутренним стейтом, а `onChange` всё равно срабатывает (подписка\n * без владения значением).\n */\n highlightActiveRow?: {\n state?: [\n number | undefined,\n React.Dispatch<React.SetStateAction<number | undefined>>,\n ];\n /**\n * Колбэк смены подсвеченной строки: отдаёт её флэт-индекс и сам объект\n * строки (`rows[index]`). Позволяет открывать данные подсвеченной строки\n * (например, в SplitView) без `onCellClicked`.\n */\n onChange?: (params: {\n index: number | undefined;\n row: RowType | undefined;\n }) => void;\n };\n /**\n * Эффекты при наведении (hover)\n * `row` — подсветка строки под курсором.\n * Независимая визуальная ось: селектинг (`cellsSelection`) и `highlightActiveType='row'`\n * рисуются ПОВЕРХ hover-подсветки и визуально перекрывают её (hover\n * «остаётся под ними» и снова виден после сброса выделения).\n *\n * `{ row: true }` — включить с цветами из темы;\n * `{ row: { color: '#F7F9FB' } }` — переопределить цвет data-ячеек.\n * @default undefined (выключено)\n */\n hoverEffects?: HoverEffectsConfig;\n /**\n * Включает компенсацию тонких canvas-линий при browser zoom ниже 100%, когда devicePixelRatio меньше 1.\n * Влияет только на grid/header/sticky hairline borders.\n * @default false\n */\n enableLowDprHairline?: boolean;\n /**\n * rowSize - размеры строк таблицы\n */\n rowSize?: Prettify<RowSize>;\n /**\n * rowHeight - размер высоты строк таблицы\n */\n rowHeight?: Maybe<number | RowHeightFunc<RowType>>;\n /**\n * sorting - активация сортировки. Условие активации - это наличие данного свойства. Нужно также сконфигурировать колонки.\n *\n * Пример:\n *\n * tableConfig={sorting: {sortingState}}\n *\n * columnConfig=[{sortingType: 'numberSort'}]\n */\n sorting?: {\n state: [\n readonly SortColumn[],\n React.Dispatch<React.SetStateAction<readonly SortColumn[]>>,\n ];\n /**\n * manualSorting - пропс, активирующий ручную-кастомную (или на стороне бэкенда) сортировку\n */\n manualSorting?: boolean;\n };\n /** @deprecated Свойство view не используется и будет удалено в следующей мажорной версии. */\n view?: View;\n /**\n * filtering - активация фильтрации. Условие активации - это наличие данного свойства. Нужно также сконфигурировать колонки.\n *\n * Пример:\n *\n * tableConfig={filtering: {stateAndSetter, ...}}\n *\n * columnConfig=[{filtering: {...}}]\n */\n filtering?: FilteringConfig<FilterStateType>;\n /**\n * Сворачивание / разворачивание таблицы\n */\n collapsing?: TableCollapseConfig;\n /**\n * selecting - активация выбора строк. Условие активации - это наличие данного свойства.\n * Есть поддержка выбора строк с многоуровневой вложенностью.\n *\n * Пример:\n *\n *```jsx\n * import { Table } from '@daisforge/ui';\n *\n * <Table\n * tableConfig={{selecting: {stateAndSetter, rowKeyGetter}}}\n * {...rest}\n * />\n * ```\n */\n selecting?: {\n state: [\n ReadonlySet<RowIdType>,\n React.Dispatch<React.SetStateAction<ReadonlySet<RowIdType>>>,\n ];\n rowKeyGetter: (row: RowType) => RowIdType;\n } & Prettify<SelectingRowConfig<RowType, RowIdType>> & {\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n controlBlock?: {\n domMetadata?: DomMetadata;\n };\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам RightSidebar\n */\n sidebar?: {\n domMetadata?: DomMetadata;\n };\n };\n /**\n * editing - активация редактирования. Условие активации - это наличие данного свойства. Нужно также сконфигурировать колонки.\n *\n * Пример:\n *\n * tableConfig={editing: {onRowsChange, rowKeyGetter}}\n *\n * columnConfig=[{editingCell: {...}}]\n */\n editing?: EditingConfig<RowType, RowIdType, SummaryRowType>;\n\n /**\n * cellTransfer — конфигурация копирования, вставки и fill handle.\n * По умолчанию копирование (Ctrl+C) работает в режиме редактирования.\n * Данные копируются в формате TSV (tab-separated values), совместимом с Excel.\n *\n * Пример:\n *\n * tableConfig={{ cellTransfer: { enabled: true, onBeforeCopy: (data) => data } }}\n */\n cellTransfer?: CellTransferConfig;\n\n /**\n * Объединение ячеек тела таблицы.\n *\n * mergeByCellValues — колонки, в которых подряд идущие одинаковые значения\n * сливаются в один блок (по вертикали). Границы блоков таблица считает сама из\n * данных; сортировка и фильтр их пересобирают. Данные не меняются — значение и\n * так повторяется в строках, объединение лишь показывает его одной ячейкой.\n *\n * mergedCellsRegions — список блоков, заданных снаружи (как выделение): каждый\n * блок описан ключами строк (rowKeys) и колонок (colKeys). Нужен rowKeyGetter.\n * Если после сортировки или скрытия колонок строки/колонки блока перестали идти\n * подряд — блок не рисуется. Важнее mergeByCellValues.\n *\n * Примеры: mergeCells={{ mergeByCellValues: ['dept', 'role'] }},\n * mergeCells={{ mergedCellsRegions, rowKeyGetter: (r) => r.id }}.\n */\n mergeCells?: {\n mergeByCellValues?: Array<\n string | { colKey: string; value: (row: RowType) => unknown }\n >;\n /** Список блоков, заданных снаружи (по ключам строк и колонок). */\n mergedCellsRegions?: MergedCellsRegion[];\n /**\n * Нужен для mergedCellsRegions: находит строку по её ключу. Должна быть\n * стабильной функцией; менять её на лету не нужно — в пересборку таблицы она\n * не входит.\n */\n rowKeyGetter?: (row: RowType) => string | number;\n /**\n * Выравнивание по умолчанию для всех блоков. Колоночный mergedCellsAlign и\n * выравнивание конкретного региона важнее.\n */\n mergedCellsAlign?: MergedCellsAlign;\n };\n\n /**\n * Модуль нотификаций: стандартизированный канал событий для внешних\n * потребителей. Таблица UI не рисует — вызывает `onNotification`, потребитель\n * показывает тост/модалку на своей стороне. Сейчас эмитятся ошибки copy/paste\n * (в т.ч. multi-range 2D-разброс, readonly/overflow-abort, пропуск валидацией).\n */\n notifications?: TableNotificationsConfig;\n\n /**\n * subRows - активация иерархии, отображения вложенных строк. Условие активации - наличие данного свойства. Нужно также сконфигурировать колонки.\n *\n * Пример:\n *\n * tableConfig={subRows: {getSubRows, rowKeyGetter}}\n *\n * columnConfig=[{subRow: {...}}]\n */\n subRows?: SubRows<RowType, RowIdType>;\n /**\n * Столбец с нумерацией строк.\n * Активируется наличием этого свойства. Поддерживает `subRows` любой глубины.\n *\n * @see {@link RowMarkersTableConfig} — полное описание конфигурации и примеры.\n */\n rowMarkers?: RowMarkersTableConfig<RowType>;\n rowsGrouping?: RowsGrouping<RowType, SummaryRowType>;\n\n /**\n * resizableColumn - активация изменения ширины колонки с помощью курсора. Условие активации - resizableColumn: true. Нужно также сконфигурировать колонки.\n *\n * Пример:\n *\n * tableConfig={resizableColumn: true}\n *\n * columnConfig=[{resizable: true}]\n */\n resizableColumn?: boolean;\n /**\n * style - inline-стили. Для стилей самой таблицы (без вложенности).\n *\n * Исключены свойства 'width' | 'height' | 'minWidth' | 'minHeight' | 'maxWidth' | 'maxHeight'. Их следует стилизовать через свойства containerStyle.\n */\n style?: Omit<\n CSSProperties,\n 'width' | 'height' | 'minWidth' | 'minHeight' | 'maxWidth' | 'maxHeight'\n >;\n /**\n * css - для стилей простых и сложных(например, для стилизации cell, headerCell, ...).\n *\n * Пример:\n *\n * ```css\n * & > .rdg-header-row > .rdgCell {\n * background-color: red;\n * }\n * ```\n *\n */\n css?: string | CSSObject;\n\n summaryRows?: SummaryRowsConfig;\n /**\n * controlBlock - пропс для активации, кастомизации контролблока.\n */\n controlBlock?: ControlBlockConfig;\n /**\n * containerStyle - инлайновые стили контейнера таблицы и контролблока. высоту и ширину для таблицы рекомендуется задавать в этом пропсе.\n * Пример:\n *\n * ```tsx\n tableConfig={{ containerStyle: { height: '70vh' } }}\n * ```\n */\n containerStyle?: CSSProperties | undefined;\n /**\n * containerCss - стили для контейнера таблицы и контролблока.\n * Через этот пропс можно дополнительно кастомизировать контейнер и все его дочерние элементы.\n */\n containerCss?: string | CSSObject | undefined;\n /**\n * containerId - html-атрибут id контейнера таблицы.\n */\n containerId?: string | undefined;\n\n /**\n * unstickyHeader - откреплённая шапка. Header уезжает вместе со скроллом контента.\n * @default false\n */\n unstickyHeader?: boolean;\n\n /** Тултип при hover по canvas-элементам.\n * Для активации фичи необходимо заполнить данный конфиг,\n * а также добавить нужные изменения в Canvas-элементах или в конфиге колонки.\n */\n tooltip?: TableConfigTooltip;\n\n /**\n * infinityScroll - бесконечная подгрузка данных при скролле.\n *\n * Условие активации - наличие самого пропса infinityScroll.\n *\n * При активации infinityScroll отключается дефолтная сортировка и фильтрация.\n * (Предполагается, что если есть infinityScroll,\n * то в таблице представлен не весь объем данных,\n * по этой причине дефолтная сортировка и фильтрация не подходят и будут отображать некорректные данные)\n *\n */\n infinityScroll?: InfinityScrollConfig<RowType>;\n /**\n * @isLoading - состояние загрузки данных для таблицы.\n */\n isLoading?: boolean | { boolean: boolean; skeletonRowsCount: number };\n /**\n * loadingOverlay - конфигурация для отображения оверлея загрузки.\n * Показывает индикатор загрузки поверх таблицы с возможностью кастомизации.\n */\n loadingOverlay?: {\n /**\n * Активен ли оверлей загрузки\n * @default true\n */\n active?: boolean;\n /**\n * Кастомный компонент спиннера\n * @default <Spinner view=\"secondary\" size=\"36\" /> (внутренний компонент)\n */\n spinner?: ReactNode;\n /**\n * Основной заголовок оверлея\n * @default \"Загрузка таблицы\"\n */\n title?: string;\n /**\n * Подзаголовок, который появится после задержки, пустая строка - значит он не появится\n * @default \"\"\n */\n subtitle?: string;\n /**\n * Задержка перед показом подзаголовка (мс)\n * @default 10000 (10 секунд)\n */\n showSubtitleDelay?: number;\n };\n /**\n * Empty state внутри content-области canvas-таблицы.\n * Не заменяет control block, header или pagination.\n */\n emptyState?: TableCanvasEmptyStateConfig;\n /**\n * Error state внутри content-области canvas-таблицы.\n * Не заменяет control block, header или pagination.\n */\n errorState?: TableCanvasErrorStateConfig;\n // FIXME:\n // noRowsFallback?: boolean | { custom: ReactNode };\n columnsControl?: ColumnsControlConfig;\n // FIXME:\n // rowDetailPanel?: RowDetailConfig<RowType>;\n // FIXME: Временно комментирую использование, пока не адаптируем TableCanvas\n // rowInstruments?: {\n // getRowDropdownConfig: RowInstrumentsType<RowType>;\n // /**\n // * @default false\n // */\n // defaultOpened?: boolean;\n // /**\n // * @default true\n // */\n // showInControl?: boolean;\n // /**\n // * Внешний стейт видимости\n // */\n // openedState?: [boolean, React.Dispatch<React.SetStateAction<boolean>>];\n // };\n fullScreenEnabled?: FullScreen;\n /**\n * Переносит портал editor overlay внутрь контейнера таблицы вместо document.body.\n * Решает проблему focus trap и сдвига координат при рендере таблицы в модалке с CSS transform.\n * @default undefined (overlay рендерится в document.body — стандартное поведение)\n */\n editorOverlayPortal?: 'inside';\n keyText?: boolean | KeyTextConfig;\n /**\n * pagination - пропс для пагинации.\n *\n * Условие активации - наличие самого пропса pagination.\n *\n * При активации pagination отключается дефолтные поиск, сортировка и фильтрация.\n * (поиск работает на уровне с фильтрацией и сортировкой, сначала поиск, затем фильтрация, затем сортировка)\n *\n */\n pagination?: PaginationProps;\n /**\n * searching - пропс для поиска по таблицу.\n *\n * Условие активации - наличие searching.enabled: true\n *\n */\n /**\n * Конфигурация табов в сайдбаре\n */\n sidebarConfig?: SidebarConfig;\n searching?: SearchingProps;\n /**\n * onHeaderContextMenu - callback открытия контекстного меню.\n */\n onHeaderContextMenu?: TableGlideInstanceProps<\n RowType,\n SummaryRowType\n >['onHeaderContextMenu'];\n onHeaderContextMenuDropdown?: TableGlideInstanceProps<\n RowType,\n SummaryRowType\n >['onHeaderContextMenuDropdown'];\n onCellContextMenuDropdown?: TableGlideInstanceProps<\n RowType,\n SummaryRowType\n >['onCellContextMenuDropdown'];\n onCellContextMenu?: TableGlideInstanceProps<\n RowType,\n SummaryRowType\n >['onCellContextMenu'];\n /**\n * Обработчик клика по ячейке.\n *\n * Получает `cell` readonly [colIndex, rowIndex] от glide, и `info` обогащённый объект\n * с row, column, ctxs, refTable (аналогично onCellContextMenu).\n */\n onCellClicked?: (\n cell: readonly [number, number],\n info: TableInfoWithRow<RowType, SummaryRowType>,\n ) => void;\n} & GlideInstanceOmitted<RowType, SummaryRowType>;\n\ntype GlideInstanceOmitted<\n RowType extends ObjectForExtending,\n SummaryRowType,\n> = Pick<\n Omit<\n TableGlideInstanceProps<RowType, SummaryRowType>,\n | keyof TableGlideCustomProps<RowType, SummaryRowType>\n | 'CellReadOnlyEditor' /* CellReadOnlyEditor - свойство только для GlideInstance */\n >,\n | 'className'\n | 'columnSelect'\n | 'minColumnWidth'\n | 'maxColumnWidth'\n | 'maxColumnAutoWidth'\n | 'onVisibleRegionChanged'\n | 'onCellClicked'\n // | 'CellReadOnlyEditor'\n // | 'onGroupHeaderClicked'\n | 'onHeaderClicked'\n | 'onItemHovered'\n | 'trapFocus'\n | 'onColumnResize'\n>;\nexport type CellReadOnlyEditorProps<\n RowType extends ObjectForExtending,\n SummaryRowType,\n> = CellReadOnlyEditorGlideInstanceStaticProps &\n EditingCellInfo<RowType, SummaryRowType>;\n\n// & Pick<\n// DataGridPropsDefault<RowType, SummaryRowType, RowIdType>,\n// | 'summaryRowHeight'\n// | 'onFill'\n// | 'onCopy'\n// | 'onPaste'\n// | 'onCellClick'\n// | 'onCellDoubleClick'\n// | 'onCellContextMenu'\n// | 'onCellKeyDown'\n// | 'onSelectedCellChange'\n// | 'onScroll'\n// | 'onColumnResize'\n// | 'onColumnsReorder'\n// | 'enableVirtualization'\n// | 'rowClass'\n// | 'data-testid'\n// | 'headerRowHeight'\n// >;\n\n/**\n * Конфигурация фичи rowMarkers (столбец с нумерацией строк).\n *\n * Столбец frozen, вставляется первым, исключён из reorder/pin/hide/sort/grouping.\n * Поддерживает плоский и древовидный (`subRows`) режимы любой глубины вложенности.\n *\n * **Дефолтное поведение** (без `getRowMarker`): root-only нумерация —\n * корневые строки получают номер (`startIndex + rootIndex`), дочерние — пустую строку.\n *\n * @example\n * ```tsx\n * // Минимальная конфигурация\n * tableConfig={{ rowMarkers: { startIndex: 1 } }}\n *\n * // Сквозная стабильная нумерация\n * tableConfig={{ rowMarkers: { getRowMarker: ({ flatIndex }) => flatIndex + 1 } }}\n * ```\n */\nexport type RowMarkersTableConfig<\n RowType extends ObjectForExtending = ObjectForExtending,\n> = {\n /**\n * Стартовый индекс нумерации (для дефолтной логики без `getRowMarker`).\n * @default 1\n */\n startIndex?: number;\n\n /**\n * Ширина столбца с нумерацией (в px).\n * Если задан `size` — он приоритетнее.\n+ * Если ни `size`, ни `width` не заданы — ширина подстраивается\n+ * под глобальный `tableConfig.rowSize` (small=20, medium=32, big=48).\n * @default 32\n */\n width?: number;\n /**\n * Размер столбца. Приоритетнее `width`.\n * - `xs` = 20px\n * - `s` = 32px\n * - `m` = 48px\n */\n size?: 'xs' | 's' | 'm';\n /**\n * Кастомная функция нумерации. Полностью переопределяет дефолтную root-only логику.\n * Вызывается при рендере каждой ячейки столбца нумерации.\n *\n * ⚠️ Вызывается не только при полной отрисовке таблицы, но и при ховере/скролле —\n * для **одной** ячейки. Не используйте внешние переменные-счётчики —\n * используйте аргументы (`siblingPath`, `flatIndex` и др.), они всегда актуальны.\n *\n * @example\n * // Сквозная стабильная нумерация (все строки, номера не прыгают при сворачивании)\n * getRowMarker: ({ flatIndex }) => flatIndex + 1\n *\n * @example\n * // Корневые — номер, дочерние — прочерк\n * getRowMarker: ({ isSubRow, flatIndex }) => isSubRow ? '—' : flatIndex + 1\n *\n * @example\n * // Иерархическая нумерация любой глубины: 1, 1.1, 1.1.1, 1.2, 2\n * getRowMarker: ({ siblingPath }) => siblingPath.map(i => i + 1).join('.')\n */\n getRowMarker?: (args: {\n /** Данные текущей строки. */\n row: RowType;\n /** Уровень строки в дереве: `0` — корневая, `1` — дочерняя, `2` — внучка, и т.д. */\n level: number;\n /** `true`, если строка дочерняя (`level > 0`). */\n isSubRow: boolean;\n /**\n * Индекс строки в **видимых** строках.\n * **Нестабильный** — меняется при сворачивании и разворачивании веток.\n */\n rowIndex: number;\n /**\n * Стабильный 0-based индекс строки в **полном** дереве (включая скрытые/свёрнутые).\n * Не меняется при collapse/expand — подходит для сквозной нумерации.\n */\n flatIndex: number;\n /**\n * Порядковый номер среди siblings одного родителя (0-based).\n * Для корневых строк — порядковый номер среди всех корневых.\n * Для дочерних — порядковый номер среди children одного `parentKey`.\n */\n siblingIndex: number;\n /**\n * Путь siblingIndex-ов от корня до текущей строки (каждый элемент 0-based).\n *\n * Примеры:\n * - корневая строка (2-я): `[1]`\n * - дочерняя (3-й ребёнок 2-го корня): `[1, 2]`\n * - внучка (1-й ребёнок 1-го ребёнка 1-го корня): `[0, 0, 0]`\n *\n * Для иерархической нумерации: `siblingPath.map(i => i + 1).join('.')` → `\"1.1.1\"`\n *\n * Для плоской таблицы (без subRows): всегда `[siblingIndex]` (один элемент).\n */\n siblingPath: number[];\n /**\n * Ключ родительской строки (`rowKeyGetter(parent)`).\n * `null` для корневых строк. Работает для **любой** глубины вложенности.\n */\n parentKey: string | number | null;\n /** Текущий видимый `flattened` массив строк. */\n rows: readonly RowType[];\n }) => string | number;\n};\n```\n\n## FilterComponentInPopoverProps\n\nПропсы, доступные в кастомном компоненте фильтра (`component: 'custom'`).\n\n```typescript\ntype FilterComponentInPopoverProps<\n FilterStateType extends ObjectForExtending,\n ColumnConfig,\n> = {\n popoverIsOpen: boolean;\n setPopoverIsOpen: React.Dispatch<React.SetStateAction<boolean>>;\n columnConfig: ColumnConfig;\n tabIndex: number;\n headerContextState: HeaderContextValueTypeInstance<FilterStateType> &\n FiltersVariables &\n HeaderContextValueTypeInstance<ObjectForExtending>;\n /**\n * Источник открытия фильтра: из шапки таблицы или из сайдбара\n * Полезно для условной логики в customRender (например, alwaysOpened для combobox)\n */\n filterSource?: 'header' | 'sidebar';\n};\n```",
52979
53357
  "api": [
52980
53358
  {
52981
53359
  "typeName": "FilteringConfig",
52982
- "source": "type FilteringConfig<T> = {\n state: [T, React.Dispatch<React.SetStateAction<T>>];\n /**\n * @deprecated Использовать filtersInfo\n *\n * clearedValue - состояние фильтров после очистки. Используется для сравнения:\n * Например, был ли фильтр конкретной колонки изменен рассчитывается посредством сравнения текущего значения фильтра и значения фильтра в clearedValue.\n * Если они равны, то фильтр считается не измененным.\n */\n clearedValue?: T;\n /**\n * Информация о фильтрах для каждой колонки.\n * Используется для:\n * 1. Хранения меток (label) фильтров для отображения в UI\n * 2. Хранения значений по умолчанию (clearedValue) для каждого фильтра\n * 3. Определения, был ли фильтр изменен (сравнение текущего значения с clearedValue)\n */\n filtersInfo?: Record<\n keyof T,\n {\n label: string;\n clearedValue: T[keyof T];\n }\n >;\n /**\n * manualFiltering - пропс, активирующий ручную-кастомную (или на стороне бэка) фильтрацию.\n * @remarks\n * Для автоматической фильтрации (когда не используется manualFiltering в tableConfig):\n * - Для всех типов фильтров обязательно должен быть указан `valueInRow`\n * - Для component: 'select' дополнительно должен быть указан `filteringType`\n * - Для component: 'input' с кастомным фильтром (когда filter - функция)\n * функция фильтрации должна быть передана явно\n *\n * Если используется manualFiltering, эти параметры не обязательны,\n * так как вся логика фильтрации реализуется извне.\n */\n manualFiltering?: boolean;\n /**\n * Конфигурация для отображения фильтров в правом сайдбаре.\n *\n * Позволяет:\n * 1. Добавлять глобальные фильтры (не привязанные к конкретной колонке)\n * 2. Управлять порядком отображения фильтров\n * 3. Переопределять рендер и заголовки колоночных фильтров\n *\n * Логика работы:\n * - По умолчанию в сайдбаре отображаются все колоночные фильтры (из columnConfig)\n * - Ключом фильтра считается `key` колонки, если его нет, то пытаемся взять `keyInFilterState` (если указан), иначе это не будет работать\n * - Заголовком фильтра по умолчанию является `name` колонки или ключ фильтра (name || key)\n * - Глобальные фильтры добавляются через `items` с уникальными ключами\n *\n * Особенности:\n * 1. Порядок отображения:\n * - Сначала фильтры из `order` (в указанной последовательности)\n * - Затем остальные колоночные фильтры (в порядке columnConfig)\n * - В конце - глобальные фильтры (в алфавитном порядке ключей)\n *\n * 2. Переопределение колоночных фильтров:\n * - Чтобы изменить заголовок: укажите ключ колонки в `items` с новым `label`\n * - Чтобы заменить рендер: укажите ключ колонки с `customRenderFn`\n * - Оригинальный фильтр из колонки будет проигнорирован\n *\n * 3. Глобальные фильтры:\n * - Ключ не должен совпадать с ключами колонок\n * - Обязательно указать `label` и `customRenderFn`\n * - Отображаются после всех колоночных фильтров, если не переопределены в order\n *\n * @example\n * // Добавление глобального фильтра и изменение порядка\n * sidebarConfig: {\n * order: ['status', 'tasks', 'type'], // Сначала статус, затем глобальный поиск\n * items: {\n * tasks: { // Уникальный ключ\n * label: 'Поиск по всем полям',\n * customRenderFn: () => <TaskComponent />\n * },\n * status: { // Переопределение колоночного фильтра\n * label: 'Статус заявки', // Новый заголовок\n * customRenderFn: () => <CustomStatusFilter /> // Кастомный рендер\n * }\n * type: { // Переопределение только Label колоночного фильтра\n * label: 'Тип', // Новый заголовок\n * }\n * }\n * }\n */\n sidebarConfig?: {\n /**\n * Определяет порядок отображения фильтров.\n * - Указываются ключи фильтров (колоночных или глобальных)\n * - Не указанные в order фильтры отображаются после\n * - Если order пуст, сохраняется порядок: глобальные фильтры + columnConfig фильтры в конце\n */\n order?: string[];\n /**\n * Конфигурация фильтров для сайдбара.\n * Ключом может быть:\n * - Ключ колонки (для переопределения колоночного фильтра)\n * - Уникальный ключ (для добавления глобального фильтра)\n */\n items: Partial<\n Record<\n keyof T,\n {\n /** Заголовок фильтра (обязателен для глобальных фильтров), можно использовать для переопределения для локальных фильтров */\n label: string;\n /**\n * Функция рендера компонента фильтра.\n * Для колоночных фильтров переопределяет оригинальный рендер.\n * Для глобальных фильтров обязательна.\n */\n customRenderFn?: (\n filters: T,\n setFilters: React.Dispatch<React.SetStateAction<T>>,\n ) => React.ReactNode;\n }\n >\n >;\n };\n /**\n * Callback для кастомизации стилей чипсов (фильтров) в списке\n *\n * @param {ItemOrGroup} itemOrGroup - Текущий элемент или группа фильтров\n * @param {Item | undefined} item - Конкретный элемент фильтра (если есть)\n * @returns {CSSObject} Объект стилей, который будет применен к чипсу\n *\n * @description\n * Позволяет динамически задавать стили для каждого чипса в зависимости от его типа и содержимого.\n * Вызывается для каждого отображаемого чипса (как для отдельных элементов, так и для элементов внутри групп).\n *\n * @example\n * // Пример 1: Стилизация чипсов по типу\n * chipStyle: (itemOrGroup, item) => {\n * if (isGroup(itemOrGroup)) {\n * return { backgroundColor: '#f0f0f0' };\n * }\n * return { backgroundColor: '#e0e0e0' };\n * }\n *\n * @example\n * // Пример 2: Стилизация по значению фильтра\n * chipStyle: (itemOrGroup, item) => {\n * if (item?.label === 'Высокий приоритет') {\n * return {\n * backgroundColor: '#ffebee',\n * color: '#d32f2f'\n * };\n * }\n * return {};\n * }\n *\n * @example\n * // Пример 3: Разные стили для элементов в группе и одиночных\n * chipStyle: (itemOrGroup, item) => {\n * if (item) {\n * // Стиль для элемента внутри группы\n * return { maxWidth: 180 };\n * }\n * // Стиль для одиночного чипа\n * return { maxWidth: 150 };\n * }\n */\n chipStyle?: (itemOrGroup: ItemOrGroup, item: Item | undefined) => CSSObject;\n /**\n * Пользовательский форматтер заголовка группы чипсов.\n *\n * Используется в блоке активных фильтров для подмены текста заголовка\n * группы (например, “Статус”, “Тип”, “Автор”). Полезно, когда нужно\n * динамически менять подпись (добавить счётчик, i18n и т.п.).\n *\n * @param {ItemOrGroup} itemOrGroup Объект группы (тип Group). Вызов происходит только для групп,\n * поэтому безопасно кастовать к Group.\n * @returns {string} Текст заголовка группы чипсов.\n *\n * @default Возвращается `group.groupLabel`.\n *\n * @remarks\n * - Функция должна быть чистой и быстрой (без сетевых запросов и побочных эффектов).\n * - Возвращайте ТОЛЬКО строку — чипы отображают текстовое значение.\n * - Для длинных строк применяется усечение (overflow с многоточием) на уровне компонента.\n *\n * @example\n * // Добавить двоеточие и количество выбранных элементов\n * renderGroupLabel: (group) => `${group.groupLabel}: ${group.items.length}`\n *\n * @example\n * // Локализация заголовка группы\n * const i18n = { status: 'Статус', type: 'Тип' };\n * renderGroupLabel: (group) => i18n[group.groupId] ?? group.groupLabel\n */\n renderGroupLabel?: (group: Group) => string;\n\n /**\n * Пользовательский форматтер текста чипса (элемента внутри группы или одиночного фильтра).\n *\n * Позволяет управлять тем, что именно отображается внутри каждого чипса. Особенно полезен\n * при серверной пагинации/ленивой загрузке, когда в состоянии фильтра хранится только value,\n * а label необходимо подставить из локального кэша.\n *\n * @param {Group | null } group Группа, внутри которой рендерится чип (или null).\n * @param {Item} item Сам элемент чипса. В группах передаётся конкретный `Item`,\n * для одиночного чипа может быть `undefined`.\n * @returns {string} Текст, который будет показан в чипсе.\n *\n * @default Используется `item?.label.toString()` (или строковое представление value).\n *\n * @remarks\n * - Функция должна быть чистой и быстрой;\n * - Возвращайте ТОЛЬКО строку.\n *\n * @example\n * // 1) Отображение label из кэша при серверной пагинации\n * const labelsCacheRef = useRef(new Map<string, string>());\n * renderChipLabel: (group, item) => {\n * if (item?.id != null) {\n * const key = String(item.id);\n * const fromCache = labelsCacheRef.current.get(key);\n * if (fromCache) return fromCache; // красивый label, если уже загрузили\n * return String(item.label ?? key); // фоллбэк: временно показываем value/label из item\n * }\n * return ''; // безопасный фоллбэк для одиночных случаев\n * }\n *\n * @example\n * // 2) Нормализация отображения числовых значений\n * renderChipLabel: (_group, item) => {\n * const v = Number(item?.label);\n * return Number.isFinite(v) ? v.toLocaleString('ru-RU') : String(item?.label ?? '');\n * }\n *\n * @example\n * // 3) Префикс по типу группы\n * renderChipLabel: (group, item) => {\n * const prefix = group.groupId === 'status' ? '' : '#';\n * return `${prefix}${item?.label ?? item?.id ?? ''}`;\n * }\n */\n renderChipLabel?: (group: Group | null, item: Item) => string;\n};\n\nexport type DefaultSidebarTabIds = 'columns' | 'tableSettings' | 'filtering';\n\n/**\n * Конфигурация sidebar\n */\nexport type SidebarConfig = {\n /**\n * Включен ли sidebar. Отвечает только за UI. Не влияет на перерасчёт фичей.\n * @default true\n */\n enabled?: boolean;\n /**\n * Открыт ли sidebar при первом рендере (uncontrolled-режим).\n * Игнорируется, если передан openState.\n * @default false\n */\n defaultOpen?: boolean;\n /**\n * Внешний контроль открытия/закрытия sidebar.\n * Если передан — источник истины, defaultOpen игнорируется.\n */\n openState?: [boolean, React.Dispatch<React.SetStateAction<boolean>>];\n /**\n * id вкладки, выбранной по умолчанию (актуально при открытом сайдбаре).\n * Если id не найден или у вкладки showInSidebar=false — используется первая доступная.\n */\n defaultActiveTabId?: string;\n /**\n * Внешний контроль активной вкладки (controlled-режим).\n * Если передан — источник истины, defaultActiveTabId игнорируется.\n */\n activeTabState?: [\n string | null,\n React.Dispatch<React.SetStateAction<string | null>>,\n ];\n /**\n * Колбэк смены активной вкладки. Вызывается и в uncontrolled-режиме.\n * При закрытии сайдбара приходит null.\n */\n onActiveTabChange?: (tabId: string | null, tab?: SidebarTab) => void;\n /**\n * Кастомные табы\n */\n customTabs?: Array<\n Omit<SidebarTab, 'id'> & {\n id: Exclude<string, DefaultSidebarTabIds>;\n }\n >;\n /**\n * Порядок отображения кастомных вкладок\n */\n customTabsOrder?: Array<Exclude<string, DefaultSidebarTabIds>>;\n defaultTabs?: Array<\n | {\n id: 'filtering' | 'columns';\n /** название таба в рамках горизонтального табов внутри таба настройки */\n label?: string;\n /** название таба в рамках вертикальных табов сайдбара (если данный таб окажется единственным табом в настройках) */\n title?: string;\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n domMetadata?: DomMetadata;\n /**\n * Кастомный элемент справа от title в шапке сайдбара\n */\n titleRightSlot?: React.ReactNode;\n /** @default true */\n showInSidebar?: boolean;\n /** тултип иконки шестеренки (для табов с id = filtering и columns - недоступен. Настраивается через таб с id='tableSettings') */\n iconTooltipText?: undefined;\n }\n | {\n id: 'tableSettings';\n /** название таба в рамках горизонтального табов внутри таба настройки */\n label?: string;\n /** название таба в рамках вертикальных табов сайдбара */\n title?: string;\n\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n domMetadata?: DomMetadata;\n /**\n * Кастомный слот для вкладки tableSettings (рендерится после общих настроек)\n * Только дл id: 'tableSettings'\n */\n customGeneralSettingsSlot?: React.ReactNode;\n /**\n * Кастомный элемент справа от title в шапке сайдбара\n */\n titleRightSlot?: React.ReactNode;\n /** @default true */\n showInSidebar?: boolean;\n /** тултип иконки шестеренки @default 'Настройки' */\n iconTooltipText?: string;\n }\n >;\n};\n\nexport function activeViewIs<T extends 'cards' | 'rows'>(\n checkType: T,\n viewState: 'cards' | 'rows',\n view: View,\n): view is ViewMods[T] {\n return checkType === viewState;\n}\n\n/** Размер controlBlock: 'm' и 's' — одинаковые стили, 'xs' — уменьшенный */\nexport type ControlBlockSize = 'm' | 's' | 'xs';\n\nexport type ControlBlockConfig = {\n /**\n * show - наличие controlBlock-а\n * @default true\n */\n show?: boolean;\n /**\n * Размер controlBlock и его элементов (кнопки, иконки, поиск, отступы).\n * 'm' и 's' — стандартные стили, 'xs' — компактный режим.\n * Не влияет на customFeatures и кастомные слоты — они контролируются разработчиком.\n * @default 'm'\n */\n size?: ControlBlockSize;\n /**\n * @deprecated Используйте кастомные кнопки через rightSideInner или customFeatures.\n * leftSideInner - пропс для добавления кнопок в левую часть контролблока.\n * Продолжает работать для обратной совместимости.\n */\n leftSideInner?: ControlBlockButtonProps[];\n /**\n * rightSideInner - пропс для добавления кнопок в правую часть контролблока\n */\n rightSideInner?: ControlBlockButtonProps[];\n /**\n * customFeatures - пропс для добавления кастомных фичей (кнопки-иконки)\n */\n customFeatures?: FeatureItem[];\n /**\n * pinningMenu - нативная фича закрепления столбцов (SplitIconButton с\n * дропдауном) в правой зоне иконок. Появляется, когда активировано\n * закрепление колонок (columnsControl.pinning). Продукт может донастроить\n * и дополнить пункты меню (см. PinningMenuConfig).\n */\n pinningMenu?: PinningMenuConfig;\n /**\n * Пропсы для компонента dropdown в котором будут скрыты левые фичи при адаптивной компрессии\n */\n leftSideDropdownProps?: TableDropdownConfigProps;\n /**\n * Пропсы для компонента dropdown в котором будут скрыты правые фичи при адаптивной компрессии\n */\n rightSideDropdownProps?: TableDropdownConfigProps;\n /**\n * Активна ли фича компрессии (сжатие ToolsMenu при адаптиве)\n * @default true\n */\n enableAdaptiveCompress?: boolean;\n /**\n * Панель массовых действий\n */\n massActionPanel?: {\n /**\n * Кнопки панели. Размеры кнопок/дропдаунов панель подбирает сама (по `size` панели и компактности) —\n * передавать `size` кнопкам не нужно. Если `size` на кнопке всё же задан — он используется как есть.\n */\n buttons: MassActionButtonProps[];\n /**\n * Пропсы для Dropdown, в который сжались кнопки\n */\n collapsedDropdownProps?: TableDropdownConfigProps;\n /**\n * Отступ панели снизу от контейнера (px)\n * @default 24\n */\n bottom?: number;\n /**\n * Управление отображением панели массовых действий.\n * - `undefined` (по умолчанию) — стандартное поведение (показывается при selecting + выбранных строках)\n * - `false` — панель не рендерится, разработчик управляет действиями самостоятельно\n * - `true` — панель показывается всегда, даже без активного selecting и выбранных строк\n */\n show?: boolean;\n /**\n * Размерная сетка панели внутри таблицы: `m`/`s` — обычный размер, `xs` — уменьшенный (кнопки `xxs`, «ещё» `xs`, счётчик Body XS).\n * Viewport-логика (1280) в таблице не используется.\n * @default 's'\n */\n size?: MassActionsSize;\n };\n};\n\n/** Пропсы кнопки редактирования. onClick исключён — используйте onSave/onCancel/onEnableEditing. */\nexport type EditingButtonProps = Omit<\n Partial<ControlBlockButtonProps>,\n | 'onClick'\n | 'size'\n | 'dropdown'\n | 'isTargetAction'\n | 'skipRightDivider'\n | 'tooltipText'\n>;\n\nexport type EditingConfig<\n RowType extends ObjectForExtending,\n RowIdType,\n SummaryRowType,\n> = {\n /**\n * Функция обработки изменений в редактируемой строке\n */\n onRowsChange: Maybe<\n (rows: RowType[], data: RowsChangeData<RowType, SummaryRowType>) => void\n >;\n /**\n * свойство, необходимое для корректного изменения дочерних строк.\n * Данное свойство обязательно, если ваши дочерние строки установлены не под ключом \"subRows\" внутри строки.\n *\n * Как дочерние строки можно указывать свойство, которые вложено в другое свойство.\n * В таком случае \".\" будет знаком для обозначения сл. уровня вложенности.\n *\n * @example \"child\" или \"uvh367.children\"\n */\n subRowsKey?: string;\n /**\n * Глубокое копирование строк перед применением правки в режиме редактирования.\n *\n * Включите, если строки, передаваемые в таблицу, иммутабельны/заморожены\n * (напр. стейт под управлением Redux Toolkit или Immer — они вызывают\n * Object.freeze в dev). При редактировании дочерней строки таблица записывает\n * изменение ВНУТРЬ объекта родителя; на замороженном объекте это падает с\n * `TypeError: Cannot assign to read only property`.\n *\n * Когда флаг включён, таблица сама делает structuredClone редактируемой строки\n * перед записью — ваш иммутабельный стейт не мутируется, и редактирование\n * дочерних строк работает без действий с вашей стороны.\n *\n * ⚠️ Данные строки должны быть сериализуемыми. Где доступен structuredClone —\n * Date/Map/Set и вложенные структуры копируются корректно; на старых средах\n * без structuredClone используется JSON-фоллбэк (теряет Date/Map/Set, undefined\n * и функции). Не включайте без необходимости — глубокое копирование добавляет\n * накладные расходы.\n *\n * @default false\n */\n deepCloneRows?: boolean;\n /**\n * Функция определения уникального id строки\n * @param row\n * @returns\n */\n rowKeyGetter: (row: RowType) => RowIdType;\n /**\n * Функция определения возможности редактирования строки\n * @param row\n * @returns\n */\n rowEditable?: (row: RowType) => boolean;\n /**\n * defaultEnabled - пропс, отвечающий за то, будет ли активен режим редактирования или нет. По умолчанию - не активно.\n * @default false\n */\n defaultEnabled?: boolean;\n /**\n * enabled - необходим для управления режимом редактирования снаружи компонента Таблицы.\n * По умолчанию, управление происходит в компоненте.\n * Приоритетнее, чем defaultEnabled.\n *\n * @type boolean - если НЕ нужно переключение в самой таблице\n * @type [boolean, React.Dispatch<React.SetStateAction<boolean>>] - если нужно переключение в самой таблице\n *\n */\n enabled?: boolean | [boolean, React.Dispatch<React.SetStateAction<boolean>>];\n /**\n * Cостояние скрытия/раскрытия кнопки включения/выключения фичи\n * @default true\n */\n showButtons?: boolean;\n /**\n * Функция, вызывающаяся при включении фичи.\n * @param enableEditorMode - функция включающая режим редактирования\n */\n onEnableEditing?: (enableEditorMode: () => void) => void;\n /**\n * Функция, вызывающаяся при сохранении отредактированного.\n * @param disableEditorMode - функция выключающая режим редактирования\n */\n onSave?: (disableEditorMode: () => void) => void;\n /**\n * Функция, вызывающаяся при отмене отредактированного.\n * @param disableEditorMode - функция выключающая режим редактирования\n */\n onCancel?: (disableEditorMode: () => void) => void;\n /** Пропсы кнопок в controlBlock. */\n buttons?: {\n save?: EditingButtonProps;\n cancel?: EditingButtonProps;\n edit?: EditingButtonProps;\n };\n /**\n * Кастомный слот, отображаемый левее кнопок «Отменить» / «Сохранить».\n * Виден только когда режим редактирования активен (editMode = true).\n * Зона ответственности разработчика — размерная сетка controlBlock не влияет на этот слот.\n */\n editModeLeftSlot?: React.ReactNode;\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n domMetadata?: {\n enableButton?: DomMetadata;\n saveButton?: DomMetadata;\n cancelButton?: DomMetadata;\n };\n};\n\nexport type SummaryRowsConfig = {\n showDefault: boolean;\n showInControl: boolean;\n} & {\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n domMetadata?: DomMetadata;\n};\n\n/**\n * Конфиг тултипа при hover по canvas-элементам.\n * Для активации фичи необходимо заполнить данный конфиг,\n * а также добавить нужные изменения в Canvas-элементах или в конфиге колонки.\n */\nexport type TableConfigTooltip = {\n /**\n * Включить/выключить колоночные и кастомные тултипы (cellTooltip, headerCellTooltip).\n * Внутренние тултипы (drag-иконка в шапке и другие по nodeId) работают всегда.\n * @default false\n */\n enabled?: boolean;\n /** Глобальная задержка перед показом тултипа (мс). Per-node переопределяет. @default 500 */\n mouseEnterDelay?: number;\n /** Глобальная задержка перед скрытием тултипа (мс). Per-node переопределяет. @default 0 */\n mouseLeaveDelay?: number;\n};\n\nexport type InfinityScrollConfig<RowType extends ObjectForExtending> = {\n /** Триггер достижения скроллом зоны подгрузки данных. */\n onTrigger: (rows: RowType[]) => Promise<void> | void;\n /** Состояние загрузки (скелетоны) новых строк. */\n isLoading: boolean;\n /**\n * Флаг, когда все данные загружены — false.\n * @default true\n */\n hasMore?: boolean;\n /**\n * Для mode='region': за сколько строк до конца триггерить загрузку.\n * @default 5\n */\n rowThreshold?: number;\n};\n\nexport type { TableCanvasEmptyStateConfig, TableCanvasErrorStateConfig };\n\n/**\n * Настройка выделения ячеек/колонок/строк в TableCanvas — единый объект.\n * Это отдельная ось взаимодействия — не зависит от `highlightActiveType`.\n */\nexport type CellsSelectionConfig = {\n /**\n * Режим фактического выделения ячеек (нативный glide selection). По нему\n * работают copy/paste, рамка, fill-handle и затемнение шапки/нумерации.\n * @default \"range-cell\"\n */\n mode?: CellsSelectionMode;\n /**\n * Выделение колонок по клику на шапку. Ctrl/Cmd — добавить/убрать колонку,\n * Shift — диапазон колонок. Клик по иконкам сортировки/фильтрации в шапке\n * выделение НЕ вызывает. Поддерживает copy/paste по выделенным колонкам.\n * @default true\n */\n enableColumnSelection?: boolean;\n /**\n * Выделение строк по клику/драгу на колонке нумерации (`rowMarkers`).\n * Ctrl/Cmd — несмежный выбор отдельных строк, драг — смежный диапазон.\n * Поддерживает copy/paste по выделенным строкам. Требует включённой колонки\n * нумерации (`rowMarkers`). При `false` клик по нумерации ничего не выделяет.\n * @default true\n */\n enableRowSelection?: boolean;\n /**\n * Выделение всей таблицы кликом по «нулевой» ячейке — шапке колонки нумерации\n * (левый верхний угол). Выделяет все строки данных по всем колонкам одним\n * диапазоном; поддерживает copy/paste. Требует включённой колонки нумерации\n * (`rowMarkers`) и активного `mode` (≠ `disabled`).\n * @default true\n */\n enableSelectAll?: boolean;\n /**\n * Внешний (controlled) контроль НАТИВНОГО выделения (ячейки/диапазон/смежные\n * строки и колонки). `state` — кортеж `[value, setter]` как у `selecting.state`.\n * Сброс: `setter({ current: undefined, rows: empty, columns: empty })`.\n * Несмежный Ctrl-выбор колонок/строк (own-state) сюда не входит — он внутренний.\n */\n state?: [GridSelection, React.Dispatch<React.SetStateAction<GridSelection>>];\n};\n\n/** Один объединённый блок: какие строки и колонки слить. */\nexport type MergedCellsRegion = {\n rowKeys: Array<string | number>;\n colKeys: string[];\n /** Выравнивание контента этого блока. Важнее колоночного и общего. */\n mergedCellsAlign?: MergedCellsAlign;\n};\n\nexport type TableConfig<\n RowType extends ObjectForExtending,\n SummaryRowType,\n RowIdType extends string | number,\n FilterStateType extends ObjectForExtending,\n // SubRowType\n> = {\n /**\n * Группировка колонок (многоуровневая шапка через `columnConfig.children`):\n * объединение пустых ячеек шапки (`squashEmptyCells`, по умолчанию включено) и\n * дефолт выравнивания в объединённых ячейках (`squashedHeaderAlign`).\n */\n columnsGrouping?: ColumnsGroupingConfig;\n /**\n * Подсветка активной сущности в canvas-таблице.\n * @deprecated Значения `'cell'`/`'range-cell'` устарели — используйте\n * `cellsSelection.mode`. Актуальны `'row'` (подсветка строки) и `'disabled'`.\n */\n highlightActiveType?: HighlightActiveType;\n /**\n * Единый конфиг выделения ячеек: режим (`mode`), оси\n * (`enableColumnSelection`/`enableRowSelection`/`enableSelectAll`) и controlled\n * (`state`). См. {@link CellsSelectionConfig}.\n */\n cellsSelection?: CellsSelectionConfig;\n /**\n * Подсвеченная строка (`highlightActiveType='row'`).\n * `state` (опционально) — controlled-кортеж `[value, setter]`: задан — значением\n * владеешь снаружи (сброс `setter(undefined)`); не задан — таблица крутит\n * подсветку внутренним стейтом, а `onChange` всё равно срабатывает (подписка\n * без владения значением).\n */\n highlightActiveRow?: {\n state?: [\n number | undefined,\n React.Dispatch<React.SetStateAction<number | undefined>>,\n ];\n /**\n * Колбэк смены подсвеченной строки: отдаёт её флэт-индекс и сам объект\n * строки (`rows[index]`). Позволяет открывать данные подсвеченной строки\n * (например, в SplitView) без `onCellClicked`.\n */\n onChange?: (params: {\n index: number | undefined;\n row: RowType | undefined;\n }) => void;\n };\n /**\n * Эффекты при наведении (hover)\n * `row` — подсветка строки под курсором.\n * Независимая визуальная ось: селектинг (`cellsSelection`) и `highlightActiveType='row'`\n * рисуются ПОВЕРХ hover-подсветки и визуально перекрывают её (hover\n * «остаётся под ними» и снова виден после сброса выделения).\n *\n * `{ row: true }` — включить с цветами из темы;\n * `{ row: { color: '#F7F9FB' } }` — переопределить цвет data-ячеек.\n * @default undefined (выключено)\n */\n hoverEffects?: HoverEffectsConfig;\n /**\n * Включает компенсацию тонких canvas-линий при browser zoom ниже 100%, когда devicePixelRatio меньше 1.\n * Влияет только на grid/header/sticky hairline borders.\n * @default false\n */\n enableLowDprHairline?: boolean;\n /**\n * rowSize - размеры строк таблицы\n */\n rowSize?: Prettify<RowSize>;\n /**\n * rowHeight - размер высоты строк таблицы\n */\n rowHeight?: Maybe<number | RowHeightFunc<RowType>>;\n /**\n * sorting - активация сортировки. Условие активации - это наличие данного свойства. Нужно также сконфигурировать колонки.\n *\n * Пример:\n *\n * tableConfig={sorting: {sortingState}}\n *\n * columnConfig=[{sortingType: 'numberSort'}]\n */\n sorting?: {\n state: [\n readonly SortColumn[],\n React.Dispatch<React.SetStateAction<readonly SortColumn[]>>,\n ];\n /**\n * manualSorting - пропс, активирующий ручную-кастомную (или на стороне бэкенда) сортировку\n */\n manualSorting?: boolean;\n };\n /** @deprecated Свойство view не используется и будет удалено в следующей мажорной версии. */\n view?: View;\n /**\n * filtering - активация фильтрации. Условие активации - это наличие данного свойства. Нужно также сконфигурировать колонки.\n *\n * Пример:\n *\n * tableConfig={filtering: {stateAndSetter, ...}}\n *\n * columnConfig=[{filtering: {...}}]\n */\n filtering?: FilteringConfig<FilterStateType>;\n /**\n * Сворачивание / разворачивание таблицы\n */\n collapsing?: TableCollapseConfig;\n /**\n * selecting - активация выбора строк. Условие активации - это наличие данного свойства.\n * Есть поддержка выбора строк с многоуровневой вложенностью.\n *\n * Пример:\n *\n *"
53360
+ "source": "type FilteringConfig<T> = {\n state: [T, React.Dispatch<React.SetStateAction<T>>];\n /**\n * @deprecated Использовать filtersInfo\n *\n * clearedValue - состояние фильтров после очистки. Используется для сравнения:\n * Например, был ли фильтр конкретной колонки изменен рассчитывается посредством сравнения текущего значения фильтра и значения фильтра в clearedValue.\n * Если они равны, то фильтр считается не измененным.\n */\n clearedValue?: T;\n /**\n * Информация о фильтрах для каждой колонки.\n * Используется для:\n * 1. Хранения меток (label) фильтров для отображения в UI\n * 2. Хранения значений по умолчанию (clearedValue) для каждого фильтра\n * 3. Определения, был ли фильтр изменен (сравнение текущего значения с clearedValue)\n */\n filtersInfo?: Record<\n keyof T,\n {\n label: string;\n clearedValue: T[keyof T];\n }\n >;\n /**\n * manualFiltering - пропс, активирующий ручную-кастомную (или на стороне бэка) фильтрацию.\n * @remarks\n * Для автоматической фильтрации (когда не используется manualFiltering в tableConfig):\n * - Для всех типов фильтров обязательно должен быть указан `valueInRow`\n * - Для component: 'select' дополнительно должен быть указан `filteringType`\n * - Для component: 'input' с кастомным фильтром (когда filter - функция)\n * функция фильтрации должна быть передана явно\n *\n * Если используется manualFiltering, эти параметры не обязательны,\n * так как вся логика фильтрации реализуется извне.\n */\n manualFiltering?: boolean;\n /**\n * Конфигурация для отображения фильтров в правом сайдбаре.\n *\n * Позволяет:\n * 1. Добавлять глобальные фильтры (не привязанные к конкретной колонке)\n * 2. Управлять порядком отображения фильтров\n * 3. Переопределять рендер и заголовки колоночных фильтров\n *\n * Логика работы:\n * - По умолчанию в сайдбаре отображаются все колоночные фильтры (из columnConfig)\n * - Ключом фильтра считается `key` колонки, если его нет, то пытаемся взять `keyInFilterState` (если указан), иначе это не будет работать\n * - Заголовком фильтра по умолчанию является `name` колонки или ключ фильтра (name || key)\n * - Глобальные фильтры добавляются через `items` с уникальными ключами\n *\n * Особенности:\n * 1. Порядок отображения:\n * - Сначала фильтры из `order` (в указанной последовательности)\n * - Затем остальные колоночные фильтры (в порядке columnConfig)\n * - В конце - глобальные фильтры (в алфавитном порядке ключей)\n *\n * 2. Переопределение колоночных фильтров:\n * - Чтобы изменить заголовок: укажите ключ колонки в `items` с новым `label`\n * - Чтобы заменить рендер: укажите ключ колонки с `customRenderFn`\n * - Оригинальный фильтр из колонки будет проигнорирован\n *\n * 3. Глобальные фильтры:\n * - Ключ не должен совпадать с ключами колонок\n * - Обязательно указать `label` и `customRenderFn`\n * - Отображаются после всех колоночных фильтров, если не переопределены в order\n *\n * @example\n * // Добавление глобального фильтра и изменение порядка\n * sidebarConfig: {\n * order: ['status', 'tasks', 'type'], // Сначала статус, затем глобальный поиск\n * items: {\n * tasks: { // Уникальный ключ\n * label: 'Поиск по всем полям',\n * customRenderFn: () => <TaskComponent />\n * },\n * status: { // Переопределение колоночного фильтра\n * label: 'Статус заявки', // Новый заголовок\n * customRenderFn: () => <CustomStatusFilter /> // Кастомный рендер\n * }\n * type: { // Переопределение только Label колоночного фильтра\n * label: 'Тип', // Новый заголовок\n * }\n * }\n * }\n */\n sidebarConfig?: {\n /**\n * Определяет порядок отображения фильтров.\n * - Указываются ключи фильтров (колоночных или глобальных)\n * - Не указанные в order фильтры отображаются после\n * - Если order пуст, сохраняется порядок: глобальные фильтры + columnConfig фильтры в конце\n */\n order?: string[];\n /**\n * Конфигурация фильтров для сайдбара.\n * Ключом может быть:\n * - Ключ колонки (для переопределения колоночного фильтра)\n * - Уникальный ключ (для добавления глобального фильтра)\n */\n items: Partial<\n Record<\n keyof T,\n {\n /** Заголовок фильтра (обязателен для глобальных фильтров), можно использовать для переопределения для локальных фильтров */\n label: string;\n /**\n * Функция рендера компонента фильтра.\n * Для колоночных фильтров переопределяет оригинальный рендер.\n * Для глобальных фильтров обязательна.\n */\n customRenderFn?: (\n filters: T,\n setFilters: React.Dispatch<React.SetStateAction<T>>,\n ) => React.ReactNode;\n }\n >\n >;\n };\n /**\n * Callback для кастомизации стилей чипсов (фильтров) в списке\n *\n * @param {ItemOrGroup} itemOrGroup - Текущий элемент или группа фильтров\n * @param {Item | undefined} item - Конкретный элемент фильтра (если есть)\n * @returns {CSSObject} Объект стилей, который будет применен к чипсу\n *\n * @description\n * Позволяет динамически задавать стили для каждого чипса в зависимости от его типа и содержимого.\n * Вызывается для каждого отображаемого чипса (как для отдельных элементов, так и для элементов внутри групп).\n *\n * @example\n * // Пример 1: Стилизация чипсов по типу\n * chipStyle: (itemOrGroup, item) => {\n * if (isGroup(itemOrGroup)) {\n * return { backgroundColor: '#f0f0f0' };\n * }\n * return { backgroundColor: '#e0e0e0' };\n * }\n *\n * @example\n * // Пример 2: Стилизация по значению фильтра\n * chipStyle: (itemOrGroup, item) => {\n * if (item?.label === 'Высокий приоритет') {\n * return {\n * backgroundColor: '#ffebee',\n * color: '#d32f2f'\n * };\n * }\n * return {};\n * }\n *\n * @example\n * // Пример 3: Разные стили для элементов в группе и одиночных\n * chipStyle: (itemOrGroup, item) => {\n * if (item) {\n * // Стиль для элемента внутри группы\n * return { maxWidth: 180 };\n * }\n * // Стиль для одиночного чипа\n * return { maxWidth: 150 };\n * }\n */\n chipStyle?: (itemOrGroup: ItemOrGroup, item: Item | undefined) => CSSObject;\n /**\n * Пользовательский форматтер заголовка группы чипсов.\n *\n * Используется в блоке активных фильтров для подмены текста заголовка\n * группы (например, “Статус”, “Тип”, “Автор”). Полезно, когда нужно\n * динамически менять подпись (добавить счётчик, i18n и т.п.).\n *\n * @param {ItemOrGroup} itemOrGroup Объект группы (тип Group). Вызов происходит только для групп,\n * поэтому безопасно кастовать к Group.\n * @returns {string} Текст заголовка группы чипсов.\n *\n * @default Возвращается `group.groupLabel`.\n *\n * @remarks\n * - Функция должна быть чистой и быстрой (без сетевых запросов и побочных эффектов).\n * - Возвращайте ТОЛЬКО строку — чипы отображают текстовое значение.\n * - Для длинных строк применяется усечение (overflow с многоточием) на уровне компонента.\n *\n * @example\n * // Добавить двоеточие и количество выбранных элементов\n * renderGroupLabel: (group) => `${group.groupLabel}: ${group.items.length}`\n *\n * @example\n * // Локализация заголовка группы\n * const i18n = { status: 'Статус', type: 'Тип' };\n * renderGroupLabel: (group) => i18n[group.groupId] ?? group.groupLabel\n */\n renderGroupLabel?: (group: Group) => string;\n\n /**\n * Пользовательский форматтер текста чипса (элемента внутри группы или одиночного фильтра).\n *\n * Позволяет управлять тем, что именно отображается внутри каждого чипса. Особенно полезен\n * при серверной пагинации/ленивой загрузке, когда в состоянии фильтра хранится только value,\n * а label необходимо подставить из локального кэша.\n *\n * @param {Group | null } group Группа, внутри которой рендерится чип (или null).\n * @param {Item} item Сам элемент чипса. В группах передаётся конкретный `Item`,\n * для одиночного чипа может быть `undefined`.\n * @returns {string} Текст, который будет показан в чипсе.\n *\n * @default Используется `item?.label.toString()` (или строковое представление value).\n *\n * @remarks\n * - Функция должна быть чистой и быстрой;\n * - Возвращайте ТОЛЬКО строку.\n *\n * @example\n * // 1) Отображение label из кэша при серверной пагинации\n * const labelsCacheRef = useRef(new Map<string, string>());\n * renderChipLabel: (group, item) => {\n * if (item?.id != null) {\n * const key = String(item.id);\n * const fromCache = labelsCacheRef.current.get(key);\n * if (fromCache) return fromCache; // красивый label, если уже загрузили\n * return String(item.label ?? key); // фоллбэк: временно показываем value/label из item\n * }\n * return ''; // безопасный фоллбэк для одиночных случаев\n * }\n *\n * @example\n * // 2) Нормализация отображения числовых значений\n * renderChipLabel: (_group, item) => {\n * const v = Number(item?.label);\n * return Number.isFinite(v) ? v.toLocaleString('ru-RU') : String(item?.label ?? '');\n * }\n *\n * @example\n * // 3) Префикс по типу группы\n * renderChipLabel: (group, item) => {\n * const prefix = group.groupId === 'status' ? '' : '#';\n * return `${prefix}${item?.label ?? item?.id ?? ''}`;\n * }\n */\n renderChipLabel?: (group: Group | null, item: Item) => string;\n};\n\nexport type DefaultSidebarTabIds = 'columns' | 'tableSettings' | 'filtering';\n\n/**\n * Конфигурация sidebar\n */\nexport type SidebarConfig = {\n /**\n * Включен ли sidebar. Отвечает только за UI. Не влияет на перерасчёт фичей.\n * @default true\n */\n enabled?: boolean;\n /**\n * Открыт ли sidebar при первом рендере (uncontrolled-режим).\n * Игнорируется, если передан openState.\n * @default false\n */\n defaultOpen?: boolean;\n /**\n * Внешний контроль открытия/закрытия sidebar.\n * Если передан — источник истины, defaultOpen игнорируется.\n */\n openState?: [boolean, React.Dispatch<React.SetStateAction<boolean>>];\n /**\n * id вкладки, выбранной по умолчанию (актуально при открытом сайдбаре).\n * Если id не найден или у вкладки showInSidebar=false — используется первая доступная.\n */\n defaultActiveTabId?: string;\n /**\n * Внешний контроль активной вкладки (controlled-режим).\n * Если передан — источник истины, defaultActiveTabId игнорируется.\n */\n activeTabState?: [\n string | null,\n React.Dispatch<React.SetStateAction<string | null>>,\n ];\n /**\n * Колбэк смены активной вкладки. Вызывается и в uncontrolled-режиме.\n * При закрытии сайдбара приходит null.\n */\n onActiveTabChange?: (tabId: string | null, tab?: SidebarTab) => void;\n /**\n * Кастомные табы\n */\n customTabs?: Array<\n Omit<SidebarTab, 'id'> & {\n id: Exclude<string, DefaultSidebarTabIds>;\n }\n >;\n /**\n * Порядок отображения кастомных вкладок\n */\n customTabsOrder?: Array<Exclude<string, DefaultSidebarTabIds>>;\n defaultTabs?: Array<\n | {\n id: 'filtering' | 'columns';\n /** название таба в рамках горизонтального табов внутри таба настройки */\n label?: string;\n /** название таба в рамках вертикальных табов сайдбара (если данный таб окажется единственным табом в настройках) */\n title?: string;\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n domMetadata?: DomMetadata;\n /**\n * Кастомный элемент справа от title в шапке сайдбара\n */\n titleRightSlot?: React.ReactNode;\n /** @default true */\n showInSidebar?: boolean;\n /** тултип иконки шестеренки (для табов с id = filtering и columns - недоступен. Настраивается через таб с id='tableSettings') */\n iconTooltipText?: undefined;\n }\n | {\n id: 'tableSettings';\n /** название таба в рамках горизонтального табов внутри таба настройки */\n label?: string;\n /** название таба в рамках вертикальных табов сайдбара */\n title?: string;\n\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n domMetadata?: DomMetadata;\n /**\n * Кастомный слот для вкладки tableSettings (рендерится после общих настроек)\n * Только дл id: 'tableSettings'\n */\n customGeneralSettingsSlot?: React.ReactNode;\n /**\n * Кастомный элемент справа от title в шапке сайдбара\n */\n titleRightSlot?: React.ReactNode;\n /** @default true */\n showInSidebar?: boolean;\n /** тултип иконки шестеренки @default 'Настройки' */\n iconTooltipText?: string;\n }\n >;\n};\n\nexport function activeViewIs<T extends 'cards' | 'rows'>(\n checkType: T,\n viewState: 'cards' | 'rows',\n view: View,\n): view is ViewMods[T] {\n return checkType === viewState;\n}\n\n/** Размер controlBlock: 'm' и 's' — одинаковые стили, 'xs' — уменьшенный */\nexport type ControlBlockSize = 'm' | 's' | 'xs';\n\nexport type ControlBlockConfig = {\n /**\n * show - наличие controlBlock-а\n * @default true\n */\n show?: boolean;\n /**\n * Размер controlBlock и его элементов (кнопки, иконки, поиск, отступы).\n * 'm' и 's' — стандартные стили, 'xs' — компактный режим.\n * Не влияет на customFeatures и кастомные слоты — они контролируются разработчиком.\n * @default 'm'\n */\n size?: ControlBlockSize;\n /**\n * @deprecated Используйте кастомные кнопки через rightSideInner или customFeatures.\n * leftSideInner - пропс для добавления кнопок в левую часть контролблока.\n * Продолжает работать для обратной совместимости.\n */\n leftSideInner?: ControlBlockButtonProps[];\n /**\n * rightSideInner - пропс для добавления кнопок в правую часть контролблока\n */\n rightSideInner?: ControlBlockButtonProps[];\n /**\n * customFeatures - пропс для добавления кастомных фичей (кнопки-иконки)\n */\n customFeatures?: FeatureItem[];\n /**\n * pinningMenu - нативная фича закрепления столбцов (SplitIconButton с\n * дропдауном) в правой зоне иконок. Появляется, когда активировано\n * закрепление колонок (columnsControl.pinning). Продукт может донастроить\n * и дополнить пункты меню (см. PinningMenuConfig).\n */\n pinningMenu?: PinningMenuConfig;\n /**\n * Пропсы для компонента dropdown в котором будут скрыты левые фичи при адаптивной компрессии\n */\n leftSideDropdownProps?: TableDropdownConfigProps;\n /**\n * Пропсы для компонента dropdown в котором будут скрыты правые фичи при адаптивной компрессии\n */\n rightSideDropdownProps?: TableDropdownConfigProps;\n /**\n * Активна ли фича компрессии (сжатие ToolsMenu при адаптиве)\n * @default true\n */\n enableAdaptiveCompress?: boolean;\n /**\n * Панель массовых действий\n */\n massActionPanel?: {\n /**\n * Кнопки панели. Размеры кнопок/дропдаунов панель подбирает сама (по `size` панели и компактности) —\n * передавать `size` кнопкам не нужно. Если `size` на кнопке всё же задан — он используется как есть.\n */\n buttons: MassActionButtonProps[];\n /**\n * Пропсы для Dropdown, в который сжались кнопки\n */\n collapsedDropdownProps?: TableDropdownConfigProps;\n /**\n * Отступ панели снизу от контейнера (px)\n * @default 24\n */\n bottom?: number;\n /**\n * Управление отображением панели массовых действий.\n * - `undefined` (по умолчанию) — стандартное поведение (показывается при selecting + выбранных строках)\n * - `false` — панель не рендерится, разработчик управляет действиями самостоятельно\n * - `true` — панель показывается всегда, даже без активного selecting и выбранных строк\n */\n show?: boolean;\n /**\n * Размерная сетка панели внутри таблицы: `m`/`s` — обычный размер, `xs` — уменьшенный (кнопки `xxs`, «ещё» `xs`, счётчик Body XS).\n * Viewport-логика (1280) в таблице не используется.\n * @default 's'\n */\n size?: MassActionsSize;\n };\n};\n\n/** Пропсы кнопки редактирования. onClick исключён — используйте onSave/onCancel/onEnableEditing. */\nexport type EditingButtonProps = Omit<\n Partial<ControlBlockButtonProps>,\n | 'onClick'\n | 'size'\n | 'dropdown'\n | 'isTargetAction'\n | 'skipRightDivider'\n | 'tooltipText'\n>;\n\nexport type EditingConfig<\n RowType extends ObjectForExtending,\n RowIdType,\n SummaryRowType,\n> = {\n /**\n * Функция обработки изменений в редактируемой строке\n */\n onRowsChange: Maybe<\n (rows: RowType[], data: RowsChangeData<RowType, SummaryRowType>) => void\n >;\n /**\n * свойство, необходимое для корректного изменения дочерних строк.\n * Данное свойство обязательно, если ваши дочерние строки установлены не под ключом \"subRows\" внутри строки.\n *\n * Как дочерние строки можно указывать свойство, которые вложено в другое свойство.\n * В таком случае \".\" будет знаком для обозначения сл. уровня вложенности.\n *\n * @example \"child\" или \"uvh367.children\"\n */\n subRowsKey?: string;\n /**\n * Глубокое копирование строк перед применением правки в режиме редактирования.\n *\n * Включите, если строки, передаваемые в таблицу, иммутабельны/заморожены\n * (напр. стейт под управлением Redux Toolkit или Immer — они вызывают\n * Object.freeze в dev). При редактировании дочерней строки таблица записывает\n * изменение ВНУТРЬ объекта родителя; на замороженном объекте это падает с\n * `TypeError: Cannot assign to read only property`.\n *\n * Когда флаг включён, таблица сама делает structuredClone редактируемой строки\n * перед записью — ваш иммутабельный стейт не мутируется, и редактирование\n * дочерних строк работает без действий с вашей стороны.\n *\n * ⚠️ Данные строки должны быть сериализуемыми. Где доступен structuredClone —\n * Date/Map/Set и вложенные структуры копируются корректно; на старых средах\n * без structuredClone используется JSON-фоллбэк (теряет Date/Map/Set, undefined\n * и функции). Не включайте без необходимости — глубокое копирование добавляет\n * накладные расходы.\n *\n * @default false\n */\n deepCloneRows?: boolean;\n /**\n * Функция определения уникального id строки\n * @param row\n * @returns\n */\n rowKeyGetter: (row: RowType) => RowIdType;\n /**\n * Функция определения возможности редактирования строки\n * @param row\n * @returns\n */\n rowEditable?: (row: RowType) => boolean;\n /**\n * defaultEnabled - пропс, отвечающий за то, будет ли активен режим редактирования или нет. По умолчанию - не активно.\n * @default false\n */\n defaultEnabled?: boolean;\n /**\n * enabled - необходим для управления режимом редактирования снаружи компонента Таблицы.\n * По умолчанию, управление происходит в компоненте.\n * Приоритетнее, чем defaultEnabled.\n *\n * @type boolean - если НЕ нужно переключение в самой таблице\n * @type [boolean, React.Dispatch<React.SetStateAction<boolean>>] - если нужно переключение в самой таблице\n *\n */\n enabled?: boolean | [boolean, React.Dispatch<React.SetStateAction<boolean>>];\n /**\n * Cостояние скрытия/раскрытия кнопки включения/выключения фичи\n * @default true\n */\n showButtons?: boolean;\n /**\n * Функция, вызывающаяся при включении фичи.\n * @param enableEditorMode - функция включающая режим редактирования\n */\n onEnableEditing?: (enableEditorMode: () => void) => void;\n /**\n * Функция, вызывающаяся при сохранении отредактированного.\n * @param disableEditorMode - функция выключающая режим редактирования\n */\n onSave?: (disableEditorMode: () => void) => void;\n /**\n * Функция, вызывающаяся при отмене отредактированного.\n * @param disableEditorMode - функция выключающая режим редактирования\n */\n onCancel?: (disableEditorMode: () => void) => void;\n /** Пропсы кнопок в controlBlock. */\n buttons?: {\n save?: EditingButtonProps;\n cancel?: EditingButtonProps;\n edit?: EditingButtonProps;\n };\n /**\n * Кастомный слот, отображаемый левее кнопок «Отменить» / «Сохранить».\n * Виден только когда режим редактирования активен (editMode = true).\n * Зона ответственности разработчика — размерная сетка controlBlock не влияет на этот слот.\n */\n editModeLeftSlot?: React.ReactNode;\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n domMetadata?: {\n enableButton?: DomMetadata;\n saveButton?: DomMetadata;\n cancelButton?: DomMetadata;\n };\n};\n\nexport type SummaryRowsConfig = {\n showDefault: boolean;\n showInControl: boolean;\n} & {\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n domMetadata?: DomMetadata;\n};\n\n/**\n * Конфиг тултипа при hover по canvas-элементам.\n * Для активации фичи необходимо заполнить данный конфиг,\n * а также добавить нужные изменения в Canvas-элементах или в конфиге колонки.\n */\nexport type TableConfigTooltip = {\n /**\n * Включить/выключить колоночные и кастомные тултипы (cellTooltip, headerCellTooltip).\n * Внутренние тултипы (drag-иконка в шапке и другие по nodeId) работают всегда.\n * @default false\n */\n enabled?: boolean;\n /** Глобальная задержка перед показом тултипа (мс). Per-node переопределяет. @default 500 */\n mouseEnterDelay?: number;\n /** Глобальная задержка перед скрытием тултипа (мс). Per-node переопределяет. @default 0 */\n mouseLeaveDelay?: number;\n /**\n * Минимальная ширина тултипа. Число трактуется как px, строка с единицей\n * (например '20rem', '50%') отдаётся как есть. Действует на все canvas-тултипы,\n * включая авто-тултип Canvas.Text. Если ширина задана на самом тултипе\n * (per-node), приоритет у неё.\n */\n minWidth?: number | string;\n /**\n * Максимальная ширина тултипа. Число трактуется как px, строка с единицей\n * (например '20rem', '50%') отдаётся как есть. Действует на все canvas-тултипы,\n * включая авто-тултип Canvas.Text. Если ширина задана на самом тултипе\n * (per-node), приоритет у неё.\n */\n maxWidth?: number | string;\n};\n\nexport type InfinityScrollConfig<RowType extends ObjectForExtending> = {\n /** Триггер достижения скроллом зоны подгрузки данных. */\n onTrigger: (rows: RowType[]) => Promise<void> | void;\n /** Состояние загрузки (скелетоны) новых строк. */\n isLoading: boolean;\n /**\n * Флаг, когда все данные загружены — false.\n * @default true\n */\n hasMore?: boolean;\n /**\n * Для mode='region': за сколько строк до конца триггерить загрузку.\n * @default 5\n */\n rowThreshold?: number;\n};\n\nexport type { TableCanvasEmptyStateConfig, TableCanvasErrorStateConfig };\n\n/**\n * Настройка выделения ячеек/колонок/строк в TableCanvas — единый объект.\n * Это отдельная ось взаимодействия — не зависит от `highlightActiveType`.\n */\nexport type CellsSelectionConfig = {\n /**\n * Режим фактического выделения ячеек (нативный glide selection). По нему\n * работают copy/paste, рамка, fill-handle и затемнение шапки/нумерации.\n * @default \"range-cell\"\n */\n mode?: CellsSelectionMode;\n /**\n * Выделение колонок по клику на шапку. Ctrl/Cmd — добавить/убрать колонку,\n * Shift — диапазон колонок. Клик по иконкам сортировки/фильтрации в шапке\n * выделение НЕ вызывает. Поддерживает copy/paste по выделенным колонкам.\n * @default true\n */\n enableColumnSelection?: boolean;\n /**\n * Выделение строк по клику/драгу на колонке нумерации (`rowMarkers`).\n * Ctrl/Cmd — несмежный выбор отдельных строк, драг — смежный диапазон.\n * Поддерживает copy/paste по выделенным строкам. Требует включённой колонки\n * нумерации (`rowMarkers`). При `false` клик по нумерации ничего не выделяет.\n * @default true\n */\n enableRowSelection?: boolean;\n /**\n * Выделение всей таблицы кликом по «нулевой» ячейке — шапке колонки нумерации\n * (левый верхний угол). Выделяет все строки данных по всем колонкам одним\n * диапазоном; поддерживает copy/paste. Требует включённой колонки нумерации\n * (`rowMarkers`) и активного `mode` (≠ `disabled`).\n * @default true\n */\n enableSelectAll?: boolean;\n /**\n * Внешний (controlled) контроль НАТИВНОГО выделения (ячейки/диапазон/смежные\n * строки и колонки). `state` — кортеж `[value, setter]` как у `selecting.state`.\n * Сброс: `setter({ current: undefined, rows: empty, columns: empty })`.\n * Несмежный Ctrl-выбор колонок/строк (own-state) сюда не входит — он внутренний.\n */\n state?: [GridSelection, React.Dispatch<React.SetStateAction<GridSelection>>];\n};\n\n/** Один объединённый блок: какие строки и колонки слить. */\nexport type MergedCellsRegion = {\n rowKeys: Array<string | number>;\n colKeys: string[];\n /** Выравнивание контента этого блока. Важнее колоночного и общего. */\n mergedCellsAlign?: MergedCellsAlign;\n};\n\nexport type TableConfig<\n RowType extends ObjectForExtending,\n SummaryRowType,\n RowIdType extends string | number,\n FilterStateType extends ObjectForExtending,\n // SubRowType\n> = {\n /**\n * Группировка колонок (многоуровневая шапка через `columnConfig.children`):\n * объединение пустых ячеек шапки (`squashEmptyCells`, по умолчанию включено) и\n * дефолт выравнивания в объединённых ячейках (`squashedHeaderAlign`).\n */\n columnsGrouping?: ColumnsGroupingConfig;\n /**\n * Подсветка активной сущности в canvas-таблице.\n * @deprecated Значения `'cell'`/`'range-cell'` устарели — используйте\n * `cellsSelection.mode`. Актуальны `'row'` (подсветка строки) и `'disabled'`.\n */\n highlightActiveType?: HighlightActiveType;\n /**\n * Единый конфиг выделения ячеек: режим (`mode`), оси\n * (`enableColumnSelection`/`enableRowSelection`/`enableSelectAll`) и controlled\n * (`state`). См. {@link CellsSelectionConfig}.\n */\n cellsSelection?: CellsSelectionConfig;\n /**\n * Подсвеченная строка (`highlightActiveType='row'`).\n * `state` (опционально) — controlled-кортеж `[value, setter]`: задан — значением\n * владеешь снаружи (сброс `setter(undefined)`); не задан — таблица крутит\n * подсветку внутренним стейтом, а `onChange` всё равно срабатывает (подписка\n * без владения значением).\n */\n highlightActiveRow?: {\n state?: [\n number | undefined,\n React.Dispatch<React.SetStateAction<number | undefined>>,\n ];\n /**\n * Колбэк смены подсвеченной строки: отдаёт её флэт-индекс и сам объект\n * строки (`rows[index]`). Позволяет открывать данные подсвеченной строки\n * (например, в SplitView) без `onCellClicked`.\n */\n onChange?: (params: {\n index: number | undefined;\n row: RowType | undefined;\n }) => void;\n };\n /**\n * Эффекты при наведении (hover)\n * `row` — подсветка строки под курсором.\n * Независимая визуальная ось: селектинг (`cellsSelection`) и `highlightActiveType='row'`\n * рисуются ПОВЕРХ hover-подсветки и визуально перекрывают её (hover\n * «остаётся под ними» и снова виден после сброса выделения).\n *\n * `{ row: true }` — включить с цветами из темы;\n * `{ row: { color: '#F7F9FB' } }` — переопределить цвет data-ячеек.\n * @default undefined (выключено)\n */\n hoverEffects?: HoverEffectsConfig;\n /**\n * Включает компенсацию тонких canvas-линий при browser zoom ниже 100%, когда devicePixelRatio меньше 1.\n * Влияет только на grid/header/sticky hairline borders.\n * @default false\n */\n enableLowDprHairline?: boolean;\n /**\n * rowSize - размеры строк таблицы\n */\n rowSize?: Prettify<RowSize>;\n /**\n * rowHeight - размер высоты строк таблицы\n */\n rowHeight?: Maybe<number | RowHeightFunc<RowType>>;\n /**\n * sorting - активация сортировки. Условие активации - это наличие данного свойства. Нужно также сконфигурировать колонки.\n *\n * Пример:\n *\n * tableConfig={sorting: {sortingState}}\n *\n * columnConfig=[{sortingType: 'numberSort'}]\n */\n sorting?: {\n state: [\n readonly SortColumn[],\n React.Dispatch<React.SetStateAction<readonly SortColumn[]>>,\n ];\n /**\n * manualSorting - пропс, активирующий ручную-кастомную (или на стороне бэкенда) сортировку\n */\n manualSorting?: boolean;\n };\n /** @deprecated Свойство view не используется и будет удалено в следующей мажорной версии. */\n view?: View;\n /**\n * filtering - активация фильтрации. Условие активации - это наличие данного свойства. Нужно также сконфигурировать колонки.\n *\n * Пример:\n *\n * tableConfig={filtering: {stateAndSetter, ...}}\n *\n * columnConfig=[{filtering: {...}}]\n */\n filtering?: FilteringConfig<FilterStateType>;\n /**\n * Сворачивание / разворачивание таблицы\n */\n collapsing?: TableCollapseConfig;\n /**\n * selecting - активация выбора строк. Условие активации - это наличие данного свойства.\n * Есть поддержка выбора строк с многоуровневой вложенностью.\n *\n * Пример:\n *\n *"
52983
53361
  },
52984
53362
  {
52985
53363
  "typeName": "FilterComponentInPopoverProps",
@@ -53653,7 +54031,7 @@
53653
54031
  "exportName": "SubRows",
53654
54032
  "displayName": "Иерархичный вид",
53655
54033
  "type": "full-code",
53656
- "code": "import { ColumnConfig, TableCanvas } from '@daisforge/ui/components/TableCanvas';\n\n() => {\n const [rows] = useState(() => createRowsTree());\n\n const columns = useMemo(\n (): readonly ColumnConfig<TreeRow>[] => [\n {\n key: 'block',\n name: 'Блок / Трайб / Продукт',\n\n subRow: {\n keyOfColumnInSubRow: (lvl) => {\n switch (lvl) {\n case 0:\n return 'block';\n case 1:\n return 'tribe';\n case 2:\n return 'product';\n default:\n return 'block';\n }\n },\n\n isColumnWithArrow: true,\n hideHeaderExpandAllArrow: false,\n },\n },\n {\n key: 'blockActivity',\n name: 'Активность блока',\n },\n {\n key: ' ',\n name: 'Локация трайба',\n subRow: {\n renderSubRowCell: (props, lvl) => {\n if (lvl === 1) {\n return (\n <Canvas.Container\n alignItems=\"center\"\n padding={{ left: 8 }}\n style={{ width: '100%' }}\n >\n <Canvas.Badge\n id=\"kek\"\n text={props.row?.tribeZone}\n view=\"accent\"\n size=\"m\"\n />\n </Canvas.Container>\n );\n }\n return '';\n },\n },\n },\n {\n key: 'q1',\n name: 'Q1',\n\n subRow: {\n parentKeyAsDefault: true,\n },\n },\n\n {\n key: 'q2',\n name: 'Q2',\n subRow: {\n keyOfColumnInSubRow: 'q1',\n },\n },\n {\n key: 'q3',\n name: 'Q3',\n subRow: {\n keyOfColumnInSubRow: 'q1',\n },\n },\n {\n key: 'q4',\n name: 'Q4',\n subRow: {\n keyOfColumnInSubRow: 'q1',\n },\n },\n ],\n [],\n );\n\n return (\n <TableCanvas\n tableConfig={{\n containerStyle: { height: '60vh' },\n subRows: {\n getSubRows: (row) => row?.subRows,\n rowKeyGetter: (row) => row.id,\n },\n fullScreenEnabled: true,\n resizableColumn: true,\n }}\n columnConfig={columns}\n rows={rows}\n />\n );\n }"
54034
+ "code": "import { ColumnConfig, TableCanvas } from '@daisforge/ui/components/TableCanvas';\n\n() => {\n // Разная глубина и число детей у строк — «рваная лестница» отступов\n const [rows] = useState(() => createRaggedRowsTree());\n\n const columns = useMemo(\n (): readonly ColumnConfig<TreeRow>[] => [\n {\n key: 'block',\n name: 'Блок / Трайб / Продукт',\n\n subRow: {\n keyOfColumnInSubRow: (lvl) => {\n switch (lvl) {\n case 0:\n return 'block';\n case 1:\n return 'tribe';\n default:\n return 'product';\n }\n },\n\n isColumnWithArrow: true,\n hideHeaderExpandAllArrow: false,\n },\n },\n {\n key: 'blockActivity',\n name: 'Активность блока',\n },\n {\n key: ' ',\n name: 'Локация трайба',\n subRow: {\n renderSubRowCell: (props, lvl) => {\n if (lvl === 1) {\n return (\n <Canvas.Container\n alignItems=\"center\"\n padding={{ left: 8 }}\n style={{ width: '100%' }}\n >\n <Canvas.Badge\n id=\"kek\"\n text={props.row?.tribeZone}\n view=\"accent\"\n size=\"m\"\n />\n </Canvas.Container>\n );\n }\n return '';\n },\n },\n },\n {\n key: 'q1',\n name: 'Q1',\n\n subRow: {\n parentKeyAsDefault: true,\n },\n },\n\n {\n key: 'q2',\n name: 'Q2',\n subRow: {\n keyOfColumnInSubRow: 'q1',\n },\n },\n {\n key: 'q3',\n name: 'Q3',\n subRow: {\n keyOfColumnInSubRow: 'q1',\n },\n },\n {\n key: 'q4',\n name: 'Q4',\n subRow: {\n keyOfColumnInSubRow: 'q1',\n },\n },\n ],\n [],\n );\n\n return (\n <TableCanvas\n tableConfig={{\n containerStyle: { height: '85vh' },\n subRows: {\n getSubRows: (row) => row?.subRows,\n rowKeyGetter: (row) => row.id,\n },\n // Отступ уровня зависит от размера строки: big 16/66/116,\n // medium 6/42/78, small 4/32/60 px\n rowSize: { showInControl: true, default: 'big' },\n fullScreenEnabled: true,\n resizableColumn: true,\n }}\n columnConfig={columns}\n rows={rows}\n />\n );\n }"
53657
54035
  }
53658
54036
  ]
53659
54037
  },
@@ -53684,7 +54062,7 @@
53684
54062
  "feature": "ThemeOverride",
53685
54063
  "legacy": false,
53686
54064
  "summary": "*columnConfig.themeOverride**",
53687
- "docs": "# Theme Override\n\n**columnConfig.themeOverride**\n\nПереопределение визуальных свойств ячейки на уровне колоночного конфига. Колбэк вызывается для каждой ячейки колонки и возвращает частичный override темы (`Partial<Theme>`), либо `undefined`, если для ячейки переопределение не нужно.\n\n## Ключевые особенности\n\n- `bgCell` — цвет фона ячейки (рисуется нативно, закрашивает всю площадь ячейки, включая паддинги)\n- `cellHorizontalPadding` — горизонтальные отступы контента ячейки\n- `cellVerticalPadding` — вертикальные отступы контента ячейки\n- Колбэк получает `cellInfo` (row, column, ctxs, theme) и `lvl` — уровень вложенности subRow (0 для корневых строк, 1+ для дочерних)\n- Условное поведение: можно менять стили в зависимости от данных строки или уровня вложенности\n\n## Сигнатура\n\n```ts\nthemeOverride?: (\n cellInfo: CellInfo<Row, SummRow, CustomCtxs>,\n lvl: number\n) => CellThemeOverrideResult | undefined;\n```\n\n## Особенности\n\n### Обычные колонки\n\nДля колонок без `subRow.isColumnWithArrow` `cellHorizontalPadding` через `themeOverride` применяется напрямую и одинаково на всех уровнях вложенности (root и subRows). Левый и правый паддинги получают точное значение из override.\n\n### Tree-колонки (с шевроном раскрытия)\n\nДля колонок с `subRow.isColumnWithArrow: true` левый край ячейки рассчитывается формулой `getPaddingLeftFinal(padding, lvl, hasChildrenAndArrow, isExpandable)`. Формула берёт `cellHorizontalPadding` как базу и прибавляет к нему отступ под шеврон + offset на уровень вложенности. Override влияет на левый край, но итоговое значение `= override + offsets`, а не ровно значение override. Правый край и `bgCell` для tree-колонок работают как обычно.\n\n### Кастомный renderCell\n\nДля колонок с `renderCell` системная обёртка с паддингом не добавляется. Разработчик сам управляет отступами через `theme.cellHorizontalPadding` внутри своего renderCell.\n\n### bgCell\n\n`bgCell` рисуется нативно на уровне самой таблицы. Фон закрашивает всю ячейку целиком, включая области паддингов и любых обёрток.\n\n## См. также\n\n- `getRowThemeOverride` — нативный API таблицы для переопределения темы **строки целиком** (по индексу строки, без cellInfo). Используется для подсветки summary-строк и selected-строк. Если нужен row-level эффект (например, \"выделенная строка целиком\") — используйте этот механизм, а не `themeOverride` на каждой ячейке.\n\n> Подробнее о типах — [Theme Override API](?path=/docs/локальные-компоненты-tablecanvas-themeoverride-api--docs)",
54065
+ "docs": "# Theme Override\n\n**columnConfig.themeOverride**\n\nПереопределение визуальных свойств ячейки на уровне колоночного конфига. Колбэк вызывается для каждой ячейки колонки и возвращает частичный override темы (`Partial<Theme>`), либо `undefined`, если для ячейки переопределение не нужно.\n\n## Ключевые особенности\n\n- `bgCell` — цвет фона ячейки (рисуется нативно, закрашивает всю площадь ячейки, включая паддинги)\n- `cellHorizontalPadding` — горизонтальные отступы контента ячейки\n- `cellVerticalPadding` — вертикальные отступы контента ячейки\n- Колбэк получает `cellInfo` (row, column, ctxs, theme) и `lvl` — уровень вложенности subRow (0 для корневых строк, 1+ для дочерних)\n- Условное поведение: можно менять стили в зависимости от данных строки или уровня вложенности\n\n## Сигнатура\n\n```ts\nthemeOverride?: (\n cellInfo: CellInfo<Row, SummRow, CustomCtxs>,\n lvl: number\n) => CellThemeOverrideResult | undefined;\n```\n\n## Особенности\n\n### Обычные колонки\n\nДля колонок без `subRow.isColumnWithArrow` `cellHorizontalPadding` через `themeOverride` применяется напрямую и одинаково на всех уровнях вложенности (root и subRows). Левый и правый паддинги получают точное значение из override.\n\n### Tree-колонки (с шевроном раскрытия)\n\nДля колонок с `subRow.isColumnWithArrow: true` левый край ячейки рассчитывается формулой `cellHorizontalPadding + step * lvl`, где шаг зависит от размера строки: `big` — 50 (16 → 66 → 116 → 166 px), `medium` — 36 (6 → 42 → 78 → 114 px), `small` — 28 (4 → 32 → 60 → 88 px). Отступ зависит только от уровня вложенности и не зависит от наличия шеврона, поэтому текст дочерней строки всегда правее текста родителя. Шеврон рисуется иконкой без пустого места слева: раскрытый `∨` начинается ровно на линии уровня (там же, где текст соседнего листа), у свёрнутого `>` небольшой отступ, чтобы при раскрытии не было скачка. Справа от шеврона места столько же, сколько у исходной иконки, поэтому расстояние до текста прежнее. Двойной шеврон в шапке (`раскрыть/скрыть все строки`) построен так же и стоит на линии свёрнутого шеврона строки, а заголовок колонки — над текстом строк верхнего уровня. Override влияет на левый край, но итоговое значение `= override + offsets`, а не ровно значение override. Правый край и `bgCell` для tree-колонок работают как обычно.\n\n### Кастомный renderCell\n\nДля колонок с `renderCell` системная обёртка с паддингом не добавляется. Разработчик сам управляет отступами через `theme.cellHorizontalPadding` внутри своего renderCell.\n\n### bgCell\n\n`bgCell` рисуется нативно на уровне самой таблицы. Фон закрашивает всю ячейку целиком, включая области паддингов и любых обёрток.\n\n## См. также\n\n- `getRowThemeOverride` — нативный API таблицы для переопределения темы **строки целиком** (по индексу строки, без cellInfo). Используется для подсветки summary-строк и selected-строк. Если нужен row-level эффект (например, \"выделенная строка целиком\") — используйте этот механизм, а не `themeOverride` на каждой ячейке.\n\n> Подробнее о типах — [Theme Override API](?path=/docs/локальные-компоненты-tablecanvas-themeoverride-api--docs)",
53688
54066
  "apiDocs": "# Theme Override API\n\nПереопределение темы настраивается через свойство `themeOverride` в `columnConfig`.\n\nЯвляется частью `ColumnConfig`.\n\n## CellThemeOverrideResult\n\n```typescript\ntype CellThemeOverrideResult = Partial<{\n bgCell: string;\n cellHorizontalPadding: number;\n cellVerticalPadding: number;\n}>;\n```\n\n## CellInfo\n\n```typescript\ntype CellInfo<\n R extends ObjectForExtending,\n SR = unknown,\n CustomCtxs extends ObjectForExtending = {},\n> = Omit<\n CellInfoGlideInstance<R, SR, CustomCtxs>,\n 'column' | 'ctxs' | 'hovered' | 'active'\n> & {\n column: ColumnConfig<R, SR, CustomCtxs>;\n ctxs: CtxsType<CustomCtxs>;\n /**\n * Состояние наведения для текущей ячейки, которую рендерит renderCell.\n * `cellHover` равно true только у ячейки под курсором, `rowHover` — у всех ячеек ее строки.\n */\n hovered: CellHoverState;\n /**\n * Состояние активного выделения для текущей ячейки, которую рендерит renderCell.\n * `cellActive` равно true у активной ячейки или диапазона, `rowActive` — у строк с активной ячейкой или диапазоном.\n */\n active: CellActiveState;\n};\n```",
53689
54067
  "api": [
53690
54068
  {
@@ -53734,8 +54112,8 @@
53734
54112
  "feature": "Tooltip",
53735
54113
  "legacy": false,
53736
54114
  "summary": "*tableConfig.tooltip + columnConfig.cellTooltip / headerCellTooltip**",
53737
- "docs": "# Tooltip на канвасной таблице\n\n**tableConfig.tooltip + columnConfig.cellTooltip / headerCellTooltip**\n\nОдин общий тултип для элементов, отрисованных на канвасе (ячейки, заголовки, кнопки и т.д.). Тултип показывается при наведении на те канвас-элементы, которые явно участвуют в механике тултипа.\n\n## Принцип работы\n\n- На таблице работает **один тултип**: при наведении на разные элементы отображается один и тот же тултип-оверлей с нужным текстом/пропсами для текущего элемента.\n- Участие элемента в показе тултипа задаётся через проп **`portalHoverEnabled`** на Canvas-примитиве — без этого пропса наведение на элемент не будет передаваться в подсистему тултипа.\n\n## Три источника конфига (по приоритету)\n\n1. **Проп `tooltip` на Canvas-элементе** — задаётся прямо на `Canvas.Container`, `Canvas.Button` и т.д. Строка или объект с `text`. Самый высокий приоритет. **Работает всегда.**\n2. **Поле `cellTooltip` / `headerCellTooltip` в `columnConfig`** — конфиг на уровне колонки. Может быть строкой, объектом или функцией `(context) => config | null`. Для ячеек используется `cellTooltip`, для заголовков — `headerCellTooltip`. **Требует `tooltip.enabled: true` в `tableConfig`.**\n3. **Встроенный маппинг по `nodeId`** — внутренний словарь (например, иконка drag в заголовке → «Перетащить колонку»). **Работает всегда.**\n\n## Как включить тултип на элементе\n\n### Через `tooltip` на Canvas-примитиве\n\nВ `renderCell` / `renderHeaderCell` задать `portalHoverEnabled` и `tooltip` на нужном элементе:\n\n```tsx\nrenderCell: () => (\n <Canvas.Button\n portalHoverEnabled\n tooltip=\"Нажмите для перехода\"\n onClick={() => {}}\n >\n Подробнее\n </Canvas.Button>\n);\n```\n\n### Авто-тултип для обрезанного текста (`autoTooltip` на `Canvas.Text`)\n\nЧастный случай node-тултипа: `Canvas.Text` с пропом `autoTooltip` показывает тултип с полным текстом **только когда текст реально обрезан в многоточие** (однострочный ellipsis или многострочный clamp). `portalHoverEnabled` включается автоматически, `tooltip.enabled: true` в `tableConfig` не требуется — работает всегда, как и остальные node-тултипы.\n\n```tsx\nrenderCell: ({ row }) => (\n <Canvas.Text\n overflow=\"hidden\"\n textOverflow=\"ellipsis\"\n autoTooltip\n style={{ flexGrow: 1 }}\n >\n {row.longText}\n </Canvas.Text>\n);\n```\n\nПоведение настраивается объектом: `placement`, `view`, `mouseEnterDelay` / `mouseLeaveDelay`, трансформация текста через `text`, выключение через `enabled: false`. Подробности и правила — в [доке Canvas.Text](?path=/docs/локальные-компоненты-tablecanvas-canvaselements-canvastext--docs), тип — `CanvasTextAutoTooltip`.\n\n> Действует только на `Canvas.Text` в canvas-разметке (`renderCell` / `renderHeaderCell`). Обычные текстовые ячейки (примитивные значения без `renderCell`) рисуются встроенным text-рендерером glide — авто-тултип на них пока не распространяется.\n\n### Через `cellTooltip` / `headerCellTooltip` в `columnConfig`\n\nЗадать на уровне колонки — строкой, объектом или функцией. Не забудьте включить `tooltip.enabled: true`:\n\n```tsx\ntableConfig={{\n tooltip: { enabled: true },\n}}\ncolumnConfig={[\n {\n key: 'task',\n name: 'Title',\n headerCellTooltip: 'Название задачи',\n cellTooltip: ({ row }) => `Задача: ${row.task}`,\n },\n]}\n```\n\n## Формат конфига\n\n- **Строка** — используется как текст тултипа с дефолтными пропсами.\n- **Объект** `{ text: string, placement?, view?, mouseEnterDelay?, ... }` — текст и кастомные пропсы для `Tooltip`.\n- **`null`** — тултип для этого элемента не показывается (переход к следующему приоритету или без тултипа).\n\nПодробное описание типов и контракта — в разделе [API](/docs/локальные-компоненты-tablecanvas-tooltip-api--docs).",
53738
- "apiDocs": "# Tooltip API\n\n## Источники конфига тултипа\n\nТултип может быть задан на **трёх уровнях** (проверяются по приоритету, первый непустой побеждает):\n\n1. **Встроенный маппинг по `nodeId`** — внутренний словарь `TOOLTIP_TEXTS` (например, `HEADER_TOOLTIP_DRAG_ID` → «Перетащить колонку»). **Работает всегда.** Наивысший приоритет — колоночный конфиг не может перебить внутренние тултипы UI таблицы.\n2. **Проп `tooltip` на Canvas-элементе** — задаётся прямо на `Canvas.Container`, `Canvas.Button` и т.д. внутри `renderCell` / `renderHeaderCell`. Тип: `CanvasNodeTooltipConfig`. **Работает всегда.**\n3. **Поле `cellTooltip` / `headerCellTooltip` в `columnConfig`** — на уровне конфигурации колонки. Может быть строкой, объектом или функцией `(context) => config | null`. **Работает только при `tooltip.enabled: true`.**\n\n**Формат конфига:** строка (только текст) или объект с обязательным полем `text` и опциональными пропсами `Tooltip` (`placement`, `view` и т.д.; без `opened`, `target`, `style`), а также `mouseEnterDelay` / `mouseLeaveDelay` для per-node задержек.\n\nПо умолчанию текст рендерится с `white-space: normal` — переносы строк (`\\n`) в `text` схлопываются в пробел. Чтобы сохранить переносы (например, в многострочных подсказках), добавьте в объектную форму конфига `preserveLineBreaks: true` — тогда к тексту тултипа применится `white-space: pre-line`. Флаг выключен по умолчанию и не меняет поведение существующих строковых тултипов.\n\n## Модуль tableConfig.tooltip\n\nГлобальные настройки тултипа вынесены в `tableConfig.tooltip` (тип `TableConfigTooltip`):\n\n- **tooltip.enabled** — включает колоночные/кастомные тултипы (`cellTooltip`, `headerCellTooltip`). По умолчанию `false`. Внутренние тултипы (проп `tooltip` на Canvas-элементе и маппинг по `nodeId`) работают всегда, независимо от `enabled`.\n- **tooltip.mouseEnterDelay** — глобальная задержка перед показом (мс, по умолчанию `500`). Per-node переопределяет.\n- **tooltip.mouseLeaveDelay** — глобальная задержка перед скрытием (мс, по умолчанию `0`). Per-node переопределяет.\n\nПример:\n\n```tsx\ntableConfig={{\n tooltip: {\n enabled: true,\n mouseEnterDelay: 300,\n },\n}}\n```\n\n## Колоночные cellTooltip / headerCellTooltip\n\nЗадаются в `columnConfig` на уровне колонки. Значение — строка, объект или функция. Требуют `tooltip.enabled: true` в `tableConfig`:\n\n```tsx\nconst columnConfig = [\n {\n key: 'task',\n name: 'Title',\n // Строка — простой текст\n headerCellTooltip: 'Название задачи',\n // Функция — динамический конфиг\n cellTooltip: ({ row, column }) => {\n return `${column.name}: ${row.task}`;\n },\n },\n];\n```\n\nКонтекст функции `cellTooltip` содержит: `row`, `column`, `ctxs`, `refTable`, `colInd`, `rowInd`, `theme`.\nКонтекст функции `headerCellTooltip` содержит: `column`, `ctxs`, `refTable`, `colInd`, `theme`.\n\n---\n\n## Типы\n\n### CanvasNodeTooltipConfig\n\nПроп `tooltip` на Canvas-элементах и базовый формат конфига. Строка (текст) или объект с `text` и опциональными пропсами Tooltip.\n\n```typescript\ntype CanvasNodeTooltipConfig =\n | string\n | (CanvasNodeTooltipProps & {\n /** Текст тултипа (только string, не ReactNode). */\n text: string;\n /** Задержка перед показом (мс). По умолчанию 0. */\n mouseEnterDelay?: number;\n /** Задержка перед скрытием после ухода мыши (мс). По умолчанию 0. */\n mouseLeaveDelay?: number;\n });\n```\n\n### CanvasNodeTooltipProps\n\nПропсы Tooltip, которые можно задать через объектную форму конфига. Управляемые внутренне поля (`opened`, `target`, `style`, `text`, `mouseEnterDelay`, `mouseLeaveDelay`, `hoverTimeout`, `trigger`) исключены.\n\n```typescript\ntype CanvasNodeTooltipProps = Pick<\n TooltipProps,\n 'placement' | 'view' | 'minWidth' | 'maxWidth'\n> & {\n /** Сохранять переносы строк (\\n) в тексте тултипа через white-space: pre-line. @default false */\n preserveLineBreaks?: boolean;\n};\n```\n\n### TooltipConfigResult\n\nАлиас: `CanvasNodeTooltipConfig | null`. Используется как возвращаемый тип функциональной формы `cellTooltip` / `headerCellTooltip`.\n\n```typescript\ntype TooltipConfigResult = CanvasNodeTooltipConfig | null;\n```\n\n### TooltipData\n\nВнутренний результат резолвинга: текст, пропсы тултипа и per-node задержки. Возвращается из `resolveTooltipData` и передаётся в `usePortalHover`.\n\n```typescript\ninterface TooltipData {\n tooltipText: string;\n tooltipProps?: CanvasNodeTooltipProps;\n mouseEnterDelay?: number;\n mouseLeaveDelay?: number;\n}\n```\n\n### TableConfigTooltip\n\nГлобальные настройки тултипа в `tableConfig.tooltip`.\n\n```typescript\ntype TableConfigTooltip = {\n /**\n * Включить/выключить колоночные и кастомные тултипы (cellTooltip, headerCellTooltip).\n * Внутренние тултипы (drag-иконка в шапке и другие по nodeId) работают всегда.\n * @default false\n */\n enabled?: boolean;\n /** Глобальная задержка перед показом тултипа (мс). Per-node переопределяет. @default 500 */\n mouseEnterDelay?: number;\n /** Глобальная задержка перед скрытием тултипа (мс). Per-node переопределяет. @default 0 */\n mouseLeaveDelay?: number;\n};\n```\n\n### CanvasPortalHoverDetail\n\nОбъект события hover по canvas-элементу. Содержит координаты, размеры, `nodeId`, `source` (`'header'` | `'cell'`), `tooltipFromNode` и `tooltipContext` (column, row, ctxs, refTable).\n\n```typescript\ninterface CanvasPortalHoverDetail<\n TContext extends TooltipContextShape = TooltipContextShape\n> {\n visible: boolean;\n x: number;\n y: number;\n width: number;\n height: number;\n node?: CanvasNode | null;\n nodeId?: string;\n source?: CanvasPortalSource;\n originId?: string;\n /** column, row, ctxs, refTable — тип задаётся generic TContext */\n tooltipContext?: TContext;\n /** Конфиг с ноды (проп tooltip на Canvas-элементе). */\n tooltipFromNode?: CanvasNodeTooltipConfig;\n /**\n * Приоритет события. usePortalHover не заменяет активный тултип с бо́льшим приоритетом.\n * - 1 — canvas-нода (CanvasHoverController)\n * - 0 — колоночный тултип (useItemHoveredHandler)\n * @default 0\n */\n priority?: number;\n}\n```",
54115
+ "docs": "# Tooltip на канвасной таблице\n\n**tableConfig.tooltip + columnConfig.cellTooltip / headerCellTooltip**\n\nОдин общий тултип для элементов, отрисованных на канвасе (ячейки, заголовки, кнопки и т.д.). Тултип показывается при наведении на те канвас-элементы, которые явно участвуют в механике тултипа.\n\n## Принцип работы\n\n- На таблице работает **один тултип**: при наведении на разные элементы отображается один и тот же тултип-оверлей с нужным текстом/пропсами для текущего элемента.\n- Участие элемента в показе тултипа задаётся через проп **`portalHoverEnabled`** на Canvas-примитиве — без этого пропса наведение на элемент не будет передаваться в подсистему тултипа.\n\n## Три источника конфига (по приоритету)\n\n1. **Проп `tooltip` на Canvas-элементе** — задаётся прямо на `Canvas.Container`, `Canvas.Button` и т.д. Строка или объект с `text`. Самый высокий приоритет. **Работает всегда.**\n2. **Поле `cellTooltip` / `headerCellTooltip` в `columnConfig`** — конфиг на уровне колонки. Может быть строкой, объектом или функцией `(context) => config | null`. Для ячеек используется `cellTooltip`, для заголовков — `headerCellTooltip`. **Требует `tooltip.enabled: true` в `tableConfig`.**\n3. **Встроенный маппинг по `nodeId`** — внутренний словарь (например, иконка drag в заголовке → «Перетащить колонку»). **Работает всегда.**\n\n## Как включить тултип на элементе\n\n### Через `tooltip` на Canvas-примитиве\n\nВ `renderCell` / `renderHeaderCell` задать `portalHoverEnabled` и `tooltip` на нужном элементе:\n\n```tsx\nrenderCell: () => (\n <Canvas.Button\n portalHoverEnabled\n tooltip=\"Нажмите для перехода\"\n onClick={() => {}}\n >\n Подробнее\n </Canvas.Button>\n);\n```\n\n### Авто-тултип для обрезанного текста (`autoTooltip` на `Canvas.Text`)\n\nЧастный случай node-тултипа: `Canvas.Text` с пропом `autoTooltip` показывает тултип с полным текстом **только когда текст реально обрезан в многоточие** (однострочный ellipsis или многострочный clamp). `portalHoverEnabled` включается автоматически, `tooltip.enabled: true` в `tableConfig` не требуется — работает всегда, как и остальные node-тултипы.\n\n```tsx\nrenderCell: ({ row }) => (\n <Canvas.Text\n overflow=\"hidden\"\n textOverflow=\"ellipsis\"\n autoTooltip\n style={{ flexGrow: 1 }}\n >\n {row.longText}\n </Canvas.Text>\n);\n```\n\nПоведение настраивается объектом: `placement`, `view`, `mouseEnterDelay` / `mouseLeaveDelay`, трансформация текста через `text`, выключение через `enabled: false`. Подробности и правила — в [доке Canvas.Text](?path=/docs/локальные-компоненты-tablecanvas-canvaselements-canvastext--docs), тип — `CanvasTextAutoTooltip`.\n\n> Действует только на `Canvas.Text` в canvas-разметке (`renderCell` / `renderHeaderCell`). Обычные текстовые ячейки (примитивные значения без `renderCell`) рисуются встроенным text-рендерером glide — авто-тултип на них пока не распространяется.\n\n### Через `cellTooltip` / `headerCellTooltip` в `columnConfig`\n\nЗадать на уровне колонки — строкой, объектом или функцией. Не забудьте включить `tooltip.enabled: true`:\n\n```tsx\ntableConfig={{\n tooltip: { enabled: true },\n}}\ncolumnConfig={[\n {\n key: 'task',\n name: 'Title',\n headerCellTooltip: 'Название задачи',\n cellTooltip: ({ row }) => `Задача: ${row.task}`,\n },\n]}\n```\n\n## Ширина тултипа\n\nШирину тултипа можно задать глобально для всей таблицы через `tableConfig.tooltip`:\n\n```tsx\ntableConfig={{\n tooltip: { minWidth: 120, maxWidth: 440 },\n}}\n```\n\nЭта ширина применяется ко всем canvas-тултипам, включая авто-тултип `Canvas.Text`.\n\nЧисло трактуется как пиксели. Если нужна другая единица, передайте строку: `maxWidth: '20rem'`, `maxWidth: '50%'`.\n\nПриоритет от высокого к низкому:\n\n- ширина, заданная на самом тултипе (`tooltip` или `autoTooltip` на Canvas-элементе);\n- глобальная `tableConfig.tooltip.minWidth` / `maxWidth`;\n- дефолт компонента `Tooltip`.\n\nТо есть глобальное значение работает как значение по умолчанию, а точечное на элементе его перекрывает:\n\n```tsx\n// у этого тултипа своя ширина, глобальная не применится\n<Canvas.Text\n overflow=\"hidden\"\n textOverflow=\"ellipsis\"\n autoTooltip={{ maxWidth: 300 }}\n>\n {row.longText}\n</Canvas.Text>\n```\n\n## Формат конфига\n\n- **Строка** — используется как текст тултипа с дефолтными пропсами.\n- **Объект** `{ text: string, placement?, view?, mouseEnterDelay?, ... }` — текст и кастомные пропсы для `Tooltip`.\n- **`null`** — тултип для этого элемента не показывается (переход к следующему приоритету или без тултипа).\n\nПодробное описание типов и контракта — в разделе [API](/docs/локальные-компоненты-tablecanvas-tooltip-api--docs).",
54116
+ "apiDocs": "# Tooltip API\n\n## Источники конфига тултипа\n\nТултип может быть задан на **трёх уровнях** (проверяются по приоритету, первый непустой побеждает):\n\n1. **Встроенный маппинг по `nodeId`** — внутренний словарь `TOOLTIP_TEXTS` (например, `HEADER_TOOLTIP_DRAG_ID` → «Перетащить колонку»). **Работает всегда.** Наивысший приоритет — колоночный конфиг не может перебить внутренние тултипы UI таблицы.\n2. **Проп `tooltip` на Canvas-элементе** — задаётся прямо на `Canvas.Container`, `Canvas.Button` и т.д. внутри `renderCell` / `renderHeaderCell`. Тип: `CanvasNodeTooltipConfig`. **Работает всегда.**\n3. **Поле `cellTooltip` / `headerCellTooltip` в `columnConfig`** — на уровне конфигурации колонки. Может быть строкой, объектом или функцией `(context) => config | null`. **Работает только при `tooltip.enabled: true`.**\n\n**Формат конфига:** строка (только текст) или объект с обязательным полем `text` и опциональными пропсами `Tooltip` (`placement`, `view` и т.д.; без `opened`, `target`, `style`), а также `mouseEnterDelay` / `mouseLeaveDelay` для per-node задержек.\n\nПо умолчанию текст рендерится с `white-space: normal` — переносы строк (`\\n`) в `text` схлопываются в пробел. Чтобы сохранить переносы (например, в многострочных подсказках), добавьте в объектную форму конфига `preserveLineBreaks: true` — тогда к тексту тултипа применится `white-space: pre-line`. Флаг выключен по умолчанию и не меняет поведение существующих строковых тултипов.\n\n## Модуль tableConfig.tooltip\n\nГлобальные настройки тултипа вынесены в `tableConfig.tooltip` (тип `TableConfigTooltip`):\n\n- **tooltip.enabled** — включает колоночные/кастомные тултипы (`cellTooltip`, `headerCellTooltip`). По умолчанию `false`. Внутренние тултипы (проп `tooltip` на Canvas-элементе и маппинг по `nodeId`) работают всегда, независимо от `enabled`.\n- **tooltip.mouseEnterDelay** — глобальная задержка перед показом (мс, по умолчанию `500`). Per-node переопределяет.\n- **tooltip.mouseLeaveDelay** — глобальная задержка перед скрытием (мс, по умолчанию `0`). Per-node переопределяет.\n- **tooltip.minWidth** — глобальная минимальная ширина тултипа (число = px, строка с единицей отдаётся как есть). Действует на все canvas-тултипы, включая авто-тултип `Canvas.Text`. Per-node переопределяет.\n- **tooltip.maxWidth** — глобальная максимальная ширина тултипа (число = px, строка с единицей отдаётся как есть). Действует на все canvas-тултипы, включая авто-тултип `Canvas.Text`. Per-node переопределяет.\n\nПример:\n\n```tsx\ntableConfig={{\n tooltip: {\n enabled: true,\n mouseEnterDelay: 300,\n maxWidth: 440,\n },\n}}\n```\n\n## Колоночные cellTooltip / headerCellTooltip\n\nЗадаются в `columnConfig` на уровне колонки. Значение — строка, объект или функция. Требуют `tooltip.enabled: true` в `tableConfig`:\n\n```tsx\nconst columnConfig = [\n {\n key: 'task',\n name: 'Title',\n // Строка — простой текст\n headerCellTooltip: 'Название задачи',\n // Функция — динамический конфиг\n cellTooltip: ({ row, column }) => {\n return `${column.name}: ${row.task}`;\n },\n },\n];\n```\n\nКонтекст функции `cellTooltip` содержит: `row`, `column`, `ctxs`, `refTable`, `colInd`, `rowInd`, `theme`.\nКонтекст функции `headerCellTooltip` содержит: `column`, `ctxs`, `refTable`, `colInd`, `theme`.\n\n---\n\n## Типы\n\n### CanvasNodeTooltipConfig\n\nПроп `tooltip` на Canvas-элементах и базовый формат конфига. Строка (текст) или объект с `text` и опциональными пропсами Tooltip.\n\n```typescript\ntype CanvasNodeTooltipConfig =\n | string\n | (CanvasNodeTooltipProps & {\n /** Текст тултипа (только string, не ReactNode). */\n text: string;\n /** Задержка перед показом (мс). По умолчанию 0. */\n mouseEnterDelay?: number;\n /** Задержка перед скрытием после ухода мыши (мс). По умолчанию 0. */\n mouseLeaveDelay?: number;\n });\n```\n\n### CanvasNodeTooltipProps\n\nПропсы Tooltip, которые можно задать через объектную форму конфига. Управляемые внутренне поля (`opened`, `target`, `style`, `text`, `mouseEnterDelay`, `mouseLeaveDelay`, `hoverTimeout`, `trigger`) исключены.\n\n```typescript\ntype CanvasNodeTooltipProps = Pick<\n TooltipProps,\n 'placement' | 'view' | 'minWidth' | 'maxWidth'\n> & {\n /** Сохранять переносы строк (\\n) в тексте тултипа через white-space: pre-line. @default false */\n preserveLineBreaks?: boolean;\n /**\n * Сдвиг тултипа по X (px) относительно центра ноды. Нужен, когда видимая\n * часть ноды смещена внутри неё (например, иконка прижата к краю кнопки).\n * @default 0\n */\n offsetX?: number;\n};\n```\n\n### TooltipConfigResult\n\nАлиас: `CanvasNodeTooltipConfig | null`. Используется как возвращаемый тип функциональной формы `cellTooltip` / `headerCellTooltip`.\n\n```typescript\ntype TooltipConfigResult = CanvasNodeTooltipConfig | null;\n```\n\n### TooltipData\n\nВнутренний результат резолвинга: текст, пропсы тултипа и per-node задержки. Возвращается из `resolveTooltipData` и передаётся в `usePortalHover`.\n\n```typescript\ninterface TooltipData {\n tooltipText: string;\n tooltipProps?: CanvasNodeTooltipProps;\n mouseEnterDelay?: number;\n mouseLeaveDelay?: number;\n}\n```\n\n### TableConfigTooltip\n\nГлобальные настройки тултипа в `tableConfig.tooltip`.\n\n```typescript\ntype TableConfigTooltip = {\n /**\n * Включить/выключить колоночные и кастомные тултипы (cellTooltip, headerCellTooltip).\n * Внутренние тултипы (drag-иконка в шапке и другие по nodeId) работают всегда.\n * @default false\n */\n enabled?: boolean;\n /** Глобальная задержка перед показом тултипа (мс). Per-node переопределяет. @default 500 */\n mouseEnterDelay?: number;\n /** Глобальная задержка перед скрытием тултипа (мс). Per-node переопределяет. @default 0 */\n mouseLeaveDelay?: number;\n /**\n * Минимальная ширина тултипа. Число трактуется как px, строка с единицей\n * (например '20rem', '50%') отдаётся как есть. Действует на все canvas-тултипы,\n * включая авто-тултип Canvas.Text. Если ширина задана на самом тултипе\n * (per-node), приоритет у неё.\n */\n minWidth?: number | string;\n /**\n * Максимальная ширина тултипа. Число трактуется как px, строка с единицей\n * (например '20rem', '50%') отдаётся как есть. Действует на все canvas-тултипы,\n * включая авто-тултип Canvas.Text. Если ширина задана на самом тултипе\n * (per-node), приоритет у неё.\n */\n maxWidth?: number | string;\n};\n```\n\n### CanvasPortalHoverDetail\n\nОбъект события hover по canvas-элементу. Содержит координаты, размеры, `nodeId`, `source` (`'header'` | `'cell'`), `tooltipFromNode` и `tooltipContext` (column, row, ctxs, refTable).\n\n```typescript\ninterface CanvasPortalHoverDetail<\n TContext extends TooltipContextShape = TooltipContextShape\n> {\n visible: boolean;\n x: number;\n y: number;\n width: number;\n height: number;\n node?: CanvasNode | null;\n nodeId?: string;\n source?: CanvasPortalSource;\n originId?: string;\n /** column, row, ctxs, refTable — тип задаётся generic TContext */\n tooltipContext?: TContext;\n /** Конфиг с ноды (проп tooltip на Canvas-элементе). */\n tooltipFromNode?: CanvasNodeTooltipConfig;\n /**\n * Приоритет события. usePortalHover не заменяет активный тултип с бо́льшим приоритетом.\n * - 1 — canvas-нода (CanvasHoverController)\n * - 0 — колоночный тултип (useItemHoveredHandler)\n * @default 0\n */\n priority?: number;\n}\n```",
53739
54117
  "api": [
53740
54118
  {
53741
54119
  "typeName": "CanvasNodeTooltipConfig",
@@ -53743,7 +54121,7 @@
53743
54121
  },
53744
54122
  {
53745
54123
  "typeName": "CanvasNodeTooltipProps",
53746
- "source": "type CanvasNodeTooltipProps = Pick<\n TooltipProps,\n 'placement' | 'view' | 'minWidth' | 'maxWidth'\n> & {\n /** Сохранять переносы строк (\\n) в тексте тултипа через white-space: pre-line. @default false */\n preserveLineBreaks?: boolean;\n};"
54124
+ "source": "type CanvasNodeTooltipProps = Pick<\n TooltipProps,\n 'placement' | 'view' | 'minWidth' | 'maxWidth'\n> & {\n /** Сохранять переносы строк (\\n) в тексте тултипа через white-space: pre-line. @default false */\n preserveLineBreaks?: boolean;\n /**\n * Сдвиг тултипа по X (px) относительно центра ноды. Нужен, когда видимая\n * часть ноды смещена внутри неё (например, иконка прижата к краю кнопки).\n * @default 0\n */\n offsetX?: number;\n};"
53747
54125
  },
53748
54126
  {
53749
54127
  "typeName": "TooltipConfigResult",
@@ -53755,7 +54133,7 @@
53755
54133
  },
53756
54134
  {
53757
54135
  "typeName": "TableConfigTooltip",
53758
- "source": "type TableConfigTooltip = {\n /**\n * Включить/выключить колоночные и кастомные тултипы (cellTooltip, headerCellTooltip).\n * Внутренние тултипы (drag-иконка в шапке и другие по nodeId) работают всегда.\n * @default false\n */\n enabled?: boolean;\n /** Глобальная задержка перед показом тултипа (мс). Per-node переопределяет. @default 500 */\n mouseEnterDelay?: number;\n /** Глобальная задержка перед скрытием тултипа (мс). Per-node переопределяет. @default 0 */\n mouseLeaveDelay?: number;\n};"
54136
+ "source": "type TableConfigTooltip = {\n /**\n * Включить/выключить колоночные и кастомные тултипы (cellTooltip, headerCellTooltip).\n * Внутренние тултипы (drag-иконка в шапке и другие по nodeId) работают всегда.\n * @default false\n */\n enabled?: boolean;\n /** Глобальная задержка перед показом тултипа (мс). Per-node переопределяет. @default 500 */\n mouseEnterDelay?: number;\n /** Глобальная задержка перед скрытием тултипа (мс). Per-node переопределяет. @default 0 */\n mouseLeaveDelay?: number;\n /**\n * Минимальная ширина тултипа. Число трактуется как px, строка с единицей\n * (например '20rem', '50%') отдаётся как есть. Действует на все canvas-тултипы,\n * включая авто-тултип Canvas.Text. Если ширина задана на самом тултипе\n * (per-node), приоритет у неё.\n */\n minWidth?: number | string;\n /**\n * Максимальная ширина тултипа. Число трактуется как px, строка с единицей\n * (например '20rem', '50%') отдаётся как есть. Действует на все canvas-тултипы,\n * включая авто-тултип Canvas.Text. Если ширина задана на самом тултипе\n * (per-node), приоритет у неё.\n */\n maxWidth?: number | string;\n};"
53759
54137
  },
53760
54138
  {
53761
54139
  "typeName": "CanvasPortalHoverDetail",
@@ -53765,33 +54143,39 @@
53765
54143
  "stories": [
53766
54144
  {
53767
54145
  "exportName": "DefaultTooltipStory",
53768
- "displayName": "Встроенный тултип — hover на drag-иконку (⠿) в шапке колонки",
54146
+ "displayName": "Встроенный тултип (drag-иконка в шапке)",
53769
54147
  "type": "full-code",
53770
54148
  "code": "import { createRows, type Row } from '@df-storybook/data/tableData';\nimport { ColumnConfig, TableCanvas } from '@ui-kit/components/TableCanvas';\nimport React, { useMemo, useState } from 'react';\n\n${getFuncAsString(\n 'packages/storybook/src/stories/TableCanvas/TableCanvas.Tooltip/TableCanvasTooltip.stories.tsx',\n 'ExampleDefaultTooltip',\n)}"
53771
54149
  },
53772
54150
  {
53773
54151
  "exportName": "ColumnTooltipStringStory",
53774
- "displayName": "cellTooltip (строка) — hover на ячейки Title / Developer",
54152
+ "displayName": "cellTooltip: строка",
53775
54153
  "type": "full-code",
53776
54154
  "code": "import { createRows, type Row } from '@df-storybook/data/tableData';\nimport { ColumnConfig, TableCanvas } from '@ui-kit/components/TableCanvas';\nimport React, { useMemo, useState } from 'react';\n\n${getFuncAsString(\n 'packages/storybook/src/stories/TableCanvas/TableCanvas.Tooltip/TableCanvasTooltip.stories.tsx',\n 'ExampleColumnTooltipString',\n)}"
53777
54155
  },
53778
54156
  {
53779
54157
  "exportName": "ColumnTooltipObjectStory",
53780
- "displayName": "cellTooltip (объект) — hover на ячейки % Complete",
54158
+ "displayName": "cellTooltip: объект",
53781
54159
  "type": "full-code",
53782
54160
  "code": "import { createRows, type Row } from '@df-storybook/data/tableData';\nimport { ColumnConfig, TableCanvas } from '@ui-kit/components/TableCanvas';\nimport React, { useMemo, useState } from 'react';\n\n${getFuncAsString(\n 'packages/storybook/src/stories/TableCanvas/TableCanvas.Tooltip/TableCanvasTooltip.stories.tsx',\n 'ExampleColumnTooltipObject',\n)}"
53783
54161
  },
53784
54162
  {
53785
54163
  "exportName": "ColumnTooltipMultilineStory",
53786
- "displayName": "cellTooltip (preserveLineBreaks) — hover на ячейки Title",
54164
+ "displayName": "cellTooltip: preserveLineBreaks",
53787
54165
  "type": "full-code",
53788
54166
  "code": "import { createRows, type Row } from '@df-storybook/data/tableData';\nimport { ColumnConfig, TableCanvas } from '@ui-kit/components/TableCanvas';\nimport React, { useMemo, useState } from 'react';\n\n${getFuncAsString(\n 'packages/storybook/src/stories/TableCanvas/TableCanvas.Tooltip/TableCanvasTooltip.stories.tsx',\n 'ExampleColumnTooltipMultiline',\n)}"
53789
54167
  },
53790
54168
  {
53791
54169
  "exportName": "ButtonWithTooltipStory",
53792
- "displayName": "Canvas.Button tooltip — hover на кнопку «Подробнее»",
54170
+ "displayName": "Canvas.Button: tooltip",
53793
54171
  "type": "full-code",
53794
54172
  "code": "import { createRows, type Row } from '@df-storybook/data/tableData';\nimport { Canvas, ColumnConfig, TableCanvas } from '@ui-kit/components/TableCanvas';\nimport React, { useMemo, useState } from 'react';\n\n${getFuncAsString(\n 'packages/storybook/src/stories/TableCanvas/TableCanvas.Tooltip/TableCanvasTooltip.stories.tsx',\n 'ExampleButtonWithTooltip',\n)}"
54173
+ },
54174
+ {
54175
+ "exportName": "GlobalTooltipWidthStory",
54176
+ "displayName": "Ширина тултипа: глобальная и своя",
54177
+ "type": "full-code",
54178
+ "code": "import { createRows, type Row } from '@df-storybook/data/tableData';\nimport { Canvas, ColumnConfig, TableCanvas } from '@daisforge/ui/components/TableCanvas';\nimport React, { useMemo, useState } from 'react';\n\n${getFuncAsString(\n 'packages/storybook/src/stories/TableCanvas/TableCanvas.Tooltip/TableCanvasTooltip.stories.tsx',\n 'ExampleGlobalTooltipWidth',\n)}"
53795
54179
  }
53796
54180
  ]
53797
54181
  },
@@ -55632,7 +56016,7 @@
55632
56016
  },
55633
56017
  "MergedCellsAlign": {
55634
56018
  "name": "MergedCellsAlign",
55635
- "definition": "export type MergedCellsAlign = {\n /** По горизонтали. @default из `contentAlign` колонки, иначе 'left' */\n horizontal?: 'left' | 'center' | 'right';\n /** По вертикали. @default 'center' */\n vertical?: 'top' | 'center' | 'bottom';\n};",
56019
+ "definition": "export type MergedCellsAlign = {\n /** По горизонтали. @default из `contentFormat.alignContent` колонки, иначе 'left' */\n horizontal?: 'left' | 'center' | 'right';\n /** По вертикали. @default 'center' */\n vertical?: 'top' | 'center' | 'bottom';\n};",
55636
56020
  "importPath": "@daisforge/ui/components/TableCanvas",
55637
56021
  "importStatement": "import { MergedCellsAlign } from '@daisforge/ui/components/TableCanvas';",
55638
56022
  "sourceFile": "packages/ui-kit/src/components/TableCanvas/types/merged-cells.type.ts"
@@ -56864,7 +57248,7 @@
56864
57248
  },
56865
57249
  "CanvasNodeTooltipProps": {
56866
57250
  "name": "CanvasNodeTooltipProps",
56867
- "definition": "export type CanvasNodeTooltipProps = Pick<\n TooltipProps,\n 'placement' | 'view' | 'minWidth' | 'maxWidth'\n> & {\n /** Сохранять переносы строк (\\n) в тексте тултипа через white-space: pre-line. @default false */\n preserveLineBreaks?: boolean;\n};",
57251
+ "definition": "export type CanvasNodeTooltipProps = Pick<\n TooltipProps,\n 'placement' | 'view' | 'minWidth' | 'maxWidth'\n> & {\n /** Сохранять переносы строк (\\n) в тексте тултипа через white-space: pre-line. @default false */\n preserveLineBreaks?: boolean;\n /**\n * Сдвиг тултипа по X (px) относительно центра ноды. Нужен, когда видимая\n * часть ноды смещена внутри неё (например, иконка прижата к краю кнопки).\n * @default 0\n */\n offsetX?: number;\n};",
56868
57252
  "importPath": "@daisforge/ui/components/TableCanvas",
56869
57253
  "importStatement": "import { CanvasNodeTooltipProps } from '@daisforge/ui/components/TableCanvas';",
56870
57254
  "sourceFile": "packages/ui-kit/src/components/TableGlide/lib/canvas/utils/portalHoverEvents.ts"
@@ -57200,7 +57584,7 @@
57200
57584
  },
57201
57585
  "TableCanvas.ColumnsControlConfig": {
57202
57586
  "name": "ColumnsControlConfig",
57203
- "definition": "export type ColumnsControlConfig = {\n enable: boolean;\n /**\n * @default enable\n */\n hiding?: boolean;\n /**\n * @default enable\n */\n pinning?: boolean;\n /**\n * @default enable\n */\n reorderingAside?: boolean;\n /**\n * reorderingHeader - активация изменения порядка колонок посредством перемещения шапок колонок таблицы\n */\n /**\n * @default enable\n */\n reorderingHeader?: boolean;\n onReorderingHeader?: (params: {\n newOrder: string[];\n sourceKey: string;\n targetKey: string;\n }) => void;\n\n columnsLabel?: Record<\n string,\n ReactNode | ((isHidden: boolean, isPinned: boolean) => ReactNode)\n >;\n\n /**\n * Виртуализация списка колонок в правом сайдбаре: в DOM держатся только\n * видимые строки списка. false — отключить полностью; { minCount } —\n * включать, когда строк в списке не меньше порога.\n * @default { minCount: 30 }\n */\n virtualization?: boolean | { minCount?: number };\n\n orderDefault?: string[];\n\n pinnedDefault?: string[];\n disablePinning?: string[];\n\n hiddenDefault?: string[];\n disableHiding?: string[];\n\n onConfirm?: (\n params: {\n pinned: string[];\n order: string[];\n hidden: string[];\n changed: { pinned?: 'pinned'; order?: 'order'; hidden?: 'hidden' };\n },\n setters: {\n setColumnsOrder: (value: React.SetStateAction<string[]>) => void;\n setPinnedCols: (value: React.SetStateAction<string[]>) => void;\n setHiddenCols: (value: React.SetStateAction<string[]>) => void;\n },\n ) => void;\n /**\n * DomMetadata для кнопок закрепления столбцов\n */\n pinDomMetadata?: DomMetadata;\n /**\n * DomMetadata для свитчеров скрытия/показа столбцов\n */\n switchDomMetadata?: DomMetadata;\n};",
57587
+ "definition": "export type ColumnsControlConfig = {\n enable: boolean;\n /**\n * @default enable\n */\n hiding?: boolean;\n /**\n * @default enable\n */\n pinning?: boolean;\n /**\n * @default enable\n */\n reorderingAside?: boolean;\n /**\n * reorderingHeader - активация изменения порядка колонок посредством перемещения шапок колонок таблицы\n */\n /**\n * @default enable\n */\n reorderingHeader?: boolean;\n onReorderingHeader?: (params: {\n newOrder: string[];\n sourceKey: string;\n targetKey: string;\n }) => void;\n\n columnsLabel?: Record<\n string,\n ReactNode | ((isHidden: boolean, isPinned: boolean) => ReactNode)\n >;\n\n /**\n * Виртуализация списка колонок в правом сайдбаре: в DOM держатся только\n * видимые строки списка. false — отключить полностью; { minCount } —\n * включать, когда строк в списке не меньше порога.\n * @default { minCount: 30 }\n */\n virtualization?: boolean | { minCount?: number };\n\n orderDefault?: string[];\n\n pinnedDefault?: string[];\n disablePinning?: string[];\n\n hiddenDefault?: string[];\n disableHiding?: string[];\n /**\n * Индикатор скрытых столбцов: синяя полосатая линия в шапке на границе, за\n * которой скрыты столбцы. Двойной клик по линии раскрывает весь промежуток,\n * ресайз на этой границе работает как обычно.\n * @default hiding\n */\n hiddenColumnsIndicator?: boolean;\n /**\n * Уведомление о раскрытии промежутка двойным кликом по индикатору скрытых\n * столбцов. Само раскрытие (снятие скрытия) обёртка делает сама; колбэк нужен,\n * чтобы внешний потребитель мог подписаться на это событие и узнать, какие\n * столбцы раскрылись и между какими видимыми колонками стояла линия.\n */\n onHiddenColumnsIndicatorExpand?: (\n info: HiddenColumnsIndicatorExpandInfo,\n ) => void;\n\n onConfirm?: (\n params: {\n pinned: string[];\n order: string[];\n hidden: string[];\n changed: { pinned?: 'pinned'; order?: 'order'; hidden?: 'hidden' };\n },\n setters: {\n setColumnsOrder: (value: React.SetStateAction<string[]>) => void;\n setPinnedCols: (value: React.SetStateAction<string[]>) => void;\n setHiddenCols: (value: React.SetStateAction<string[]>) => void;\n },\n ) => void;\n /**\n * DomMetadata для кнопок закрепления столбцов\n */\n pinDomMetadata?: DomMetadata;\n /**\n * DomMetadata для свитчеров скрытия/показа столбцов\n */\n switchDomMetadata?: DomMetadata;\n};",
57204
57588
  "internal": true,
57205
57589
  "importNotice": "Тип \"ColumnsControlConfig\" не экспортируется из публичной точки входа — импортировать его нельзя. Определение приведено для понимания структуры: опишите нужную форму по месту либо возьмите её из типа, который экспортирован.",
57206
57590
  "sourceFile": "packages/ui-kit/src/components/TableCanvas/feature-column-control/types.ts"
@@ -57830,7 +58214,7 @@
57830
58214
  },
57831
58215
  "TableConfigTooltip": {
57832
58216
  "name": "TableConfigTooltip",
57833
- "definition": "export type TableConfigTooltip = {\n /**\n * Включить/выключить колоночные и кастомные тултипы (cellTooltip, headerCellTooltip).\n * Внутренние тултипы (drag-иконка в шапке и другие по nodeId) работают всегда.\n * @default false\n */\n enabled?: boolean;\n /** Глобальная задержка перед показом тултипа (мс). Per-node переопределяет. @default 500 */\n mouseEnterDelay?: number;\n /** Глобальная задержка перед скрытием тултипа (мс). Per-node переопределяет. @default 0 */\n mouseLeaveDelay?: number;\n};",
58217
+ "definition": "export type TableConfigTooltip = {\n /**\n * Включить/выключить колоночные и кастомные тултипы (cellTooltip, headerCellTooltip).\n * Внутренние тултипы (drag-иконка в шапке и другие по nodeId) работают всегда.\n * @default false\n */\n enabled?: boolean;\n /** Глобальная задержка перед показом тултипа (мс). Per-node переопределяет. @default 500 */\n mouseEnterDelay?: number;\n /** Глобальная задержка перед скрытием тултипа (мс). Per-node переопределяет. @default 0 */\n mouseLeaveDelay?: number;\n /**\n * Минимальная ширина тултипа. Число трактуется как px, строка с единицей\n * (например '20rem', '50%') отдаётся как есть. Действует на все canvas-тултипы,\n * включая авто-тултип Canvas.Text. Если ширина задана на самом тултипе\n * (per-node), приоритет у неё.\n */\n minWidth?: number | string;\n /**\n * Максимальная ширина тултипа. Число трактуется как px, строка с единицей\n * (например '20rem', '50%') отдаётся как есть. Действует на все canvas-тултипы,\n * включая авто-тултип Canvas.Text. Если ширина задана на самом тултипе\n * (per-node), приоритет у неё.\n */\n maxWidth?: number | string;\n};",
57834
58218
  "importPath": "@daisforge/ui/components/TableCanvas",
57835
58219
  "importStatement": "import { TableConfigTooltip } from '@daisforge/ui/components/TableCanvas';",
57836
58220
  "sourceFile": "packages/ui-kit/src/components/TableCanvas/types/table-config.type.ts"