@daisforge/ui 1.17.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.
- package/chunks/{AnalyticalWidget-BWcBjoNh.mjs → AnalyticalWidget-Cdo6_s1Y.mjs} +165 -163
- package/chunks/AnalyticalWidget-wke3Jm3X.cjs +43 -0
- package/chunks/{ApprovalCenter-CGs7n-2C.cjs → ApprovalCenter-CAcC43zn.cjs} +1 -1
- package/chunks/{ApprovalCenter-BqN8Zjol.mjs → ApprovalCenter-DxcvzR8q.mjs} +1 -1
- package/chunks/{BlockTitle-o2QTRA7D.cjs → BlockTitle-BEIxiECX.cjs} +1 -1
- package/chunks/{BlockTitle-BM2EE1b1.mjs → BlockTitle-BZxOEdTc.mjs} +1 -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
- 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
- package/chunks/{FiltersActions-CKimtYsU.cjs → FiltersActions-BKJJH6Mu.cjs} +1 -1
- package/chunks/{FiltersActions-C5OGUDDx.mjs → FiltersActions-CFStLRsU.mjs} +3 -3
- package/chunks/{GridDND-DkL6-TgS.cjs → GridDND-DV-1g1sI.cjs} +1 -1
- package/chunks/{GridDND-D9T2wqLt.mjs → GridDND-UMUi8M_Q.mjs} +1 -1
- package/chunks/{ListOfFilters-B8XF6KiI.cjs → ListOfFilters-DJvnT9kw.cjs} +1 -1
- package/chunks/{ListOfFilters-BEDW_v5t.mjs → ListOfFilters-DTAZ3wfQ.mjs} +2 -2
- package/chunks/{MassActions-C66ulAuq.mjs → MassActions-DSAaO1-u.mjs} +2 -2
- package/chunks/{MassActions-BHNmuh3s.cjs → MassActions-Z-48g81T.cjs} +1 -1
- package/chunks/{PageTitle-BEdQpyZh.cjs → PageTitle-Bh3g6FUT.cjs} +1 -1
- package/chunks/{PageTitle-BVbWaV52.mjs → PageTitle-CaqXfrrQ.mjs} +1 -1
- package/chunks/{Stories-DVh7iByM.cjs → Stories-CZXv_Ves.cjs} +1 -1
- package/chunks/{Stories-lNAuXVJN.mjs → Stories-Dlwle-SM.mjs} +1 -1
- package/chunks/{Table-C_1QGsh8.mjs → Table-B9OAyWAW.mjs} +4 -4
- package/chunks/{Table-C-lLZklk.cjs → Table-BwhzcFX1.cjs} +1 -1
- package/chunks/{TableCanvas--g37wjRi.mjs → TableCanvas-DkZAx-r9.mjs} +6104 -5386
- package/chunks/TableCanvas-QmXGAjPk.cjs +30 -0
- package/chunks/TableGlide-Bngn5_5l.cjs +1 -0
- package/chunks/{TableGlide-Cjcw7Wur.mjs → TableGlide-CkorJrl9.mjs} +2124 -1956
- package/chunks/styles-AUqEaroI.cjs +2 -0
- package/chunks/styles-C-1Srtr7.mjs +132 -0
- package/chunks/{vendor-BzEO8Fvp.cjs → vendor-BSEdLAmZ.cjs} +1049 -1309
- package/chunks/{vendor-DBRfVjyT.mjs → vendor-CA3z7N_7.mjs} +1053 -1313
- package/components/AiAgentPopover/AiAgentPopover.styled.d.ts +1 -0
- package/components/AnalyticalWidget/AnalyticalWidget.d.ts +5 -3
- package/components/AnalyticalWidget/components/AnalyticalWidgetButtons/AnalyticalWidgetIconButtonDots.d.ts +69 -11
- package/components/AnalyticalWidget/components/AnalyticalWidgetButtons/index.cjs +1 -1
- package/components/AnalyticalWidget/components/AnalyticalWidgetButtons/index.mjs +1 -1
- package/components/AnalyticalWidget/components/AnalyticalWidgetChips/index.cjs +1 -1
- package/components/AnalyticalWidget/components/AnalyticalWidgetChips/index.mjs +1 -1
- package/components/AnalyticalWidget/components/AnalyticalWidgetHeader/index.cjs +1 -1
- package/components/AnalyticalWidget/components/AnalyticalWidgetHeader/index.mjs +1 -1
- package/components/AnalyticalWidget/index.cjs +1 -1
- package/components/AnalyticalWidget/index.mjs +1 -1
- package/components/ApprovalCenter/components/index.cjs +1 -1
- package/components/ApprovalCenter/components/index.mjs +1 -1
- package/components/ApprovalCenter/index.cjs +1 -1
- package/components/ApprovalCenter/index.mjs +1 -1
- package/components/ApprovalCenter/styled.d.ts +1 -0
- package/components/AutocompleteSearch/index.cjs +1 -1
- package/components/AutocompleteSearch/index.mjs +1 -1
- package/components/BlockTitle/index.cjs +1 -1
- package/components/BlockTitle/index.mjs +1 -1
- package/components/BlockTitle/utils/index.cjs +1 -1
- package/components/BlockTitle/utils/index.mjs +1 -1
- package/components/Combobox/index.cjs +1 -1
- package/components/Combobox/index.mjs +1 -1
- package/components/DrawerDF/components/styled.d.ts +1 -0
- package/components/GridDND/index.cjs +1 -1
- package/components/GridDND/index.mjs +1 -1
- package/components/GridDND/utils/index.cjs +1 -1
- package/components/GridDND/utils/index.mjs +1 -1
- package/components/LeftPanel/styled.d.ts +1 -0
- package/components/ListOfFilters/index.cjs +1 -1
- package/components/ListOfFilters/index.mjs +1 -1
- package/components/MassActions/hooks/index.cjs +1 -1
- package/components/MassActions/hooks/index.mjs +1 -1
- package/components/MassActions/index.cjs +1 -1
- package/components/MassActions/index.mjs +1 -1
- package/components/MassActions/styled.d.ts +7 -2
- package/components/Notification/index.cjs +1 -1
- package/components/Notification/index.mjs +1 -1
- package/components/NumberFormat/NumberFormat.d.ts +48 -0
- package/components/NumberFormatAmount/NumberFormatAmount.styled.d.ts +48 -0
- package/components/PageTitle/index.cjs +1 -1
- package/components/PageTitle/index.mjs +1 -1
- package/components/PageTitle/utils/index.cjs +1 -1
- package/components/PageTitle/utils/index.mjs +1 -1
- package/components/PopoverDF/index.cjs +1 -1
- package/components/PopoverDF/index.mjs +1 -1
- package/components/PopupDF/index.cjs +1 -1
- package/components/PopupDF/index.d.ts +1 -1
- package/components/PopupDF/index.mjs +108 -94
- package/components/PopupDF/types.d.ts +1 -1
- package/components/Stories/components/StoriesBanner/index.cjs +1 -1
- package/components/Stories/components/StoriesBanner/index.mjs +1 -1
- package/components/Stories/components/StoriesContent/index.cjs +1 -1
- package/components/Stories/components/StoriesContent/index.mjs +1 -1
- package/components/Stories/components/StoriesPreview/index.cjs +1 -1
- package/components/Stories/components/StoriesPreview/index.mjs +1 -1
- package/components/Stories/components/StoriesProgress/index.cjs +1 -1
- package/components/Stories/components/StoriesProgress/index.mjs +1 -1
- package/components/Stories/components/StoriesViewer/index.cjs +1 -1
- package/components/Stories/components/StoriesViewer/index.mjs +1 -1
- package/components/Stories/index.cjs +1 -1
- package/components/Stories/index.mjs +1 -1
- package/components/Table/components/TableDropdown/index.cjs +1 -1
- package/components/Table/components/TableDropdown/index.mjs +1 -1
- package/components/Table/feature-collapse-table/CollapseTableButton.d.ts +2 -0
- package/components/Table/feature-collapse-table/index.cjs +1 -1
- package/components/Table/feature-collapse-table/index.mjs +1 -1
- package/components/Table/feature-column-control/ColumnsList/index.cjs +1 -1
- package/components/Table/feature-column-control/ColumnsList/index.mjs +1 -1
- package/components/Table/feature-column-control/index.cjs +1 -1
- package/components/Table/feature-column-control/index.mjs +1 -1
- package/components/Table/feature-column-control/styled.d.ts +1 -0
- package/components/Table/feature-columns-grouping/index.cjs +1 -1
- package/components/Table/feature-columns-grouping/index.mjs +1 -1
- package/components/Table/feature-context-menu/index.cjs +1 -1
- package/components/Table/feature-context-menu/index.mjs +1 -1
- package/components/Table/feature-edit/index.cjs +1 -1
- package/components/Table/feature-edit/index.mjs +1 -1
- package/components/Table/feature-edit/textEditor.styled.d.ts +48 -0
- package/components/Table/feature-filtering/combobox/index.cjs +1 -1
- package/components/Table/feature-filtering/combobox/index.mjs +1 -1
- package/components/Table/feature-filtering/filter-list-block/index.cjs +1 -1
- package/components/Table/feature-filtering/filter-list-block/index.mjs +1 -1
- package/components/Table/feature-filtering/header-filter-button/index.cjs +1 -1
- package/components/Table/feature-filtering/header-filter-button/index.mjs +1 -1
- package/components/Table/feature-filtering/header-filter-button/styles.d.ts +1 -0
- package/components/Table/feature-filtering/index.cjs +1 -1
- package/components/Table/feature-filtering/index.mjs +1 -1
- package/components/Table/feature-filtering/sidebar-filter-block/index.cjs +1 -1
- package/components/Table/feature-filtering/sidebar-filter-block/index.mjs +1 -1
- package/components/Table/feature-infinity-scroll/index.cjs +1 -1
- package/components/Table/feature-infinity-scroll/index.mjs +1 -1
- package/components/Table/feature-key-text/index.cjs +1 -1
- package/components/Table/feature-key-text/index.mjs +1 -1
- package/components/Table/feature-pagination/index.cjs +1 -1
- package/components/Table/feature-pagination/index.mjs +1 -1
- package/components/Table/feature-right-sidebar/index.cjs +1 -1
- package/components/Table/feature-right-sidebar/index.mjs +1 -1
- package/components/Table/feature-row-detail/handlers.d.ts +1 -0
- package/components/Table/feature-row-detail/index.cjs +1 -1
- package/components/Table/feature-row-detail/index.mjs +1 -1
- package/components/Table/feature-row-instruments/index.cjs +1 -1
- package/components/Table/feature-row-instruments/index.mjs +1 -1
- package/components/Table/feature-row-size/index.cjs +1 -1
- package/components/Table/feature-row-size/index.mjs +1 -1
- package/components/Table/feature-rows-grouping/index.cjs +1 -1
- package/components/Table/feature-rows-grouping/index.mjs +1 -1
- package/components/Table/feature-searching/index.cjs +1 -1
- package/components/Table/feature-searching/index.mjs +1 -1
- package/components/Table/feature-searching/styled.d.ts +1 -0
- package/components/Table/feature-select-row/index.cjs +1 -1
- package/components/Table/feature-select-row/index.mjs +1 -1
- package/components/Table/feature-sorting/index.cjs +1 -1
- package/components/Table/feature-sorting/index.mjs +1 -1
- package/components/Table/feature-sorting/styles.d.ts +1 -0
- package/components/Table/feature-table-settings/index.cjs +1 -1
- package/components/Table/feature-table-settings/index.mjs +1 -1
- package/components/Table/feature-tree/index.cjs +1 -1
- package/components/Table/feature-tree/index.mjs +1 -1
- package/components/Table/index.cjs +1 -1
- package/components/Table/index.mjs +1 -1
- package/components/Table/renders/formatCell/index.cjs +1 -1
- package/components/Table/renders/formatCell/index.mjs +1 -1
- package/components/Table/styles/index.cjs +1 -1
- package/components/Table/styles/index.mjs +1 -1
- package/components/Table/table-hooks/index.cjs +1 -1
- package/components/Table/table-hooks/index.mjs +1 -1
- package/components/Table/types/index.cjs +1 -1
- package/components/Table/types/index.mjs +1 -1
- package/components/Table/utils/index.cjs +1 -1
- package/components/Table/utils/index.mjs +1 -1
- package/components/Table/widgets/control-block/control-block-button.d.ts +3 -2
- package/components/Table/widgets/control-block/index.cjs +1 -1
- package/components/Table/widgets/control-block/index.mjs +1 -1
- package/components/Table/widgets/control-block/right-side/index.cjs +1 -1
- package/components/Table/widgets/control-block/right-side/index.mjs +1 -1
- package/components/Table/widgets/index.cjs +1 -1
- package/components/Table/widgets/index.mjs +1 -1
- package/components/Table/widgets/mass-actions/index.cjs +1 -1
- package/components/Table/widgets/mass-actions/index.mjs +1 -1
- package/components/TableCanvas/TableGlideInstance/adapters/column/index.cjs +1 -1
- package/components/TableCanvas/TableGlideInstance/adapters/column/index.mjs +1 -1
- package/components/TableCanvas/TableGlideInstance/adapters/index.cjs +1 -1
- package/components/TableCanvas/TableGlideInstance/adapters/index.mjs +1 -1
- package/components/TableCanvas/TableGlideInstance/index.cjs +1 -1
- package/components/TableCanvas/TableGlideInstance/index.mjs +2 -2
- package/components/TableCanvas/TableGlideInstance/type.d.ts +3 -1
- package/components/TableCanvas/TableGlideInstance/utils/column/index.cjs +1 -1
- package/components/TableCanvas/TableGlideInstance/utils/column/index.mjs +1 -1
- package/components/TableCanvas/TableGlideInstance/utils/index.cjs +1 -1
- package/components/TableCanvas/TableGlideInstance/utils/index.mjs +1 -1
- package/components/TableCanvas/components/SplitIconButton/index.cjs +1 -1
- package/components/TableCanvas/components/SplitIconButton/index.mjs +1 -1
- package/components/TableCanvas/components/TableDropdown/index.cjs +1 -1
- package/components/TableCanvas/components/TableDropdown/index.mjs +1 -1
- package/components/TableCanvas/feature-cell-transfer/index.cjs +1 -1
- package/components/TableCanvas/feature-cell-transfer/index.mjs +1 -1
- package/components/TableCanvas/feature-cell-transfer/types.d.ts +1 -1
- package/components/TableCanvas/feature-cell-transfer/utils/applyBlockEdit.d.ts +12 -0
- package/components/TableCanvas/feature-cell-transfer/utils/applyValuesToRows.d.ts +2 -1
- package/components/TableCanvas/feature-cell-transfer/utils/collectMatrixFromTargets.d.ts +1 -0
- package/components/TableCanvas/feature-cell-transfer/utils/collectTextMatrix.d.ts +1 -0
- package/components/TableCanvas/feature-cell-transfer/utils/resolveBlockOrigin.d.ts +13 -0
- package/components/TableCanvas/feature-cell-transfer/utils/snapDestToRowBlocks.d.ts +4 -0
- package/components/TableCanvas/feature-collapse-table/CollapseTableButton.d.ts +3 -2
- package/components/TableCanvas/feature-collapse-table/index.cjs +1 -1
- package/components/TableCanvas/feature-collapse-table/index.mjs +1 -1
- package/components/TableCanvas/feature-column-control/ColumnsList/index.cjs +1 -1
- package/components/TableCanvas/feature-column-control/ColumnsList/index.mjs +1 -1
- package/components/TableCanvas/feature-column-control/columnsRenderOrder.d.ts +1 -0
- package/components/TableCanvas/feature-column-control/groupDepth.d.ts +14 -0
- package/components/TableCanvas/feature-column-control/hiddenBoundaries.d.ts +4 -0
- package/components/TableCanvas/feature-column-control/index.cjs +1 -1
- package/components/TableCanvas/feature-column-control/index.d.ts +2 -0
- package/components/TableCanvas/feature-column-control/index.mjs +4 -2
- package/components/TableCanvas/feature-column-control/styled.d.ts +1 -0
- package/components/TableCanvas/feature-column-control/types.d.ts +10 -0
- package/components/TableCanvas/feature-column-control/useHiddenColumnsIndicator.d.ts +19 -0
- package/components/TableCanvas/feature-columns-grouping/index.cjs +1 -1
- package/components/TableCanvas/feature-columns-grouping/index.mjs +1 -1
- package/components/TableCanvas/feature-columns-grouping/useLastLvlColumnConfig.d.ts +5 -1
- package/components/TableCanvas/feature-content-state/index.cjs +1 -1
- package/components/TableCanvas/feature-content-state/index.mjs +1 -1
- package/components/TableCanvas/feature-context-menu/index.cjs +1 -1
- package/components/TableCanvas/feature-context-menu/index.mjs +1 -1
- package/components/TableCanvas/feature-edit/index.cjs +1 -1
- package/components/TableCanvas/feature-edit/index.mjs +3 -3
- package/components/TableCanvas/feature-filtering/combobox/index.cjs +1 -1
- package/components/TableCanvas/feature-filtering/combobox/index.mjs +2 -2
- package/components/TableCanvas/feature-filtering/filter-list-block/index.cjs +1 -1
- package/components/TableCanvas/feature-filtering/filter-list-block/index.mjs +2 -2
- package/components/TableCanvas/feature-filtering/header-filter-button/index.cjs +1 -1
- package/components/TableCanvas/feature-filtering/header-filter-button/index.mjs +1 -1
- package/components/TableCanvas/feature-filtering/header-filter-button/styles.d.ts +1 -0
- package/components/TableCanvas/feature-filtering/index.cjs +1 -1
- package/components/TableCanvas/feature-filtering/index.mjs +3 -3
- package/components/TableCanvas/feature-filtering/sidebar-filter-block/index.cjs +1 -1
- package/components/TableCanvas/feature-filtering/sidebar-filter-block/index.mjs +1 -1
- package/components/TableCanvas/feature-infinity-scroll/index.cjs +1 -1
- package/components/TableCanvas/feature-infinity-scroll/index.mjs +3 -3
- package/components/TableCanvas/feature-key-text/index.cjs +1 -1
- package/components/TableCanvas/feature-key-text/index.mjs +1 -1
- package/components/TableCanvas/feature-notifications/index.cjs +1 -1
- package/components/TableCanvas/feature-notifications/index.mjs +1 -1
- package/components/TableCanvas/feature-pagination/index.cjs +1 -1
- package/components/TableCanvas/feature-pagination/index.mjs +1 -1
- package/components/TableCanvas/feature-popover-table/context/index.cjs +1 -1
- package/components/TableCanvas/feature-popover-table/context/index.mjs +1 -1
- package/components/TableCanvas/feature-popover-table/hooks/index.cjs +1 -1
- package/components/TableCanvas/feature-popover-table/hooks/index.mjs +1 -1
- package/components/TableCanvas/feature-popover-table/index.cjs +1 -1
- package/components/TableCanvas/feature-popover-table/index.mjs +4 -4
- package/components/TableCanvas/feature-popover-table/utils/index.cjs +1 -1
- package/components/TableCanvas/feature-popover-table/utils/index.mjs +1 -1
- package/components/TableCanvas/feature-right-sidebar/index.cjs +1 -1
- package/components/TableCanvas/feature-right-sidebar/index.mjs +1 -1
- package/components/TableCanvas/feature-row-detail/handlers.d.ts +1 -0
- package/components/TableCanvas/feature-row-detail/index.cjs +1 -1
- package/components/TableCanvas/feature-row-detail/index.mjs +1 -1
- package/components/TableCanvas/feature-row-instruments/index.cjs +1 -1
- package/components/TableCanvas/feature-row-instruments/index.mjs +1 -1
- package/components/TableCanvas/feature-row-markers/index.cjs +1 -1
- package/components/TableCanvas/feature-row-markers/index.mjs +1 -1
- package/components/TableCanvas/feature-row-size/index.cjs +1 -1
- package/components/TableCanvas/feature-row-size/index.mjs +1 -1
- package/components/TableCanvas/feature-rows-grouping/getColsAfterRowsGrouping.d.ts +2 -1
- package/components/TableCanvas/feature-rows-grouping/index.cjs +1 -1
- package/components/TableCanvas/feature-rows-grouping/index.mjs +1 -1
- package/components/TableCanvas/feature-rows-grouping/mergedView.d.ts +14 -0
- package/components/TableCanvas/feature-rows-grouping/types.d.ts +4 -0
- package/components/TableCanvas/feature-searching/index.cjs +1 -1
- package/components/TableCanvas/feature-searching/index.mjs +1 -1
- package/components/TableCanvas/feature-searching/styled.d.ts +1 -0
- package/components/TableCanvas/feature-select-row/index.cjs +1 -1
- package/components/TableCanvas/feature-select-row/index.mjs +1 -1
- package/components/TableCanvas/feature-sorting/index.cjs +1 -1
- package/components/TableCanvas/feature-sorting/index.mjs +1 -1
- package/components/TableCanvas/feature-sorting/styles.d.ts +1 -0
- package/components/TableCanvas/feature-table-settings/index.cjs +1 -1
- package/components/TableCanvas/feature-table-settings/index.mjs +1 -1
- package/components/TableCanvas/feature-tooltip/constants.d.ts +1 -0
- package/components/TableCanvas/feature-tooltip/index.cjs +1 -1
- package/components/TableCanvas/feature-tooltip/index.mjs +1 -1
- package/components/TableCanvas/feature-tooltip/types.d.ts +2 -0
- package/components/TableCanvas/feature-tooltip/utils/index.cjs +1 -1
- package/components/TableCanvas/feature-tooltip/utils/index.mjs +4 -4
- package/components/TableCanvas/feature-tree/index.cjs +1 -1
- package/components/TableCanvas/feature-tree/index.mjs +1 -1
- package/components/TableCanvas/feature-tree/mergedSubRows.d.ts +5 -0
- package/components/TableCanvas/feature-tree/tree-disclosure-icons.d.ts +65 -0
- package/components/TableCanvas/feature-tree/types.d.ts +2 -0
- package/components/TableCanvas/index.cjs +1 -1
- package/components/TableCanvas/index.mjs +18 -18
- package/components/TableCanvas/renders/formatCell/index.cjs +1 -1
- package/components/TableCanvas/renders/formatCell/index.mjs +1 -1
- package/components/TableCanvas/renders/rowIconConfig.d.ts +6 -5
- package/components/TableCanvas/renders/styleConstants.d.ts +3 -1
- package/components/TableCanvas/renders/styled.d.ts +0 -1
- package/components/TableCanvas/renders/withSelectIcon.d.ts +3 -1
- package/components/TableCanvas/styles/index.cjs +1 -1
- package/components/TableCanvas/styles/index.mjs +1 -1
- package/components/TableCanvas/table-hooks/createMergeByValueRowSpan.d.ts +7 -0
- package/components/TableCanvas/table-hooks/createMergedRegionsResolver.d.ts +21 -0
- package/components/TableCanvas/table-hooks/index.cjs +1 -1
- package/components/TableCanvas/table-hooks/index.mjs +3 -3
- package/components/TableCanvas/table-hooks/resolveMergedView.d.ts +7 -0
- package/components/TableCanvas/table-hooks/useColumns.d.ts +1 -0
- package/components/TableCanvas/table-hooks/usePrepareTableConfig.d.ts +4 -1
- package/components/TableCanvas/types/column-config-internal.type.d.ts +4 -1
- package/components/TableCanvas/types/column-config.type.d.ts +2 -0
- package/components/TableCanvas/types/ctxs.type.d.ts +2 -0
- package/components/TableCanvas/types/glide-type.d.ts +1 -1
- package/components/TableCanvas/types/index.cjs +1 -1
- package/components/TableCanvas/types/index.d.ts +1 -0
- package/components/TableCanvas/types/index.mjs +1 -1
- package/components/TableCanvas/types/merged-cells.type.d.ts +4 -0
- package/components/TableCanvas/types/table-config.type.d.ts +17 -0
- package/components/TableCanvas/utils/index.cjs +1 -1
- package/components/TableCanvas/utils/index.mjs +1 -1
- package/components/TableCanvas/widgets/control-block/compression/index.cjs +1 -1
- package/components/TableCanvas/widgets/control-block/compression/index.mjs +1 -1
- package/components/TableCanvas/widgets/control-block/control-block-button.d.ts +3 -2
- package/components/TableCanvas/widgets/control-block/index.cjs +1 -1
- package/components/TableCanvas/widgets/control-block/index.mjs +3 -3
- package/components/TableCanvas/widgets/control-block/right-side/index.cjs +1 -1
- package/components/TableCanvas/widgets/control-block/right-side/index.mjs +1 -1
- package/components/TableCanvas/widgets/index.cjs +1 -1
- package/components/TableCanvas/widgets/index.mjs +1 -1
- package/components/TableCanvas/widgets/mass-actions/hooks/index.cjs +1 -1
- package/components/TableCanvas/widgets/mass-actions/hooks/index.mjs +1 -1
- package/components/TableCanvas/widgets/mass-actions/index.cjs +1 -1
- package/components/TableCanvas/widgets/mass-actions/index.mjs +1 -1
- package/components/TableCanvas/widgets/mass-actions/styled.d.ts +10 -4
- package/components/TableCanvasSharedConstants/index.cjs +1 -1
- package/components/TableCanvasSharedConstants/index.d.ts +1 -0
- package/components/TableCanvasSharedConstants/index.mjs +4 -3
- package/components/TableContract/index.cjs +1 -1
- package/components/TableContract/index.mjs +1 -1
- package/components/TableGlide/TableGlide.d.ts +1 -1
- package/components/TableGlide/constants.d.ts +1 -1
- package/components/TableGlide/hooks/selection/index.cjs +1 -1
- package/components/TableGlide/hooks/selection/index.mjs +1 -1
- package/components/TableGlide/hooks/useErrorCellRanges.d.ts +14 -0
- package/components/TableGlide/hooks/useItemHoveredHandler.d.ts +4 -1
- package/components/TableGlide/index.cjs +1 -1
- package/components/TableGlide/index.mjs +13 -13
- package/components/TableGlide/lib/canvas/cells/buttons/index.cjs +1 -1
- package/components/TableGlide/lib/canvas/cells/buttons/index.mjs +1 -1
- package/components/TableGlide/lib/canvas/cells/iconSprites/index.cjs +1 -1
- package/components/TableGlide/lib/canvas/cells/iconSprites/index.mjs +1 -1
- package/components/TableGlide/lib/canvas/cells/index.cjs +1 -1
- package/components/TableGlide/lib/canvas/cells/index.mjs +1 -1
- package/components/TableGlide/lib/canvas/cells/renderer/index.cjs +1 -1
- package/components/TableGlide/lib/canvas/cells/renderer/index.mjs +1 -1
- package/components/TableGlide/lib/canvas/components/index.d.ts +1 -0
- package/components/TableGlide/lib/canvas/core/helpers/index.cjs +1 -1
- package/components/TableGlide/lib/canvas/core/helpers/index.mjs +1 -1
- package/components/TableGlide/lib/canvas/core/index.cjs +1 -1
- package/components/TableGlide/lib/canvas/core/index.mjs +1 -1
- package/components/TableGlide/lib/canvas/hooks/index.cjs +1 -1
- package/components/TableGlide/lib/canvas/hooks/index.mjs +1 -1
- package/components/TableGlide/lib/canvas/index.cjs +1 -1
- package/components/TableGlide/lib/canvas/index.mjs +22 -22
- package/components/TableGlide/lib/canvas/miniflex/index.cjs +1 -1
- package/components/TableGlide/lib/canvas/miniflex/index.mjs +1 -1
- package/components/TableGlide/lib/canvas/primitives/CanvasEmbedIconButton.d.ts +2 -0
- package/components/TableGlide/lib/canvas/primitives/index.cjs +1 -1
- package/components/TableGlide/lib/canvas/primitives/index.mjs +1 -1
- package/components/TableGlide/lib/canvas/utils/index.cjs +1 -1
- package/components/TableGlide/lib/canvas/utils/index.mjs +2 -2
- package/components/TableGlide/lib/canvas/utils/portalHoverEvents.d.ts +1 -0
- package/components/TableGlide/theming/glide-colors.d.ts +1 -0
- package/components/TableGlide/theming/index.cjs +1 -1
- package/components/TableGlide/theming/index.mjs +1 -1
- package/components/TableGlide/theming/size-tokens.d.ts +1 -1
- package/components/TableGlide/theming/sizes.d.ts +2 -2
- package/components/TableGlide/types.d.ts +10 -0
- package/components/TableGlide/utils/findBlockOrigin.d.ts +5 -0
- package/components/TableGlide/utils/getRowSpan.d.ts +6 -0
- package/components/Tooltip/index.cjs +1 -1
- package/components/Tooltip/index.mjs +1 -1
- package/components/TourWidget/index.cjs +2 -2
- package/components/TourWidget/index.mjs +3 -3
- package/components/Typography/index.cjs +1 -1
- package/components/Typography/index.mjs +1 -1
- package/components/Widget/Widget.d.ts +1 -0
- package/components/Widget/components/WidgetIconButtonDots.d.ts +1 -0
- package/components/Widget/index.cjs +1 -1
- package/components/Widget/index.mjs +1 -1
- package/formComponents/FormCombobox/index.cjs +1 -1
- package/formComponents/FormCombobox/index.mjs +1 -1
- package/formComponents/FormDatePickers/FormDatePickerRange/ui/FormDatePickerRangeStyled.d.ts +2 -0
- package/formComponents/FormSwitch/index.cjs +1 -1
- package/formComponents/FormSwitch/index.mjs +1 -1
- package/formComponents/FormTextArea/ui/ButtonStyled.d.ts +1 -0
- package/formComponents/FormTextField/ui/IconButtonStyled.d.ts +1 -0
- package/index.cjs +1 -1
- package/index.mjs +14 -14
- package/layouts/FiltersActions/FiltersActions.d.ts +15 -6
- package/layouts/FiltersActions/components/FiltersButton.d.ts +4 -0
- package/layouts/FiltersActions/components/ResetAllFiltersButton.d.ts +6 -4
- package/layouts/FiltersActions/components/Tabs.d.ts +4 -2
- package/layouts/FiltersActions/hooks/index.cjs +1 -1
- package/layouts/FiltersActions/hooks/index.mjs +1 -1
- package/layouts/FiltersActions/index.cjs +1 -1
- package/layouts/FiltersActions/index.mjs +1 -1
- package/mcp-data/component-index.json +713 -159
- package/package.json +10 -9
- package/shared/ui/Search/styled.d.ts +1 -0
- package/styles/index.cjs +1 -1
- package/styles/index.mjs +1 -1
- package/themes/index.cjs +1 -1
- package/themes/index.mjs +2 -2
- package/chunks/AnalyticalWidget-z2HzQ4aA.cjs +0 -43
- package/chunks/TableCanvas-uzBMXlx6.cjs +0 -30
- package/chunks/TableGlide-DTBZ1jNA.cjs +0 -1
- package/chunks/styles-BBVEBDDw.mjs +0 -132
- package/chunks/styles-C-pJNMSQ.cjs +0 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generatedAt": "2026-09-
|
|
3
|
-
"libVersion": "1.
|
|
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",
|
|
@@ -778,7 +796,7 @@
|
|
|
778
796
|
},
|
|
779
797
|
{
|
|
780
798
|
"name": "view",
|
|
781
|
-
"type": "\"clear\" | \"default\" | \"secondary\" | \"accent\" | \"positive\" | \"warning\" | \"negative\" | \"dark\" | \"black\" | \"white\" | undefined",
|
|
799
|
+
"type": "\"clear\" | \"default\" | \"secondary\" | \"accent\" | \"positive\" | \"warning\" | \"negative\" | \"dark\" | \"black\" | \"white\" | \"gradient\" | undefined",
|
|
782
800
|
"required": false,
|
|
783
801
|
"description": ""
|
|
784
802
|
}
|
|
@@ -860,7 +878,7 @@
|
|
|
860
878
|
},
|
|
861
879
|
{
|
|
862
880
|
"name": "view",
|
|
863
|
-
"type": "\"default\" | \"secondary\" | \"accent\" | \"positive\" | \"warning\" | \"negative\" | \"info\" | undefined",
|
|
881
|
+
"type": "\"default\" | \"secondary\" | \"accent\" | \"positive\" | \"warning\" | \"negative\" | \"gradient\" | \"info\" | undefined",
|
|
864
882
|
"required": false,
|
|
865
883
|
"description": "",
|
|
866
884
|
"default": "'secondary'"
|
|
@@ -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",
|
|
@@ -5518,10 +5567,10 @@
|
|
|
5518
5567
|
},
|
|
5519
5568
|
{
|
|
5520
5569
|
"exportName": "Usage2",
|
|
5521
|
-
"displayName": "Использование в TableCanvas.
|
|
5570
|
+
"displayName": "Использование в TableCanvas.bigData.stories.tsx",
|
|
5522
5571
|
"type": "usage",
|
|
5523
|
-
"code": "<Checkbox\n checked={
|
|
5524
|
-
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.
|
|
5572
|
+
"code": "<Checkbox\n label=\"объединение (subRows merged)\"\n checked={withMerge}\n onChange={(e) => setWithMerge(e.target.checked)}\n />",
|
|
5573
|
+
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.CellsMerging/TableCanvas.bigData.stories.tsx"
|
|
5525
5574
|
},
|
|
5526
5575
|
{
|
|
5527
5576
|
"exportName": "Vendor1",
|
|
@@ -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",
|
|
@@ -9597,6 +9688,12 @@
|
|
|
9597
9688
|
"required": false,
|
|
9598
9689
|
"description": ""
|
|
9599
9690
|
},
|
|
9691
|
+
{
|
|
9692
|
+
"name": "overlayProps",
|
|
9693
|
+
"type": "DrawerOverlayProps | undefined",
|
|
9694
|
+
"required": false,
|
|
9695
|
+
"description": ""
|
|
9696
|
+
},
|
|
9600
9697
|
{
|
|
9601
9698
|
"name": "withBlur",
|
|
9602
9699
|
"type": "boolean | undefined",
|
|
@@ -10357,7 +10454,7 @@
|
|
|
10357
10454
|
},
|
|
10358
10455
|
{
|
|
10359
10456
|
"name": "view",
|
|
10360
|
-
"type": "\"default\" | \"clear\" | \"black\" | \"white\" | \"accent\" | \"positive\" | \"warning\" | \"negative\" | \"dark\" | \"secondary\" | undefined",
|
|
10457
|
+
"type": "\"default\" | \"clear\" | \"black\" | \"white\" | \"accent\" | \"positive\" | \"warning\" | \"negative\" | \"dark\" | \"secondary\" | \"gradient\" | undefined",
|
|
10361
10458
|
"required": false,
|
|
10362
10459
|
"description": ""
|
|
10363
10460
|
}
|
|
@@ -12381,7 +12478,7 @@
|
|
|
12381
12478
|
},
|
|
12382
12479
|
{
|
|
12383
12480
|
"name": "view",
|
|
12384
|
-
"type": "\"default\" | \"accent\" | \"secondary\" | \"positive\" | \"warning\" | \"negative\" | \"info\" | undefined",
|
|
12481
|
+
"type": "\"default\" | \"accent\" | \"secondary\" | \"positive\" | \"warning\" | \"negative\" | \"info\" | \"gradient\" | undefined",
|
|
12385
12482
|
"required": false,
|
|
12386
12483
|
"description": ""
|
|
12387
12484
|
}
|
|
@@ -13676,7 +13773,7 @@
|
|
|
13676
13773
|
},
|
|
13677
13774
|
{
|
|
13678
13775
|
"name": "view",
|
|
13679
|
-
"type": "\"default\" | \"accent\" | \"secondary\" | \"clear\" | \"positive\" | \"warning\" | \"negative\" | \"dark\" | \"black\" | \"white\" | undefined",
|
|
13776
|
+
"type": "\"default\" | \"accent\" | \"secondary\" | \"clear\" | \"positive\" | \"warning\" | \"negative\" | \"dark\" | \"black\" | \"white\" | \"gradient\" | undefined",
|
|
13680
13777
|
"required": false,
|
|
13681
13778
|
"description": ""
|
|
13682
13779
|
}
|
|
@@ -13850,7 +13947,7 @@
|
|
|
13850
13947
|
},
|
|
13851
13948
|
{
|
|
13852
13949
|
"name": "view",
|
|
13853
|
-
"type": "\"default\" | \"accent\" | \"secondary\" | \"clear\" | \"positive\" | \"warning\" | \"negative\" | \"dark\" | \"black\" | \"white\" | undefined",
|
|
13950
|
+
"type": "\"default\" | \"accent\" | \"secondary\" | \"clear\" | \"positive\" | \"warning\" | \"negative\" | \"dark\" | \"black\" | \"white\" | \"gradient\" | undefined",
|
|
13854
13951
|
"required": false,
|
|
13855
13952
|
"description": ""
|
|
13856
13953
|
}
|
|
@@ -14520,7 +14617,7 @@
|
|
|
14520
14617
|
},
|
|
14521
14618
|
{
|
|
14522
14619
|
"name": "view",
|
|
14523
|
-
"type": "\"default\" | \"positive\" | \"warning\" | \"negative\" | \"black\" | \"white\" | \"accent\" | \"secondary\" | \"clear\" | \"dark\" | undefined",
|
|
14620
|
+
"type": "\"default\" | \"positive\" | \"warning\" | \"negative\" | \"black\" | \"white\" | \"accent\" | \"secondary\" | \"clear\" | \"dark\" | \"gradient\" | undefined",
|
|
14524
14621
|
"required": false,
|
|
14525
14622
|
"description": ""
|
|
14526
14623
|
}
|
|
@@ -14751,7 +14848,7 @@
|
|
|
14751
14848
|
},
|
|
14752
14849
|
{
|
|
14753
14850
|
"name": "view",
|
|
14754
|
-
"type": "\"default\" | \"positive\" | \"warning\" | \"negative\" | \"black\" | \"white\" | \"accent\" | \"secondary\" | \"clear\" | \"dark\" | undefined",
|
|
14851
|
+
"type": "\"default\" | \"positive\" | \"warning\" | \"negative\" | \"black\" | \"white\" | \"accent\" | \"secondary\" | \"clear\" | \"dark\" | \"gradient\" | undefined",
|
|
14755
14852
|
"required": false,
|
|
14756
14853
|
"description": ""
|
|
14757
14854
|
}
|
|
@@ -16092,7 +16189,7 @@
|
|
|
16092
16189
|
},
|
|
16093
16190
|
{
|
|
16094
16191
|
"name": "view",
|
|
16095
|
-
"type": "\"default\" | \"positive\" | \"warning\" | \"negative\" | \"secondary\" | \"accent\" | \"clear\" | \"dark\" | \"black\" | \"white\" | undefined",
|
|
16192
|
+
"type": "\"default\" | \"positive\" | \"warning\" | \"negative\" | \"secondary\" | \"accent\" | \"clear\" | \"dark\" | \"black\" | \"white\" | \"gradient\" | undefined",
|
|
16096
16193
|
"required": false,
|
|
16097
16194
|
"description": ""
|
|
16098
16195
|
}
|
|
@@ -16238,7 +16335,14 @@
|
|
|
16238
16335
|
"folderName": "Modal",
|
|
16239
16336
|
"role": "primary",
|
|
16240
16337
|
"description": "Базовое модальное окно поверх контента без готовых layout-слотов",
|
|
16241
|
-
"props": [
|
|
16338
|
+
"props": [
|
|
16339
|
+
{
|
|
16340
|
+
"name": "focusTrapSelectors",
|
|
16341
|
+
"type": "string[] | undefined",
|
|
16342
|
+
"required": false,
|
|
16343
|
+
"description": "Селекторы дополнительных DOM-поддеревьев, которые считаются частью модального окна для focus trap.\nИспользуется для элементов, отрисованных через Portal или вне DOM-поддерева модального окна."
|
|
16344
|
+
}
|
|
16345
|
+
],
|
|
16242
16346
|
"propsTypeName": "ModalProps",
|
|
16243
16347
|
"sourceFile": "node_modules/@salutejs/sdds-finai/types/components/Modal/Modal.d.ts",
|
|
16244
16348
|
"type": "wrapper",
|
|
@@ -16611,7 +16715,7 @@
|
|
|
16611
16715
|
},
|
|
16612
16716
|
{
|
|
16613
16717
|
"name": "view",
|
|
16614
|
-
"type": "\"default\" | \"dark\" | \"black\" | \"white\" | \"accent\" | \"secondary\" | \"clear\" | \"positive\" | \"warning\" | \"negative\" | undefined",
|
|
16718
|
+
"type": "\"default\" | \"dark\" | \"black\" | \"white\" | \"accent\" | \"secondary\" | \"clear\" | \"positive\" | \"warning\" | \"negative\" | \"gradient\" | undefined",
|
|
16615
16719
|
"required": false,
|
|
16616
16720
|
"description": ""
|
|
16617
16721
|
}
|
|
@@ -17015,7 +17119,7 @@
|
|
|
17015
17119
|
},
|
|
17016
17120
|
{
|
|
17017
17121
|
"name": "view",
|
|
17018
|
-
"type": "\"default\" | \"dark\" | \"black\" | \"white\" | \"accent\" | \"secondary\" | \"clear\" | \"positive\" | \"warning\" | \"negative\" | undefined",
|
|
17122
|
+
"type": "\"default\" | \"dark\" | \"black\" | \"white\" | \"accent\" | \"secondary\" | \"clear\" | \"positive\" | \"warning\" | \"negative\" | \"gradient\" | undefined",
|
|
17019
17123
|
"required": false,
|
|
17020
17124
|
"description": ""
|
|
17021
17125
|
}
|
|
@@ -17406,6 +17510,12 @@
|
|
|
17406
17510
|
"role": "primary",
|
|
17407
17511
|
"description": "Расширенное модальное окно с compound-слотами: шапка, контент, футер, Left/Main",
|
|
17408
17512
|
"props": [
|
|
17513
|
+
{
|
|
17514
|
+
"name": "focusTrapSelectors",
|
|
17515
|
+
"type": "string[] | undefined",
|
|
17516
|
+
"required": false,
|
|
17517
|
+
"description": "Селекторы дополнительных DOM-поддеревьев, которые считаются частью модального окна для focus trap.\nИспользуется для элементов, отрисованных через Portal или вне DOM-поддерева модального окна."
|
|
17518
|
+
},
|
|
17409
17519
|
{
|
|
17410
17520
|
"name": "contentContainerProps",
|
|
17411
17521
|
"type": "Partial<ContainerProps> | undefined",
|
|
@@ -17714,7 +17824,7 @@
|
|
|
17714
17824
|
},
|
|
17715
17825
|
{
|
|
17716
17826
|
"name": "view",
|
|
17717
|
-
"type": "\"default\" | \"dark\" | \"black\" | \"white\" | \"accent\" | \"secondary\" | \"clear\" | \"positive\" | \"warning\" | \"negative\" | undefined",
|
|
17827
|
+
"type": "\"default\" | \"dark\" | \"black\" | \"white\" | \"accent\" | \"secondary\" | \"clear\" | \"positive\" | \"warning\" | \"negative\" | \"gradient\" | undefined",
|
|
17718
17828
|
"required": false,
|
|
17719
17829
|
"description": ""
|
|
17720
17830
|
}
|
|
@@ -17858,7 +17968,7 @@
|
|
|
17858
17968
|
},
|
|
17859
17969
|
{
|
|
17860
17970
|
"name": "view",
|
|
17861
|
-
"type": "\"default\" | \"dark\" | \"black\" | \"white\" | \"accent\" | \"secondary\" | \"clear\" | \"positive\" | \"warning\" | \"negative\" | undefined",
|
|
17971
|
+
"type": "\"default\" | \"dark\" | \"black\" | \"white\" | \"accent\" | \"secondary\" | \"clear\" | \"positive\" | \"warning\" | \"negative\" | \"gradient\" | undefined",
|
|
17862
17972
|
"required": false,
|
|
17863
17973
|
"description": ""
|
|
17864
17974
|
}
|
|
@@ -18315,6 +18425,12 @@
|
|
|
18315
18425
|
"required": false,
|
|
18316
18426
|
"description": "Иконка в верхней части модального окна"
|
|
18317
18427
|
},
|
|
18428
|
+
{
|
|
18429
|
+
"name": "focusTrapSelectors",
|
|
18430
|
+
"type": "string[] | undefined",
|
|
18431
|
+
"required": false,
|
|
18432
|
+
"description": "Селекторы дополнительных DOM-поддеревьев, которые считаются частью модального окна для focus trap.\nИспользуется для элементов, отрисованных через Portal или вне DOM-поддерева модального окна."
|
|
18433
|
+
},
|
|
18318
18434
|
{
|
|
18319
18435
|
"name": "contentContainerProps",
|
|
18320
18436
|
"type": "Partial<ContainerProps> | undefined",
|
|
@@ -19284,6 +19400,12 @@
|
|
|
19284
19400
|
"role": "primary",
|
|
19285
19401
|
"description": "Поле ввода с форматированием чисел (разделители, десятичные) и кнопкой очистки",
|
|
19286
19402
|
"props": [
|
|
19403
|
+
{
|
|
19404
|
+
"name": "suffix",
|
|
19405
|
+
"type": "string | undefined",
|
|
19406
|
+
"required": false,
|
|
19407
|
+
"description": "Суффикс текста в поле ввода."
|
|
19408
|
+
},
|
|
19287
19409
|
{
|
|
19288
19410
|
"name": "onClear",
|
|
19289
19411
|
"type": "(() => void) | undefined",
|
|
@@ -19797,6 +19919,12 @@
|
|
|
19797
19919
|
"description": "Задает выравнивание индикатора обязательности поля",
|
|
19798
19920
|
"default": "right"
|
|
19799
19921
|
},
|
|
19922
|
+
{
|
|
19923
|
+
"name": "suffix",
|
|
19924
|
+
"type": "string | undefined",
|
|
19925
|
+
"required": false,
|
|
19926
|
+
"description": "Суффикс текста в поле ввода."
|
|
19927
|
+
},
|
|
19800
19928
|
{
|
|
19801
19929
|
"name": "thousandSeparator",
|
|
19802
19930
|
"type": "string | boolean | undefined",
|
|
@@ -20859,7 +20987,14 @@
|
|
|
20859
20987
|
"folderName": "Popover",
|
|
20860
20988
|
"role": "primary",
|
|
20861
20989
|
"description": "Всплывающая панель у элемента-триггера для доп. контента, меню или подсказок",
|
|
20862
|
-
"props": [
|
|
20990
|
+
"props": [
|
|
20991
|
+
{
|
|
20992
|
+
"name": "stretchHeight",
|
|
20993
|
+
"type": "boolean | undefined",
|
|
20994
|
+
"required": false,
|
|
20995
|
+
"description": "Растянуть Popover до границы доступной области по вертикали."
|
|
20996
|
+
}
|
|
20997
|
+
],
|
|
20863
20998
|
"propsTypeName": "PopoverProps",
|
|
20864
20999
|
"sourceFile": "node_modules/@salutejs/sdds-finai/types/components/Popover/Popover.d.ts",
|
|
20865
21000
|
"type": "wrapper",
|
|
@@ -23530,7 +23665,7 @@
|
|
|
23530
23665
|
"exportName": "Usage2",
|
|
23531
23666
|
"displayName": "Использование в PopupDF.stories.tsx",
|
|
23532
23667
|
"type": "usage",
|
|
23533
|
-
"code": "<PopupDF.Footer>\n <FooterActions size
|
|
23668
|
+
"code": "<PopupDF.Footer>\n <FooterActions size=\"l\" />\n </PopupDF.Footer>",
|
|
23534
23669
|
"sourceFile": "packages/storybook/src/stories/PopupDF/PopupDF.stories.tsx"
|
|
23535
23670
|
}
|
|
23536
23671
|
]
|
|
@@ -23564,7 +23699,7 @@
|
|
|
23564
23699
|
"name": "rightBlock",
|
|
23565
23700
|
"type": "React.ReactNode",
|
|
23566
23701
|
"required": false,
|
|
23567
|
-
"description": "Кастомный слот в правой части header, слева от крестика закрытия.\nПрижимается к крестику; если контент широкий — «давит» на title/description\n(уходят в многоточие с тултипом). Максимальная высота — как у крестика\n(32px при `size='m'`, 24px при `size='s'`), ширина
|
|
23702
|
+
"description": "Кастомный слот в правой части header, слева от крестика закрытия.\nПрижимается к крестику; если контент широкий — «давит» на title/description\n(уходят в многоточие с тултипом). Максимальная высота — как у крестика\n(32px при `size='l'` и `size='m'`, 24px при `size='s'`), ширина не\nограничена."
|
|
23568
23703
|
},
|
|
23569
23704
|
{
|
|
23570
23705
|
"name": "showCloseButton",
|
|
@@ -23617,7 +23752,7 @@
|
|
|
23617
23752
|
"exportName": "Usage2",
|
|
23618
23753
|
"displayName": "Использование в PopupDF.stories.tsx",
|
|
23619
23754
|
"type": "usage",
|
|
23620
|
-
"code": "<PopupDF.Header\n
|
|
23755
|
+
"code": "<PopupDF.Header\n title=\"Заголовок PopupDF размера L\"\n description=\"Body S. Двигай за шапку, тяни за угол, разворачивай кнопкой.\"\n subHeader={\n <div style={sizeLSubHeaderStyle}>\n <IconInfoCircleOutline size=\"xs\" />\n <span>Кастомный слот</span>\n </div>\n }\n rightBlock={\n <IconButton\n size=\"xs\"\n view=\"secondary\"\n pin=\"circle-circle\"\n title={fullscreen ? 'Свернуть' : 'Развернуть'}\n onClick={() => (fullscreen ? collapse() : expand())}\n >\n <IconFullS size=\"xs\" />\n </IconButton>\n }\n />",
|
|
23621
23756
|
"sourceFile": "packages/storybook/src/stories/PopupDF/PopupDF.stories.tsx"
|
|
23622
23757
|
}
|
|
23623
23758
|
]
|
|
@@ -23745,7 +23880,7 @@
|
|
|
23745
23880
|
"name": "rightBlock",
|
|
23746
23881
|
"type": "React.ReactNode",
|
|
23747
23882
|
"required": false,
|
|
23748
|
-
"description": "Кастомный слот в правой части header, слева от крестика закрытия.\nПрижимается к крестику; если контент широкий — «давит» на title/description\n(уходят в многоточие с тултипом). Максимальная высота — как у крестика\n(32px при `size='m'`, 24px при `size='s'`), ширина
|
|
23883
|
+
"description": "Кастомный слот в правой части header, слева от крестика закрытия.\nПрижимается к крестику; если контент широкий — «давит» на title/description\n(уходят в многоточие с тултипом). Максимальная высота — как у крестика\n(32px при `size='l'` и `size='m'`, 24px при `size='s'`), ширина не\nограничена."
|
|
23749
23884
|
},
|
|
23750
23885
|
{
|
|
23751
23886
|
"name": "showCloseButton",
|
|
@@ -24318,7 +24453,7 @@
|
|
|
24318
24453
|
"compound popup"
|
|
24319
24454
|
],
|
|
24320
24455
|
"docs": "# PopupDF\n\n`PopupDF` — локальная DF-обёртка над [Popup](https://plasma.sberdevices.ru/sdds-finai/components/popup/).\n\n## Ключевые особенности\n\n- крестик закрытия живёт в `PopupDF.Header`\n- доступны `PopupDF.Header`, `PopupDF.Body`, `PopupDF.Footer`\n- доступны размеры `size=\"m\" | \"s\"`\n- `title` и `description` ограничены двумя строками\n- в `Header` доступна кнопка назад через `onBackButtonClick`\n- иконка ресайза использует DF-иконку по умолчанию, учитывает `resizable.iconSize` и может быть переопределена через `resizable.icons`\n\n## Compound-компоненты\n\n```ts\nPopupDF.Header; // Шапка\nPopupDF.Body; // Контент\nPopupDF.Footer; // Футер\n```\n\n## Особенности\n\n- `Header` и `Footer` остаются опциональными и подключаются через композицию\n- `subHeader` подходит для кастомного контента, смыслово связанного с шапкой\n- если контента много, скролл должен жить внутри `PopupDF.Body`\n- по умолчанию угол иконки ресайза вычисляется из `placement` так, чтобы ресайз тянул popup внутрь доступной области\n- для ручной смены угла ресайза используйте нативный `resizable.directions`, например `directions: ['top-left']`\n- если `hiddenIcons` не передан, `PopupDF` автоматически скрывает угловые иконки, которые не входят в `directions`; для нестандартной видимости передайте `hiddenIcons` явно\n- если пользовательские `icons` не переданы, `PopupDF` заполняет угловые иконки своей `IconResizeCorneredFill`; `iconSize` влияет на DF-иконку по умолчанию\n\nОписание типов и compound-пропсов — в разделе [API](?path=/docs/локальные-компоненты-popupdf-api--docs).",
|
|
24321
|
-
"apiDocs": "# PopupDF API\n\n## PopupDFProps\n\n```typescript\ntype PopupDFProps = Omit<\n ComponentProps<typeof Popup>,\n 'children' | 'isOpen'\n> & {\n /**\n * Содержимое popup.\n * Обычно используется композиция из `PopupDF.Header`, `PopupDF.Body` и `PopupDF.Footer`.\n */\n children?: ReactNode;\n /**\n * Начальное состояние открытия в uncontrolled-режиме.\n * @default false\n */\n defaultOpened?: boolean;\n /**\n * Коллбэк смены состояния открытия.\n */\n onToggle?: (opened: boolean) => void;\n /**\n * Размер PopupDF.\n * Влияет на внутренние отступы и типографику header.\n * @default 'm'\n */\n size?: PopupDFSize;\n};\n```\n\n> `PopupDF` наследует базовые пропсы `Popup` из `sdds-finai`, но добавляет compound-структуру,\n`size`, `defaultOpened`, `onToggle` и DF-иконки для базовой настройки `resizable`.\n\n## PopupDFHeaderProps\n\n```typescript\ntype PopupDFHeaderProps = Omit<BoxProps, 'children'> & {\n /**\n * Заголовок в верхней левой части header.\n */\n title?: ReactNode;\n /**\n * Текст под заголовком в верхней левой части header.\n */\n description?: ReactNode;\n /**\n * Кастомный контент, относящийся по смыслу к header.\n */\n subHeader?: ReactNode;\n /**\n * Кастомный слот в правой части header, слева от крестика закрытия.\n * Прижимается к крестику; если контент широкий — «давит» на title/description\n * (уходят в многоточие с тултипом). Максимальная высота — как у крестика\n * (32px при `size='m'`, 24px при `size='s'`), ширина
|
|
24456
|
+
"apiDocs": "# PopupDF API\n\n## PopupDFProps\n\n```typescript\ntype PopupDFProps = Omit<\n ComponentProps<typeof Popup>,\n 'children' | 'isOpen'\n> & {\n /**\n * Содержимое popup.\n * Обычно используется композиция из `PopupDF.Header`, `PopupDF.Body` и `PopupDF.Footer`.\n */\n children?: ReactNode;\n /**\n * Начальное состояние открытия в uncontrolled-режиме.\n * @default false\n */\n defaultOpened?: boolean;\n /**\n * Коллбэк смены состояния открытия.\n */\n onToggle?: (opened: boolean) => void;\n /**\n * Размер PopupDF.\n * Влияет на внутренние отступы и типографику header.\n * @default 'm'\n */\n size?: PopupDFSize;\n};\n```\n\n> `PopupDF` наследует базовые пропсы `Popup` из `sdds-finai`, но добавляет compound-структуру,\n`size`, `defaultOpened`, `onToggle` и DF-иконки для базовой настройки `resizable`.\n\n## PopupDFSize\n\n```typescript\ntype PopupDFSize = 's' | 'm' | 'l';\n```\n\n> Размер попапа. Влияет на типографику шапки и внутренние отступы: `l` — крупный\nзаголовок (H4) с описанием (BodyS), `m` — средний, `s` — компактный.\n\n## PopupDFHeaderProps\n\n```typescript\ntype PopupDFHeaderProps = Omit<BoxProps, 'children'> & {\n /**\n * Заголовок в верхней левой части header.\n */\n title?: ReactNode;\n /**\n * Текст под заголовком в верхней левой части header.\n */\n description?: ReactNode;\n /**\n * Кастомный контент, относящийся по смыслу к header.\n */\n subHeader?: ReactNode;\n /**\n * Кастомный слот в правой части header, слева от крестика закрытия.\n * Прижимается к крестику; если контент широкий — «давит» на title/description\n * (уходят в многоточие с тултипом). Максимальная высота — как у крестика\n * (32px при `size='l'` и `size='m'`, 24px при `size='s'`), ширина не\n * ограничена.\n */\n rightBlock?: ReactNode;\n /**\n * Показывать ли крестик закрытия в правой верхней части header.\n * @default true\n */\n showCloseButton?: boolean;\n /**\n * Callback при клике на кнопку со стрелкой назад слева от заголовка.\n */\n onBackButtonClick?: () => void;\n /**\n * Кастомный обработчик закрытия.\n * Если не передан, будет использован обработчик закрытия из `PopupDF`.\n */\n onClose?: () => void;\n};\n```\n\n## PopupDFBodyProps\n\n```typescript\ntype PopupDFBodyProps = BoxProps;\n```\n\n## PopupDFFooterProps\n\n```typescript\ntype PopupDFFooterProps = BoxProps & {\n children?: ReactNode;\n};\n```\n\n## PopupDFResizableConfig\n\n```typescript\ntype PopupDFResizableConfig = Exclude<\n ComponentProps<typeof Popup>['resizable'],\n boolean | undefined\n>;\n```",
|
|
24322
24457
|
"curatedStories": [
|
|
24323
24458
|
{
|
|
24324
24459
|
"exportName": "Simple",
|
|
@@ -24331,6 +24466,12 @@
|
|
|
24331
24466
|
"displayName": "Playground",
|
|
24332
24467
|
"type": "full-code",
|
|
24333
24468
|
"code": "import { useState } from 'react';\nimport {\n Button,\n Flow,\n LinkButton,\n PopupDF,\n PopupProvider,\n SSRProvider,\n} from '@daisforge/ui';\n\n// Контент футера — обычные кнопки, которые вы кладёте в PopupDF.Footer\nfunction FooterActions() {\n return (\n <Flow mainAxisGap={8}>\n <LinkButton href=\"/\" size=\"xs\">\n LinkButton\n </LinkButton>\n <Button size=\"xs\" view=\"secondary\">\n Отмена\n </Button>\n <Button size=\"xs\" view=\"accent\">\n Применить\n </Button>\n </Flow>\n );\n}\nfunction Example() {\n const [opened, setOpened] = useState(true);\n\n return (\n <SSRProvider>\n <PopupProvider>\n <Button onClick={() => setOpened(true)}>Открыть PopupDF</Button>\n <PopupDF\n opened={opened}\n onToggle={setOpened}\n size=\"m\"\n placement=\"center\"\n offset={[0, 0]}\n draggable\n resizable={{ minWidth: 240, minHeight: 120, iconSize: 's' }}\n style={{ width: '396px' }}\n >\n <PopupDF.Header\n title=\"Title\"\n description=\"Description\"\n rightBlock={\n <div style={{ display: 'flex', alignItems: 'center' }}>\n {/* кастомный контент слева от крестика, ширина не ограничена */}\n </div>\n }\n showCloseButton\n />\n <PopupDF.Body>Контент попапа</PopupDF.Body>\n <PopupDF.Footer>\n <FooterActions />\n </PopupDF.Footer>\n </PopupDF>\n </PopupProvider>\n </SSRProvider>\n );\n}"
|
|
24469
|
+
},
|
|
24470
|
+
{
|
|
24471
|
+
"exportName": "SizeL",
|
|
24472
|
+
"displayName": "Size L",
|
|
24473
|
+
"type": "full-code",
|
|
24474
|
+
"code": "import { useRef, useState } from 'react';\nimport {\n Button,\n IconButton,\n LinkButton,\n PopupDF,\n PopupProvider,\n SSRProvider,\n} from '@daisforge/ui';\nimport { IconFullscreenOff, IconFullscreenOn } from '@daisforge/ui/icons';\n\n// Разворот на весь экран собираем сами из пропсов PopupDF:\n// сначала выключаем resizable и draggable, чтобы попап вернулся к обычному\n// размеру, затем следующим тиком плавно растим его до краёв frame.\nfunction Example() {\n const frameRef = useRef(null);\n const [opened, setOpened] = useState(true);\n const [fullscreen, setFullscreen] = useState(false);\n const [interactive, setInteractive] = useState(true);\n\n const expand = () => {\n setInteractive(false);\n window.setTimeout(() => setFullscreen(true), 30);\n };\n\n const collapse = () => {\n setFullscreen(false);\n window.setTimeout(() => setInteractive(true), 320);\n };\n\n const IconFullS = fullscreen ? IconFullscreenOff : IconFullscreenOn;\n\n const sizeStyle = {\n width: fullscreen ? 'calc(100% - 48px)' : '600px',\n height: fullscreen ? 'calc(100% - 48px)' : '600px',\n maxWidth: '100%',\n maxHeight: '100%',\n transition: 'width 280ms ease, height 280ms ease',\n // grid тянет карточку на всю заданную высоту, иначе внешний узел Popup\n // сжимается по контенту и height не применяется (600 даёт только ширину).\n display: 'grid',\n gridTemplateRows: '1fr',\n gridTemplateColumns: '1fr',\n };\n\n return (\n <SSRProvider>\n <PopupProvider>\n {/* frame — контейнер, внутри которого живёт и разворачивается попап */}\n <div ref={frameRef} style={{ position: 'relative', minHeight: 720 }}>\n <PopupDF\n opened={opened}\n onToggle={setOpened}\n frame={frameRef}\n size=\"l\"\n placement=\"center\"\n draggable={interactive}\n resizable={\n interactive\n ? {\n // стартовый размер контейнера при включённом resizable\n defaultSize: { width: 600, height: 600 },\n minWidth: 320,\n minHeight: 220,\n iconSize: 's',\n }\n : false\n }\n style={sizeStyle}\n >\n <PopupDF.Header\n title=\"Заголовок PopupDF размера L\"\n description=\"Body S. Двигай за шапку, тяни за угол, разворачивай кнопкой.\"\n subHeader={\n <div style={{ height: 40, display: 'flex', alignItems: 'center' }}>\n Кастомный слот\n </div>\n }\n rightBlock={\n <IconButton\n size=\"xs\"\n view=\"secondary\"\n pin=\"circle-circle\"\n title={fullscreen ? 'Свернуть' : 'Развернуть'}\n onClick={() => (fullscreen ? collapse() : expand())}\n >\n <IconFullS size=\"xs\" />\n </IconButton>\n }\n />\n {/* высота 100%, чтобы контент тела рос при ресайзе попапа */}\n <PopupDF.Body>\n <div style={{ height: '100%' }}>Контент попапа</div>\n </PopupDF.Body>\n <PopupDF.Footer>\n {/* LinkButton отделён от группы кнопок отступом 16px (L) */}\n <div\n style={{\n display: 'flex',\n justifyContent: 'flex-end',\n alignItems: 'center',\n gap: 16,\n }}\n >\n <LinkButton href=\"/\" size=\"s\">\n LinkButton\n </LinkButton>\n <div style={{ display: 'flex', gap: 4 }}>\n <Button size=\"s\" view=\"secondary\">\n Отмена\n </Button>\n <Button size=\"s\" view=\"accent\">\n Применить\n </Button>\n </div>\n </div>\n </PopupDF.Footer>\n </PopupDF>\n </div>\n </PopupProvider>\n </SSRProvider>\n );\n}"
|
|
24334
24475
|
}
|
|
24335
24476
|
],
|
|
24336
24477
|
"hasCuratedMeta": true,
|
|
@@ -24357,17 +24498,16 @@
|
|
|
24357
24498
|
"code": "import { useState } from 'react';\nimport {\n Button,\n Flow,\n LinkButton,\n PopupDF,\n PopupProvider,\n SSRProvider,\n} from '@daisforge/ui';\n\n// Контент футера — обычные кнопки, которые вы кладёте в PopupDF.Footer\nfunction FooterActions() {\n return (\n <Flow mainAxisGap={8}>\n <LinkButton href=\"/\" size=\"xs\">\n LinkButton\n </LinkButton>\n <Button size=\"xs\" view=\"secondary\">\n Отмена\n </Button>\n <Button size=\"xs\" view=\"accent\">\n Применить\n </Button>\n </Flow>\n );\n}\nfunction Example() {\n const [opened, setOpened] = useState(true);\n\n return (\n <SSRProvider>\n <PopupProvider>\n <Button onClick={() => setOpened(true)}>Открыть PopupDF</Button>\n <PopupDF\n opened={opened}\n onToggle={setOpened}\n size=\"m\"\n placement=\"center\"\n offset={[0, 0]}\n draggable\n resizable={{ minWidth: 240, minHeight: 120, iconSize: 's' }}\n style={{ width: '396px' }}\n >\n <PopupDF.Header\n title=\"Title\"\n description=\"Description\"\n rightBlock={\n <div style={{ display: 'flex', alignItems: 'center' }}>\n {/* кастомный контент слева от крестика, ширина не ограничена */}\n </div>\n }\n showCloseButton\n />\n <PopupDF.Body>Контент попапа</PopupDF.Body>\n <PopupDF.Footer>\n <FooterActions />\n </PopupDF.Footer>\n </PopupDF>\n </PopupProvider>\n </SSRProvider>\n );\n}"
|
|
24358
24499
|
},
|
|
24359
24500
|
{
|
|
24360
|
-
"exportName": "
|
|
24361
|
-
"displayName": "
|
|
24362
|
-
"type": "
|
|
24363
|
-
"code": "
|
|
24364
|
-
"sourceFile": "packages/storybook/src/stories/PopupDF/PopupDF.stories.tsx"
|
|
24501
|
+
"exportName": "SizeL",
|
|
24502
|
+
"displayName": "Size L",
|
|
24503
|
+
"type": "full-code",
|
|
24504
|
+
"code": "import { useRef, useState } from 'react';\nimport {\n Button,\n IconButton,\n LinkButton,\n PopupDF,\n PopupProvider,\n SSRProvider,\n} from '@daisforge/ui';\nimport { IconFullscreenOff, IconFullscreenOn } from '@daisforge/ui/icons';\n\n// Разворот на весь экран собираем сами из пропсов PopupDF:\n// сначала выключаем resizable и draggable, чтобы попап вернулся к обычному\n// размеру, затем следующим тиком плавно растим его до краёв frame.\nfunction Example() {\n const frameRef = useRef(null);\n const [opened, setOpened] = useState(true);\n const [fullscreen, setFullscreen] = useState(false);\n const [interactive, setInteractive] = useState(true);\n\n const expand = () => {\n setInteractive(false);\n window.setTimeout(() => setFullscreen(true), 30);\n };\n\n const collapse = () => {\n setFullscreen(false);\n window.setTimeout(() => setInteractive(true), 320);\n };\n\n const IconFullS = fullscreen ? IconFullscreenOff : IconFullscreenOn;\n\n const sizeStyle = {\n width: fullscreen ? 'calc(100% - 48px)' : '600px',\n height: fullscreen ? 'calc(100% - 48px)' : '600px',\n maxWidth: '100%',\n maxHeight: '100%',\n transition: 'width 280ms ease, height 280ms ease',\n // grid тянет карточку на всю заданную высоту, иначе внешний узел Popup\n // сжимается по контенту и height не применяется (600 даёт только ширину).\n display: 'grid',\n gridTemplateRows: '1fr',\n gridTemplateColumns: '1fr',\n };\n\n return (\n <SSRProvider>\n <PopupProvider>\n {/* frame — контейнер, внутри которого живёт и разворачивается попап */}\n <div ref={frameRef} style={{ position: 'relative', minHeight: 720 }}>\n <PopupDF\n opened={opened}\n onToggle={setOpened}\n frame={frameRef}\n size=\"l\"\n placement=\"center\"\n draggable={interactive}\n resizable={\n interactive\n ? {\n // стартовый размер контейнера при включённом resizable\n defaultSize: { width: 600, height: 600 },\n minWidth: 320,\n minHeight: 220,\n iconSize: 's',\n }\n : false\n }\n style={sizeStyle}\n >\n <PopupDF.Header\n title=\"Заголовок PopupDF размера L\"\n description=\"Body S. Двигай за шапку, тяни за угол, разворачивай кнопкой.\"\n subHeader={\n <div style={{ height: 40, display: 'flex', alignItems: 'center' }}>\n Кастомный слот\n </div>\n }\n rightBlock={\n <IconButton\n size=\"xs\"\n view=\"secondary\"\n pin=\"circle-circle\"\n title={fullscreen ? 'Свернуть' : 'Развернуть'}\n onClick={() => (fullscreen ? collapse() : expand())}\n >\n <IconFullS size=\"xs\" />\n </IconButton>\n }\n />\n {/* высота 100%, чтобы контент тела рос при ресайзе попапа */}\n <PopupDF.Body>\n <div style={{ height: '100%' }}>Контент попапа</div>\n </PopupDF.Body>\n <PopupDF.Footer>\n {/* LinkButton отделён от группы кнопок отступом 16px (L) */}\n <div\n style={{\n display: 'flex',\n justifyContent: 'flex-end',\n alignItems: 'center',\n gap: 16,\n }}\n >\n <LinkButton href=\"/\" size=\"s\">\n LinkButton\n </LinkButton>\n <div style={{ display: 'flex', gap: 4 }}>\n <Button size=\"s\" view=\"secondary\">\n Отмена\n </Button>\n <Button size=\"s\" view=\"accent\">\n Применить\n </Button>\n </div>\n </div>\n </PopupDF.Footer>\n </PopupDF>\n </div>\n </PopupProvider>\n </SSRProvider>\n );\n}"
|
|
24365
24505
|
},
|
|
24366
24506
|
{
|
|
24367
|
-
"exportName": "
|
|
24507
|
+
"exportName": "Usage1",
|
|
24368
24508
|
"displayName": "Использование в PopupDF.stories.tsx",
|
|
24369
24509
|
"type": "usage",
|
|
24370
|
-
"code": "<PopupDF\n
|
|
24510
|
+
"code": "<PopupDF\n opened={opened}\n onToggle={setOpened}\n frame={frameRef}\n placement={placement}\n offset={[offsetX, offsetY]}\n size={size}\n draggable={draggable}\n resizable={resizableConfig}\n style={{ width: '396px' }}\n >\n <PopupDF.Header\n title=\"Title\"\n description=\"Description\"\n subHeader={withSubHeader ? <HeaderSlot /> : undefined}\n rightBlock={\n withRightBlock ? <RightBlockSlot size={size} /> : undefined\n }\n showCloseButton={showCloseButton}\n onBackButtonClick={showBackButton ? () => {} : undefined}\n />\n {withBody && (\n <PopupDF.Body>\n <BodySlot />\n </PopupDF.Body>\n )}\n {withFooter && (\n <PopupDF.Footer>\n <FooterActions size={size} />\n </PopupDF.Footer>\n )}\n </PopupDF>",
|
|
24371
24511
|
"sourceFile": "packages/storybook/src/stories/PopupDF/PopupDF.stories.tsx"
|
|
24372
24512
|
}
|
|
24373
24513
|
]
|
|
@@ -25011,11 +25151,29 @@
|
|
|
25011
25151
|
"description": "Стиль для UI конфигурации\nВлияет на выбор предустановленого набора токенов",
|
|
25012
25152
|
"default": "default"
|
|
25013
25153
|
},
|
|
25154
|
+
{
|
|
25155
|
+
"name": "firstTextfieldInputWrapperRef",
|
|
25156
|
+
"type": "React.Ref<HTMLDivElement> | undefined",
|
|
25157
|
+
"required": false,
|
|
25158
|
+
"description": "Ссылка на обертку первого поля ввода"
|
|
25159
|
+
},
|
|
25014
25160
|
{
|
|
25015
25161
|
"name": "hasClearDivider",
|
|
25016
25162
|
"type": "boolean | undefined",
|
|
25017
25163
|
"required": false,
|
|
25018
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": "Ссылка на обертку второго поля ввода"
|
|
25019
25177
|
}
|
|
25020
25178
|
],
|
|
25021
25179
|
"propsTypeName": "RangeProps",
|
|
@@ -26609,10 +26767,10 @@
|
|
|
26609
26767
|
},
|
|
26610
26768
|
{
|
|
26611
26769
|
"exportName": "Usage2",
|
|
26612
|
-
"displayName": "Использование в TableCanvas.
|
|
26770
|
+
"displayName": "Использование в TableCanvas.cellsMerging.stories.tsx",
|
|
26613
26771
|
"type": "usage",
|
|
26614
|
-
"code": "<Select\n label=\"Режим выделения\"\n value={selectionMode}\n onChange={(
|
|
26615
|
-
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.
|
|
26772
|
+
"code": "<Select\n target=\"textfield-like\"\n label=\"Режим выделения\"\n value={selectionMode}\n onChange={(v) => setSelectionMode(v as CellsSelectionMode)}\n items={SELECTION_MODE_OPTIONS}\n />",
|
|
26773
|
+
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.CellsMerging/TableCanvas.cellsMerging.stories.tsx"
|
|
26616
26774
|
},
|
|
26617
26775
|
{
|
|
26618
26776
|
"exportName": "Vendor1",
|
|
@@ -26634,7 +26792,45 @@
|
|
|
26634
26792
|
"folderName": "Sheet",
|
|
26635
26793
|
"role": "primary",
|
|
26636
26794
|
"description": "Шторка (bottom sheet), выезжающая поверх экрана снизу с шапкой и футером",
|
|
26637
|
-
"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
|
+
],
|
|
26638
26834
|
"propsTypeName": "SheetProps",
|
|
26639
26835
|
"sourceFile": "node_modules/@salutejs/sdds-finai/types/components/Sheet/Sheet.d.ts",
|
|
26640
26836
|
"type": "wrapper",
|
|
@@ -26651,7 +26847,7 @@
|
|
|
26651
26847
|
"name": "onClose",
|
|
26652
26848
|
"type": "() => void",
|
|
26653
26849
|
"required": true,
|
|
26654
|
-
"description": "Обработчик закрытия шторки. Вызывается при клике по оверлею
|
|
26850
|
+
"description": "Обработчик закрытия шторки. Вызывается при смахивании шторки вниз,\nпри клике по оверлею (если не передан onOverlayClick)\nи при нажатии ESC (если не передан onEscKeyDown).",
|
|
26655
26851
|
"inheritedFrom": "Sheet",
|
|
26656
26852
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
26657
26853
|
},
|
|
@@ -26791,7 +26987,14 @@
|
|
|
26791
26987
|
"folderName": "Skeleton",
|
|
26792
26988
|
"role": "primary",
|
|
26793
26989
|
"description": "Плейсхолдер-линия для имитации загрузки текстовой строки",
|
|
26794
|
-
"props": [
|
|
26990
|
+
"props": [
|
|
26991
|
+
{
|
|
26992
|
+
"name": "animationDuration",
|
|
26993
|
+
"type": "number | undefined",
|
|
26994
|
+
"required": false,
|
|
26995
|
+
"description": "Длительность одного цикла анимации в миллисекундах"
|
|
26996
|
+
}
|
|
26997
|
+
],
|
|
26795
26998
|
"propsTypeName": "ComponentProps<typeof LineSkeleton>",
|
|
26796
26999
|
"sourceFile": "node_modules/@salutejs/sdds-finai/types/components/Skeleton/Skeleton.d.ts",
|
|
26797
27000
|
"type": "wrapper",
|
|
@@ -26808,7 +27011,8 @@
|
|
|
26808
27011
|
"name": "animationType",
|
|
26809
27012
|
"type": "\"shimmer\" | \"pulse\"",
|
|
26810
27013
|
"required": false,
|
|
26811
|
-
"description": "
|
|
27014
|
+
"description": "Тип анимации",
|
|
27015
|
+
"default": "'shimmer'",
|
|
26812
27016
|
"inheritedFrom": "LineSkeleton",
|
|
26813
27017
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
26814
27018
|
},
|
|
@@ -26824,7 +27028,7 @@
|
|
|
26824
27028
|
"name": "customFadeOutColor",
|
|
26825
27029
|
"type": "string",
|
|
26826
27030
|
"required": false,
|
|
26827
|
-
"description": "Значение цвета фона в
|
|
27031
|
+
"description": "Значение цвета фона в конце анимации `pulse`",
|
|
26828
27032
|
"inheritedFrom": "LineSkeleton",
|
|
26829
27033
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
26830
27034
|
},
|
|
@@ -26906,11 +27110,18 @@
|
|
|
26906
27110
|
"role": "primary",
|
|
26907
27111
|
"description": "Прямоугольный плейсхолдер для блоков и изображений на время загрузки",
|
|
26908
27112
|
"props": [
|
|
27113
|
+
{
|
|
27114
|
+
"name": "animationDuration",
|
|
27115
|
+
"type": "number | undefined",
|
|
27116
|
+
"required": false,
|
|
27117
|
+
"description": "Длительность одного цикла анимации в миллисекундах"
|
|
27118
|
+
},
|
|
26909
27119
|
{
|
|
26910
27120
|
"name": "animationType",
|
|
26911
27121
|
"type": "\"shimmer\" | \"pulse\" | undefined",
|
|
26912
27122
|
"required": false,
|
|
26913
|
-
"description": "
|
|
27123
|
+
"description": "Тип анимации",
|
|
27124
|
+
"default": "'shimmer'"
|
|
26914
27125
|
},
|
|
26915
27126
|
{
|
|
26916
27127
|
"name": "customFadeInColor",
|
|
@@ -26922,7 +27133,7 @@
|
|
|
26922
27133
|
"name": "customFadeOutColor",
|
|
26923
27134
|
"type": "string | undefined",
|
|
26924
27135
|
"required": false,
|
|
26925
|
-
"description": "Значение цвета фона в
|
|
27136
|
+
"description": "Значение цвета фона в конце анимации `pulse`"
|
|
26926
27137
|
},
|
|
26927
27138
|
{
|
|
26928
27139
|
"name": "customGradientColor",
|
|
@@ -26999,11 +27210,18 @@
|
|
|
26999
27210
|
"required": true,
|
|
27000
27211
|
"description": ""
|
|
27001
27212
|
},
|
|
27213
|
+
{
|
|
27214
|
+
"name": "animationDuration",
|
|
27215
|
+
"type": "number | undefined",
|
|
27216
|
+
"required": false,
|
|
27217
|
+
"description": "Длительность одного цикла анимации в миллисекундах"
|
|
27218
|
+
},
|
|
27002
27219
|
{
|
|
27003
27220
|
"name": "animationType",
|
|
27004
27221
|
"type": "\"shimmer\" | \"pulse\" | undefined",
|
|
27005
27222
|
"required": false,
|
|
27006
|
-
"description": "
|
|
27223
|
+
"description": "Тип анимации",
|
|
27224
|
+
"default": "'shimmer'"
|
|
27007
27225
|
},
|
|
27008
27226
|
{
|
|
27009
27227
|
"name": "customFadeInColor",
|
|
@@ -27015,7 +27233,7 @@
|
|
|
27015
27233
|
"name": "customFadeOutColor",
|
|
27016
27234
|
"type": "string | undefined",
|
|
27017
27235
|
"required": false,
|
|
27018
|
-
"description": "Значение цвета фона в
|
|
27236
|
+
"description": "Значение цвета фона в конце анимации `pulse`"
|
|
27019
27237
|
},
|
|
27020
27238
|
{
|
|
27021
27239
|
"name": "customGradientColor",
|
|
@@ -27142,7 +27360,7 @@
|
|
|
27142
27360
|
"type": "\"outer\" | \"inner\"",
|
|
27143
27361
|
"required": false,
|
|
27144
27362
|
"description": "Расположение подписи.",
|
|
27145
|
-
"default": "top",
|
|
27363
|
+
"default": "`top`",
|
|
27146
27364
|
"inheritedFrom": "Slider",
|
|
27147
27365
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
27148
27366
|
},
|
|
@@ -27397,6 +27615,13 @@
|
|
|
27397
27615
|
"importStatement": "import { Slider } from '@daisforge/ui';",
|
|
27398
27616
|
"minimalUsage": "<Slider max={0} min={0} />",
|
|
27399
27617
|
"examples": [
|
|
27618
|
+
{
|
|
27619
|
+
"exportName": "Usage",
|
|
27620
|
+
"displayName": "Использование в TableCanvas.bigData.stories.tsx",
|
|
27621
|
+
"type": "usage",
|
|
27622
|
+
"code": "<Slider\n value={cols}\n min={1}\n max={1500}\n onChangeCommitted={(value) => setCols(value)}\n />",
|
|
27623
|
+
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.CellsMerging/TableCanvas.bigData.stories.tsx"
|
|
27624
|
+
},
|
|
27400
27625
|
{
|
|
27401
27626
|
"exportName": "Vendor1",
|
|
27402
27627
|
"displayName": "Состояния Состояния Компонент поддерживает состояние disabled",
|
|
@@ -29440,6 +29665,12 @@
|
|
|
29440
29665
|
"required": true,
|
|
29441
29666
|
"description": ""
|
|
29442
29667
|
},
|
|
29668
|
+
{
|
|
29669
|
+
"name": "suffix",
|
|
29670
|
+
"type": "string | undefined",
|
|
29671
|
+
"required": false,
|
|
29672
|
+
"description": "Суффикс текста в поле ввода."
|
|
29673
|
+
},
|
|
29443
29674
|
{
|
|
29444
29675
|
"name": "align",
|
|
29445
29676
|
"type": "\"center\" | \"right\" | \"left\" | undefined",
|
|
@@ -30324,6 +30555,12 @@
|
|
|
30324
30555
|
"required": false,
|
|
30325
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."
|
|
30326
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
|
+
},
|
|
30327
30564
|
{
|
|
30328
30565
|
"name": "hideGrid",
|
|
30329
30566
|
"type": "boolean | undefined",
|
|
@@ -30552,6 +30789,12 @@
|
|
|
30552
30789
|
"required": false,
|
|
30553
30790
|
"description": "Emitted when a header menu disclosure indicator is clicked."
|
|
30554
30791
|
},
|
|
30792
|
+
{
|
|
30793
|
+
"name": "onHiddenColumnsIndicatorClicked",
|
|
30794
|
+
"type": "((col: number, event: HeaderClickedEventArgs | GroupHeaderClickedEventArgs) => void) | undefined",
|
|
30795
|
+
"required": false,
|
|
30796
|
+
"description": "Двойной клик по индикатору скрытых колонок раскрывает промежуток."
|
|
30797
|
+
},
|
|
30555
30798
|
{
|
|
30556
30799
|
"name": "onHighlightActiveRowChange",
|
|
30557
30800
|
"type": "((row: number | undefined, rowData?: R | undefined) => void) | undefined",
|
|
@@ -31077,6 +31320,13 @@
|
|
|
31077
31320
|
"role": "internal",
|
|
31078
31321
|
"description": "JSX-набор примитивов (Container, Text, Icon, Button…) для кастомного контента ячеек TableGlide",
|
|
31079
31322
|
"props": [
|
|
31323
|
+
{
|
|
31324
|
+
"name": "offsetX",
|
|
31325
|
+
"type": "number | undefined",
|
|
31326
|
+
"required": false,
|
|
31327
|
+
"description": "Сдвиг тултипа по X (px) относительно центра ноды. Нужен, когда видимая\nчасть ноды смещена внутри неё (например, иконка прижата к краю кнопки).",
|
|
31328
|
+
"default": "0"
|
|
31329
|
+
},
|
|
31080
31330
|
{
|
|
31081
31331
|
"name": "preserveLineBreaks",
|
|
31082
31332
|
"type": "boolean | undefined",
|
|
@@ -31176,7 +31426,7 @@
|
|
|
31176
31426
|
},
|
|
31177
31427
|
{
|
|
31178
31428
|
"name": "view",
|
|
31179
|
-
"type": "\"default\" | \"accent\" | \"secondary\" | \"clear\" | \"positive\" | \"warning\" | \"negative\" | \"dark\" | \"black\" | \"white\" | \"linkDefault\" | \"linkAccent\" | \"linkSecondary\" | \"linkPositive\" | \"linkWarning\" | \"linkNegative\" | \"linkInfo\" | undefined",
|
|
31429
|
+
"type": "\"default\" | \"accent\" | \"secondary\" | \"clear\" | \"positive\" | \"warning\" | \"negative\" | \"dark\" | \"black\" | \"white\" | \"gradient\" | \"linkDefault\" | \"linkAccent\" | \"linkSecondary\" | \"linkPositive\" | \"linkWarning\" | \"linkNegative\" | \"linkGradient\" | \"linkInfo\" | undefined",
|
|
31180
31430
|
"required": false,
|
|
31181
31431
|
"description": ""
|
|
31182
31432
|
},
|
|
@@ -31699,6 +31949,12 @@
|
|
|
31699
31949
|
"required": false,
|
|
31700
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."
|
|
31701
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
|
+
},
|
|
31702
31958
|
{
|
|
31703
31959
|
"name": "highlightRegions",
|
|
31704
31960
|
"type": "readonly Highlight[] | undefined",
|
|
@@ -31904,6 +32160,12 @@
|
|
|
31904
32160
|
"required": false,
|
|
31905
32161
|
"description": "Emitted when a header menu disclosure indicator is clicked."
|
|
31906
32162
|
},
|
|
32163
|
+
{
|
|
32164
|
+
"name": "onHiddenColumnsIndicatorClicked",
|
|
32165
|
+
"type": "((col: number, event: HeaderClickedEventArgs | GroupHeaderClickedEventArgs) => void) | undefined",
|
|
32166
|
+
"required": false,
|
|
32167
|
+
"description": "Двойной клик по индикатору скрытых колонок раскрывает промежуток."
|
|
32168
|
+
},
|
|
31907
32169
|
{
|
|
31908
32170
|
"name": "onItemHovered",
|
|
31909
32171
|
"type": "((args: GridMouseEventArgs) => void) | undefined",
|
|
@@ -32524,6 +32786,13 @@
|
|
|
32524
32786
|
"role": "internal",
|
|
32525
32787
|
"description": "Базовый класс узла canvas-сцены TableGlide: layout, hit-test, отрисовка, события",
|
|
32526
32788
|
"props": [
|
|
32789
|
+
{
|
|
32790
|
+
"name": "offsetX",
|
|
32791
|
+
"type": "number | undefined",
|
|
32792
|
+
"required": false,
|
|
32793
|
+
"description": "Сдвиг тултипа по X (px) относительно центра ноды. Нужен, когда видимая\nчасть ноды смещена внутри неё (например, иконка прижата к краю кнопки).",
|
|
32794
|
+
"default": "0"
|
|
32795
|
+
},
|
|
32527
32796
|
{
|
|
32528
32797
|
"name": "preserveLineBreaks",
|
|
32529
32798
|
"type": "boolean | undefined",
|
|
@@ -32925,6 +33194,12 @@
|
|
|
32925
33194
|
"required": false,
|
|
32926
33195
|
"description": "Переопределяет размер квадратной кнопки (px), приоритет над SIZE_CONFIG"
|
|
32927
33196
|
},
|
|
33197
|
+
{
|
|
33198
|
+
"name": "overrideWidth",
|
|
33199
|
+
"type": "number | undefined",
|
|
33200
|
+
"required": false,
|
|
33201
|
+
"description": "Только EmbedIconButton: ширина кнопки в раскладке и hit-area (px),\nпо умолчанию — сторона квадрата. Иконка рисуется в квадрате от левого края."
|
|
33202
|
+
},
|
|
32928
33203
|
{
|
|
32929
33204
|
"name": "view",
|
|
32930
33205
|
"type": "ButtonView | undefined",
|
|
@@ -33535,10 +33810,10 @@
|
|
|
33535
33810
|
},
|
|
33536
33811
|
{
|
|
33537
33812
|
"exportName": "Usage2",
|
|
33538
|
-
"displayName": "Использование в
|
|
33813
|
+
"displayName": "Использование в TableCanvasTooltip.stories.tsx",
|
|
33539
33814
|
"type": "usage",
|
|
33540
|
-
"code": "<Canvas.Text\n
|
|
33541
|
-
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.
|
|
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"
|
|
33542
33817
|
}
|
|
33543
33818
|
]
|
|
33544
33819
|
},
|
|
@@ -33952,6 +34227,12 @@
|
|
|
33952
34227
|
"required": false,
|
|
33953
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."
|
|
33954
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
|
+
},
|
|
33955
34236
|
{
|
|
33956
34237
|
"name": "highlightRegions",
|
|
33957
34238
|
"type": "readonly Highlight[] | undefined",
|
|
@@ -34156,6 +34437,12 @@
|
|
|
34156
34437
|
"required": false,
|
|
34157
34438
|
"description": "Emitted when a header menu disclosure indicator is clicked."
|
|
34158
34439
|
},
|
|
34440
|
+
{
|
|
34441
|
+
"name": "onHiddenColumnsIndicatorClicked",
|
|
34442
|
+
"type": "((col: number, event: HeaderClickedEventArgs | GroupHeaderClickedEventArgs) => void) | undefined",
|
|
34443
|
+
"required": false,
|
|
34444
|
+
"description": "Двойной клик по индикатору скрытых колонок раскрывает промежуток."
|
|
34445
|
+
},
|
|
34159
34446
|
{
|
|
34160
34447
|
"name": "onItemHovered",
|
|
34161
34448
|
"type": "((args: GridMouseEventArgs) => void) | undefined",
|
|
@@ -35249,6 +35536,13 @@
|
|
|
35249
35536
|
"required": false,
|
|
35250
35537
|
"description": "Сменить рендер на другой тип компонента."
|
|
35251
35538
|
},
|
|
35539
|
+
{
|
|
35540
|
+
"name": "disableScroll",
|
|
35541
|
+
"type": "boolean | undefined",
|
|
35542
|
+
"required": false,
|
|
35543
|
+
"description": "Отключает скролл к TabItem при его выборе",
|
|
35544
|
+
"default": "false"
|
|
35545
|
+
},
|
|
35252
35546
|
{
|
|
35253
35547
|
"name": "itemIndex",
|
|
35254
35548
|
"type": "number | undefined",
|
|
@@ -35330,6 +35624,13 @@
|
|
|
35330
35624
|
"required": false,
|
|
35331
35625
|
"description": "Контент справа"
|
|
35332
35626
|
},
|
|
35627
|
+
{
|
|
35628
|
+
"name": "disableScroll",
|
|
35629
|
+
"type": "boolean | undefined",
|
|
35630
|
+
"required": false,
|
|
35631
|
+
"description": "Отключает скролл к TabItem при его выборе",
|
|
35632
|
+
"default": "false"
|
|
35633
|
+
},
|
|
35333
35634
|
{
|
|
35334
35635
|
"name": "itemIndex",
|
|
35335
35636
|
"type": "number | undefined",
|
|
@@ -35361,6 +35662,12 @@
|
|
|
35361
35662
|
"required": false,
|
|
35362
35663
|
"description": ""
|
|
35363
35664
|
},
|
|
35665
|
+
{
|
|
35666
|
+
"name": "pilled",
|
|
35667
|
+
"type": "boolean | undefined",
|
|
35668
|
+
"required": false,
|
|
35669
|
+
"description": ""
|
|
35670
|
+
},
|
|
35364
35671
|
{
|
|
35365
35672
|
"name": "size",
|
|
35366
35673
|
"type": "\"xs\" | \"s\" | \"m\" | \"l\" | \"h6\" | \"h5\" | \"h4\" | \"h3\" | \"h2\" | \"h1\" | undefined",
|
|
@@ -35496,6 +35803,15 @@
|
|
|
35496
35803
|
"inheritedFrom": "Tabs",
|
|
35497
35804
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
35498
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
|
+
},
|
|
35499
35815
|
{
|
|
35500
35816
|
"name": "size",
|
|
35501
35817
|
"type": "\"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"s\" | \"l\" | \"m\" | \"xs\"",
|
|
@@ -35533,13 +35849,6 @@
|
|
|
35533
35849
|
"inheritedFrom": "Tabs",
|
|
35534
35850
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
35535
35851
|
},
|
|
35536
|
-
{
|
|
35537
|
-
"name": "pilled",
|
|
35538
|
-
"type": "boolean",
|
|
35539
|
-
"required": false,
|
|
35540
|
-
"inheritedFrom": "Tabs",
|
|
35541
|
-
"inheritedPackage": "@salutejs/sdds-finai"
|
|
35542
|
-
},
|
|
35543
35852
|
{
|
|
35544
35853
|
"name": "stretch",
|
|
35545
35854
|
"type": "boolean",
|
|
@@ -35634,7 +35943,7 @@
|
|
|
35634
35943
|
},
|
|
35635
35944
|
{
|
|
35636
35945
|
"name": "size",
|
|
35637
|
-
"type": "
|
|
35946
|
+
"type": "string | undefined",
|
|
35638
35947
|
"required": false,
|
|
35639
35948
|
"description": "Размер табов"
|
|
35640
35949
|
},
|
|
@@ -38758,7 +39067,7 @@
|
|
|
38758
39067
|
"exportName": "Usage2",
|
|
38759
39068
|
"displayName": "Использование в TourWidget.examples.tsx",
|
|
38760
39069
|
"type": "usage",
|
|
38761
|
-
"code": "<TourWidget.Header
|
|
39070
|
+
"code": "<TourWidget.Header\n title={'Знакомьтесь:\\nновые возможности'}\n description={\n 'Режимы просмотра\\nОбщий реестр — все пилоты со статусом «В реестре»\\n• Мои пилоты — только ваши проекты, включая черновики'\n }\n />",
|
|
38762
39071
|
"sourceFile": "packages/storybook/src/stories/TourWidget/TourWidget.examples.tsx"
|
|
38763
39072
|
}
|
|
38764
39073
|
]
|
|
@@ -38891,7 +39200,7 @@
|
|
|
38891
39200
|
"онбординг",
|
|
38892
39201
|
"степ-виджет"
|
|
38893
39202
|
],
|
|
38894
|
-
"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).",
|
|
38895
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```",
|
|
38896
39205
|
"curatedStories": [
|
|
38897
39206
|
{
|
|
@@ -38906,6 +39215,12 @@
|
|
|
38906
39215
|
"type": "full-code",
|
|
38907
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};"
|
|
38908
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
|
+
},
|
|
38909
39224
|
{
|
|
38910
39225
|
"exportName": "TourWithPulse",
|
|
38911
39226
|
"displayName": "Тур рядом с пульсацией",
|
|
@@ -38951,16 +39266,16 @@
|
|
|
38951
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};"
|
|
38952
39267
|
},
|
|
38953
39268
|
{
|
|
38954
|
-
"exportName": "
|
|
38955
|
-
"displayName": "
|
|
39269
|
+
"exportName": "LineBreaks",
|
|
39270
|
+
"displayName": "Переносы строк",
|
|
38956
39271
|
"type": "full-code",
|
|
38957
|
-
"code": "function
|
|
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};"
|
|
38958
39273
|
},
|
|
38959
39274
|
{
|
|
38960
|
-
"exportName": "
|
|
38961
|
-
"displayName": "
|
|
39275
|
+
"exportName": "TourWithPulse",
|
|
39276
|
+
"displayName": "Тур рядом с пульсацией",
|
|
38962
39277
|
"type": "full-code",
|
|
38963
|
-
"code": "function
|
|
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};"
|
|
38964
39279
|
}
|
|
38965
39280
|
]
|
|
38966
39281
|
},
|
|
@@ -42450,7 +42765,7 @@
|
|
|
42450
42765
|
},
|
|
42451
42766
|
{
|
|
42452
42767
|
"name": "view",
|
|
42453
|
-
"type": "\"default\" | \"accent\" | \"secondary\" | \"clear\" | \"positive\" | \"warning\" | \"negative\" | \"dark\" | \"black\" | \"white\" | undefined",
|
|
42768
|
+
"type": "\"default\" | \"accent\" | \"secondary\" | \"clear\" | \"positive\" | \"warning\" | \"negative\" | \"dark\" | \"black\" | \"white\" | \"gradient\" | undefined",
|
|
42454
42769
|
"required": false,
|
|
42455
42770
|
"description": ""
|
|
42456
42771
|
}
|
|
@@ -43942,7 +44257,7 @@
|
|
|
43942
44257
|
},
|
|
43943
44258
|
{
|
|
43944
44259
|
"name": "view",
|
|
43945
|
-
"type": "\"default\" | \"accent\" | \"secondary\" | \"clear\" | \"positive\" | \"warning\" | \"negative\" | \"dark\" | \"black\" | \"white\" | undefined",
|
|
44260
|
+
"type": "\"default\" | \"accent\" | \"secondary\" | \"clear\" | \"positive\" | \"warning\" | \"negative\" | \"dark\" | \"black\" | \"white\" | \"gradient\" | undefined",
|
|
43946
44261
|
"required": false,
|
|
43947
44262
|
"description": ""
|
|
43948
44263
|
}
|
|
@@ -45199,6 +45514,12 @@
|
|
|
45199
45514
|
"description": "Отступ календаря относительно поля ввода.",
|
|
45200
45515
|
"default": "[0, 2]"
|
|
45201
45516
|
},
|
|
45517
|
+
{
|
|
45518
|
+
"name": "onChangeVisibleDate",
|
|
45519
|
+
"type": "((date: Date) => void) | undefined",
|
|
45520
|
+
"required": false,
|
|
45521
|
+
"description": "Обработчик изменения отображаемых месяца или года при навигации по календарю."
|
|
45522
|
+
},
|
|
45202
45523
|
{
|
|
45203
45524
|
"name": "onToggle",
|
|
45204
45525
|
"type": "((isOpen: boolean, event?: Event | React.SyntheticEvent<Element, Event> | undefined) => void) | undefined",
|
|
@@ -45235,7 +45556,7 @@
|
|
|
45235
45556
|
"name": "stretched",
|
|
45236
45557
|
"type": "boolean | undefined",
|
|
45237
45558
|
"required": false,
|
|
45238
|
-
"description": "Растянуть поле ввода на всю доступную ширину"
|
|
45559
|
+
"description": "Растянуть поле ввода на всю доступную ширину, а календарь — на всю доступную ширину и высоту"
|
|
45239
45560
|
},
|
|
45240
45561
|
{
|
|
45241
45562
|
"name": "type",
|
|
@@ -45686,6 +46007,12 @@
|
|
|
45686
46007
|
"description": "Отступ календаря относительно поля ввода.",
|
|
45687
46008
|
"default": "[0, 0]"
|
|
45688
46009
|
},
|
|
46010
|
+
{
|
|
46011
|
+
"name": "onChangeVisibleDate",
|
|
46012
|
+
"type": "((date: Date) => void) | undefined",
|
|
46013
|
+
"required": false,
|
|
46014
|
+
"description": "Обработчик изменения отображаемых месяца или года при навигации по календарю."
|
|
46015
|
+
},
|
|
45689
46016
|
{
|
|
45690
46017
|
"name": "onToggle",
|
|
45691
46018
|
"type": "((isOpen: boolean, event?: Event | React.SyntheticEvent<Element, Event> | undefined) => void) | undefined",
|
|
@@ -45714,7 +46041,7 @@
|
|
|
45714
46041
|
"name": "stretched",
|
|
45715
46042
|
"type": "boolean | undefined",
|
|
45716
46043
|
"required": false,
|
|
45717
|
-
"description": "Растянуть поле ввода на всю доступную ширину"
|
|
46044
|
+
"description": "Растянуть поле ввода на всю доступную ширину, а календарь — на всю доступную ширину и высоту"
|
|
45718
46045
|
},
|
|
45719
46046
|
{
|
|
45720
46047
|
"name": "type",
|
|
@@ -45935,6 +46262,12 @@
|
|
|
45935
46262
|
"description": "",
|
|
45936
46263
|
"default": "'Формат даты указан не верно'"
|
|
45937
46264
|
},
|
|
46265
|
+
{
|
|
46266
|
+
"name": "isCalendarPositionedByInput",
|
|
46267
|
+
"type": "boolean | undefined",
|
|
46268
|
+
"required": false,
|
|
46269
|
+
"description": ""
|
|
46270
|
+
},
|
|
45938
46271
|
{
|
|
45939
46272
|
"name": "isDoubleCalendar",
|
|
45940
46273
|
"type": "boolean | undefined",
|
|
@@ -46585,6 +46918,12 @@
|
|
|
46585
46918
|
"description": "Задает выравнивание индикатора обязательности поля",
|
|
46586
46919
|
"default": "right"
|
|
46587
46920
|
},
|
|
46921
|
+
{
|
|
46922
|
+
"name": "suffix",
|
|
46923
|
+
"type": "string | undefined",
|
|
46924
|
+
"required": false,
|
|
46925
|
+
"description": "Суффикс текста в поле ввода."
|
|
46926
|
+
},
|
|
46588
46927
|
{
|
|
46589
46928
|
"name": "thousandSeparator",
|
|
46590
46929
|
"type": "string | boolean | undefined",
|
|
@@ -47094,6 +47433,13 @@
|
|
|
47094
47433
|
"required": true,
|
|
47095
47434
|
"description": ""
|
|
47096
47435
|
},
|
|
47436
|
+
{
|
|
47437
|
+
"name": "clip",
|
|
47438
|
+
"type": "boolean | undefined",
|
|
47439
|
+
"required": false,
|
|
47440
|
+
"description": "При ограничении ширины разрешает скролл и отображает дополнительные элементы со стрелками",
|
|
47441
|
+
"default": "true"
|
|
47442
|
+
},
|
|
47097
47443
|
{
|
|
47098
47444
|
"name": "filledBackground",
|
|
47099
47445
|
"type": "boolean | undefined",
|
|
@@ -47195,14 +47541,6 @@
|
|
|
47195
47541
|
"type": "React.ReactNode",
|
|
47196
47542
|
"required": false,
|
|
47197
47543
|
"description": ""
|
|
47198
|
-
},
|
|
47199
|
-
{
|
|
47200
|
-
"name": "clip",
|
|
47201
|
-
"type": "boolean | undefined",
|
|
47202
|
-
"required": false,
|
|
47203
|
-
"description": "При ограничении ширины разрешает скролл и отображает дополнительные элементы со стрелками",
|
|
47204
|
-
"deprecated": true,
|
|
47205
|
-
"default": "true"
|
|
47206
47544
|
}
|
|
47207
47545
|
],
|
|
47208
47546
|
"propsTypeName": "FormSegmentGroupProps",
|
|
@@ -48885,7 +49223,7 @@
|
|
|
48885
49223
|
},
|
|
48886
49224
|
{
|
|
48887
49225
|
"name": "view",
|
|
48888
|
-
"type": "\"default\" | \"clear\" | \"black\" | \"white\" | \"positive\" | \"warning\" | \"negative\" | \"secondary\" | \"accent\" | \"dark\" | undefined",
|
|
49226
|
+
"type": "\"default\" | \"clear\" | \"black\" | \"white\" | \"positive\" | \"warning\" | \"negative\" | \"secondary\" | \"accent\" | \"dark\" | \"gradient\" | undefined",
|
|
48889
49227
|
"required": false,
|
|
48890
49228
|
"description": ""
|
|
48891
49229
|
}
|
|
@@ -49570,6 +49908,13 @@
|
|
|
49570
49908
|
"required": false,
|
|
49571
49909
|
"description": "Контент справа"
|
|
49572
49910
|
},
|
|
49911
|
+
{
|
|
49912
|
+
"name": "disableScroll",
|
|
49913
|
+
"type": "boolean | undefined",
|
|
49914
|
+
"required": false,
|
|
49915
|
+
"description": "Отключает скролл к TabItem при его выборе",
|
|
49916
|
+
"default": "false"
|
|
49917
|
+
},
|
|
49573
49918
|
{
|
|
49574
49919
|
"name": "itemIndex",
|
|
49575
49920
|
"type": "number | undefined",
|
|
@@ -49601,9 +49946,15 @@
|
|
|
49601
49946
|
"required": false,
|
|
49602
49947
|
"description": ""
|
|
49603
49948
|
},
|
|
49949
|
+
{
|
|
49950
|
+
"name": "pilled",
|
|
49951
|
+
"type": "boolean | undefined",
|
|
49952
|
+
"required": false,
|
|
49953
|
+
"description": ""
|
|
49954
|
+
},
|
|
49604
49955
|
{
|
|
49605
49956
|
"name": "size",
|
|
49606
|
-
"type": "\"s\" | \"xs\" | \"m\" | \"
|
|
49957
|
+
"type": "\"s\" | \"xs\" | \"m\" | \"h6\" | \"h5\" | \"h4\" | \"h3\" | \"h2\" | \"h1\" | \"l\" | undefined",
|
|
49607
49958
|
"required": false,
|
|
49608
49959
|
"description": ""
|
|
49609
49960
|
},
|
|
@@ -49711,6 +50062,14 @@
|
|
|
49711
50062
|
"type": "string | undefined",
|
|
49712
50063
|
"required": false,
|
|
49713
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"
|
|
49714
50073
|
}
|
|
49715
50074
|
],
|
|
49716
50075
|
"propsTypeName": "ComponentProps<typeof FiltersActionsTabs>",
|
|
@@ -50115,7 +50474,7 @@
|
|
|
50115
50474
|
},
|
|
50116
50475
|
{
|
|
50117
50476
|
"name": "view",
|
|
50118
|
-
"type": "\"default\" | \"clear\" | \"black\" | \"white\" | \"positive\" | \"warning\" | \"negative\" | \"secondary\" | \"accent\" | \"dark\" | undefined",
|
|
50477
|
+
"type": "\"default\" | \"clear\" | \"black\" | \"white\" | \"positive\" | \"warning\" | \"negative\" | \"secondary\" | \"accent\" | \"dark\" | \"gradient\" | undefined",
|
|
50119
50478
|
"required": false,
|
|
50120
50479
|
"description": ""
|
|
50121
50480
|
}
|
|
@@ -50541,6 +50900,14 @@
|
|
|
50541
50900
|
"type": "string | undefined",
|
|
50542
50901
|
"required": false,
|
|
50543
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"
|
|
50544
50911
|
}
|
|
50545
50912
|
]
|
|
50546
50913
|
},
|
|
@@ -50572,6 +50939,13 @@
|
|
|
50572
50939
|
"required": false,
|
|
50573
50940
|
"description": "Контент справа"
|
|
50574
50941
|
},
|
|
50942
|
+
{
|
|
50943
|
+
"name": "disableScroll",
|
|
50944
|
+
"type": "boolean | undefined",
|
|
50945
|
+
"required": false,
|
|
50946
|
+
"description": "Отключает скролл к TabItem при его выборе",
|
|
50947
|
+
"default": "false"
|
|
50948
|
+
},
|
|
50575
50949
|
{
|
|
50576
50950
|
"name": "itemIndex",
|
|
50577
50951
|
"type": "number | undefined",
|
|
@@ -50603,9 +50977,15 @@
|
|
|
50603
50977
|
"required": false,
|
|
50604
50978
|
"description": ""
|
|
50605
50979
|
},
|
|
50980
|
+
{
|
|
50981
|
+
"name": "pilled",
|
|
50982
|
+
"type": "boolean | undefined",
|
|
50983
|
+
"required": false,
|
|
50984
|
+
"description": ""
|
|
50985
|
+
},
|
|
50606
50986
|
{
|
|
50607
50987
|
"name": "size",
|
|
50608
|
-
"type": "\"s\" | \"xs\" | \"m\" | \"
|
|
50988
|
+
"type": "\"s\" | \"xs\" | \"m\" | \"h6\" | \"h5\" | \"h4\" | \"h3\" | \"h2\" | \"h1\" | \"l\" | undefined",
|
|
50609
50989
|
"required": false,
|
|
50610
50990
|
"description": ""
|
|
50611
50991
|
},
|
|
@@ -51297,7 +51677,7 @@
|
|
|
51297
51677
|
},
|
|
51298
51678
|
{
|
|
51299
51679
|
"name": "view",
|
|
51300
|
-
"type": "\"default\" | \"positive\" | \"warning\" | \"negative\" | \"secondary\" | \"accent\" | \"info\" | undefined",
|
|
51680
|
+
"type": "\"default\" | \"positive\" | \"warning\" | \"negative\" | \"secondary\" | \"accent\" | \"gradient\" | \"info\" | undefined",
|
|
51301
51681
|
"required": false,
|
|
51302
51682
|
"description": ""
|
|
51303
51683
|
}
|
|
@@ -51854,6 +52234,12 @@
|
|
|
51854
52234
|
"displayName": "Default",
|
|
51855
52235
|
"type": "full-code",
|
|
51856
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/>"
|
|
51857
52243
|
}
|
|
51858
52244
|
]
|
|
51859
52245
|
},
|
|
@@ -52085,6 +52471,106 @@
|
|
|
52085
52471
|
}
|
|
52086
52472
|
]
|
|
52087
52473
|
},
|
|
52474
|
+
{
|
|
52475
|
+
"component": "TableCanvas",
|
|
52476
|
+
"feature": "CellsMerging",
|
|
52477
|
+
"legacy": false,
|
|
52478
|
+
"summary": "Объединение ячеек тела таблицы: по строкам (rowSpan), по колонкам (colSpan) и",
|
|
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```",
|
|
52481
|
+
"api": [
|
|
52482
|
+
{
|
|
52483
|
+
"typeName": "MergedCellsRegion",
|
|
52484
|
+
"source": "type MergedCellsRegion = {\n rowKeys: Array<string | number>;\n colKeys: string[];\n /** Выравнивание контента этого блока. Важнее колоночного и общего. */\n mergedCellsAlign?: MergedCellsAlign;\n};"
|
|
52485
|
+
},
|
|
52486
|
+
{
|
|
52487
|
+
"typeName": "MergedCellsAlign",
|
|
52488
|
+
"source": "type MergedCellsAlign = {\n /** По горизонтали. @default из `contentFormat.alignContent` колонки, иначе 'left' */\n horizontal?: 'left' | 'center' | 'right';\n /** По вертикали. @default 'center' */\n vertical?: 'top' | 'center' | 'bottom';\n};"
|
|
52489
|
+
},
|
|
52490
|
+
{
|
|
52491
|
+
"typeName": "RowsGrouping",
|
|
52492
|
+
"source": "type 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};"
|
|
52493
|
+
},
|
|
52494
|
+
{
|
|
52495
|
+
"typeName": "SubRows",
|
|
52496
|
+
"source": "type 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};"
|
|
52497
|
+
}
|
|
52498
|
+
],
|
|
52499
|
+
"stories": [
|
|
52500
|
+
{
|
|
52501
|
+
"exportName": "BigDataExample",
|
|
52502
|
+
"displayName": "Большой набор данных (строки × колонки)",
|
|
52503
|
+
"type": "full-code",
|
|
52504
|
+
"code": "() => {\n const [cols, setCols] = useState(1000);\n const [rowInput, setRowInput] = useState('50000');\n const [rowTarget, setRowTarget] = useState(50000);\n const [withMerge, setWithMerge] = useState(true);\n const [heavyCells, setHeavyCells] = useState(true);\n const [withEditing, setWithEditing] = useState(false);\n // Правки пользователя поверх сгенерированных данных (режим редактирования).\n const [editedRows, setEditedRows] = useState<Node[] | null>(null);\n\n const commitsRef = useRef<number[]>([]);\n const onRender = useCallback(\n (_id: string, _phase: string, actualDuration: number) => {\n commitsRef.current.push(actualDuration);\n },\n [],\n );\n\n const { rows: builtRows, leaves } = useMemo(\n () => buildData(rowTarget, withMerge),\n [rowTarget, withMerge],\n );\n\n useEffect(() => {\n setEditedRows(null);\n }, [builtRows]);\n\n const dataRows = editedRows ?? builtRows;\n\n const columns = useMemo(\n () => buildColumns(cols, heavyCells, withEditing),\n [cols, heavyCells, withEditing],\n );\n\n const tableConfig = useMemo(\n () => ({\n containerStyle: { height: '70vh' },\n rowMarkers: { startIndex: 1 },\n resizableColumn: true,\n columnsControl: {\n enable: true,\n pinning: true,\n },\n ...(withMerge\n ? {\n subRows: {\n getSubRows: (row: Node) => row?.subRows,\n rowKeyGetter: (row: Node) => row.id,\n view: 'merged' as const,\n mergedColumns: ['division', 'unit', 'team'],\n },\n }\n : {}),\n ...(withEditing\n ? {\n editing: {\n onRowsChange: (next: Node[]) => setEditedRows(next),\n rowKeyGetter: (r: Node) => r.id,\n },\n }\n : {}),\n }),\n [withMerge, withEditing],\n );\n\n return (\n <div>\n <StoryHint>\n Пример на большом наборе данных: настройте число колонок и строк,\n включите нужные режимы и проверяйте выделение, скролл, сайдбар и\n редактирование. HUD справа показывает метрики производительности: FPS\n — кадров в секунду (ниже 40 подсвечивается красным); «коммитов/с» —\n сколько раз в секунду React перерендерил таблицу (при протяжке\n выделения каждый шаг мыши даёт один коммит); «коммит сред/макс» —\n среднее и максимальное время одного такого перерендера в\n миллисекундах, то есть цена реакции таблицы на одно действие.\n </StoryHint>\n\n <div\n style={{\n display: 'flex',\n gap: 24,\n alignItems: 'center',\n flexWrap: 'wrap',\n padding: '8px 4px 12px',\n fontSize: 13,\n }}\n >\n <span style={{ display: 'flex', gap: 8, alignItems: 'center' }}>\n Колонок: <b style={{ minWidth: 42 }}>{cols}</b>\n <div style={{ width: 220 }}>\n <Slider\n value={cols}\n min={1}\n max={1500}\n onChangeCommitted={(value) => setCols(value)}\n />\n </div>\n </span>\n\n <span style={{ display: 'flex', gap: 8, alignItems: 'center' }}>\n Строк:\n <div style={{ width: 130 }}>\n <TextField\n value={rowInput}\n type=\"number\"\n size=\"s\"\n onChange={(e) => setRowInput(e.target.value)}\n />\n </div>\n <Button\n size=\"s\"\n view=\"secondary\"\n onClick={() => setRowTarget(Math.max(1, Number(rowInput) || 1))}\n >\n Построить\n </Button>\n <span style={{ opacity: 0.75 }}>\n (листьев: <b>{fmt(leaves)}</b>)\n </span>\n </span>\n\n <Checkbox\n label=\"объединение (subRows merged)\"\n checked={withMerge}\n onChange={(e) => setWithMerge(e.target.checked)}\n />\n\n <Checkbox\n label=\"тяжёлые ячейки (Canvas.Badge)\"\n checked={heavyCells}\n onChange={(e) => setHeavyCells(e.target.checked)}\n />\n\n <Checkbox\n label=\"редактирование (error-ячейки)\"\n checked={withEditing}\n onChange={(e) => setWithEditing(e.target.checked)}\n />\n\n <PerfHudBadge commitsRef={commitsRef} />\n </div>\n\n <Profiler id=\"big-data-table\" onRender={onRender}>\n <TableCanvas\n tableConfig={tableConfig}\n columnConfig={columns}\n rows={dataRows as Node[]}\n />\n </Profiler>\n </div>\n );\n }"
|
|
52505
|
+
},
|
|
52506
|
+
{
|
|
52507
|
+
"exportName": "RowSpanBasic",
|
|
52508
|
+
"displayName": "mergeByCellValues: объединение по значению",
|
|
52509
|
+
"type": "full-code",
|
|
52510
|
+
"code": "import { useMemo, useRef, useState } from 'react';\nimport { Select } from '@daisforge/ui';\nimport {\n Canvas,\n type CellsSelectionMode,\n type ColumnConfig,\n type HighlightActiveType,\n TableCanvas,\n} from '@daisforge/ui/components/TableCanvas';\n\ntype Row = {\n id: number;\n role: string;\n dept: string;\n period: string;\n plan: number;\n fact: number;\n};\n\n// role/dept повторяются в данных блоками по 3 строки — объединение\n// выводится из повторяющихся значений, данные не мутируются.\nconst GROUPS = [\n { role: 'Аналитик', dept: 'Отдел A' },\n { role: 'Разработчик', dept: 'Отдел B' },\n { role: 'Тестировщик', dept: 'Отдел C' },\n { role: 'Менеджер', dept: 'Отдел D' },\n];\nconst PERIODS = ['Q1', 'Q2', 'Q3'];\nconst INITIAL_ROWS: Row[] = [];\nlet counter = 1;\nfor (const g of GROUPS) {\n for (const p of PERIODS) {\n INITIAL_ROWS.push({\n id: counter,\n role: g.role,\n dept: g.dept,\n period: p,\n plan: counter * 10,\n fact: counter * 8,\n });\n counter += 1;\n }\n}\n\nconst SELECTION_MODE_OPTIONS: Array<{\n label: string;\n value: CellsSelectionMode;\n}> = [\n { label: 'cell', value: 'cell' },\n { label: 'range-cell', value: 'range-cell' },\n { label: 'multi-range-cell', value: 'multi-range-cell' },\n { label: 'disabled', value: 'disabled' },\n];\n\nconst HIGHLIGHT_ACTIVE_TYPE_OPTIONS: Array<{\n label: string;\n value: HighlightActiveType;\n}> = [\n { label: 'row', value: 'row' },\n { label: 'disabled', value: 'disabled' },\n];\n\nexport const Example = () => {\n const [rows, setRows] = useState<Row[]>(INITIAL_ROWS);\n const beforeEditRef = useRef(rows);\n const [selectionMode, setSelectionMode] =\n useState<CellsSelectionMode>('range-cell');\n const [highlightActiveType, setHighlightActiveType] =\n useState<HighlightActiveType>('disabled');\n\n const columns = useMemo<readonly ColumnConfig<Row>[]>(\n () => [\n { key: 'role', name: 'Роль (merge ×3)', width: 220 },\n {\n key: 'dept',\n name: 'Отдел (custom + merge ×3)',\n width: 220,\n renderCell: ({ row, theme }) => (\n <Canvas.Container padding={8} alignItems=\"center\" justifyContent=\"center\">\n <Canvas.Text color={theme.textDark}>{row.dept}</Canvas.Text>\n </Canvas.Container>\n ),\n copyData: (row) => row.dept,\n // У canvas-колонок превью по умолчанию выключено — включаем явно.\n renderCellPreview: 'cellEditorAsPreview',\n },\n { key: 'period', name: 'Период', width: 120, editingCell: { component: 'inputString' } },\n { key: 'plan', name: 'План', width: 120, editingCell: { component: 'inputNumber' } },\n { key: 'fact', name: 'Факт', width: 120, editingCell: { component: 'inputNumber' } },\n ],\n [],\n );\n\n return (\n <div>\n <div style={{ display: 'flex', gap: 16, marginBottom: 12 }}>\n <Select\n target=\"textfield-like\"\n label=\"Режим выделения\"\n value={selectionMode}\n onChange={(v) => setSelectionMode(v as CellsSelectionMode)}\n items={SELECTION_MODE_OPTIONS}\n />\n <Select\n target=\"textfield-like\"\n label=\"Highlight active\"\n value={highlightActiveType}\n onChange={(v) => setHighlightActiveType(v as HighlightActiveType)}\n items={HIGHLIGHT_ACTIVE_TYPE_OPTIONS}\n />\n </div>\n <TableCanvas\n tableConfig={{\n containerStyle: { height: '600px' },\n highlightActiveType,\n rowMarkers: { startIndex: 1 },\n columnsControl: { enable: true },\n rowSize: { default: 'medium', showInControl: true },\n fullScreenEnabled: true,\n mergeCells: { mergeByCellValues: ['role', 'dept'] },\n cellsSelection: { mode: selectionMode, enableColumnSelection: true },\n cellTransfer: { fillHandle: true },\n editing: {\n onRowsChange: setRows,\n rowKeyGetter: (r) => \\"
|
|
52511
|
+
},
|
|
52512
|
+
{
|
|
52513
|
+
"exportName": "DerivedGroupingSortFilter",
|
|
52514
|
+
"displayName": "mergeByCellValues: сортировка и фильтр",
|
|
52515
|
+
"type": "full-code",
|
|
52516
|
+
"code": "import { useState } from 'react';\nimport {\n type ColumnConfig,\n type SortColumn,\n TableCanvas,\n} from '@daisforge/ui/components/TableCanvas';\n\ntype Row = {\n id: number;\n role: string;\n dept: string;\n person: string;\n plan: number;\n};\n\nconst GROUPS = [\n { role: 'Аналитик', dept: 'Отдел A' },\n { role: 'Разработчик', dept: 'Отдел B' },\n { role: 'Тестировщик', dept: 'Отдел C' },\n { role: 'Менеджер', dept: 'Отдел D' },\n];\nconst ALL: Row[] = [];\nlet counter = 1;\nfor (const g of GROUPS) {\n for (let p = 0; p < 3; p += 1) {\n ALL.push({\n id: counter,\n role: g.role,\n dept: g.dept,\n person: \\"
|
|
52517
|
+
},
|
|
52518
|
+
{
|
|
52519
|
+
"exportName": "SpanByWithEditing",
|
|
52520
|
+
"displayName": "mergeByCellValues: редактирование",
|
|
52521
|
+
"type": "full-code",
|
|
52522
|
+
"code": "import { useRef, useState } from 'react';\nimport {\n type ColumnConfig,\n TableCanvas,\n} from '@daisforge/ui/components/TableCanvas';\n\ntype Row = { id: number; region: string; team: string; person: string };\n\n// 6 регионов × 4 строки: регион слит блоками по 4, команда — по 2 (вложенно).\nconst REGIONS = ['Север', 'Юг', 'Запад', 'Восток', 'Центр', 'Урал'];\nconst INITIAL_ROWS: Row[] = [];\nlet c = 1;\nfor (const region of REGIONS) {\n for (let t = 0; t < 4; t += 1) {\n INITIAL_ROWS.push({\n id: c,\n region,\n team: \\"
|
|
52523
|
+
},
|
|
52524
|
+
{
|
|
52525
|
+
"exportName": "MergedSelectEditing",
|
|
52526
|
+
"displayName": "Select в объединённой ячейке",
|
|
52527
|
+
"type": "full-code",
|
|
52528
|
+
"code": "import { useRef, useState } from 'react';\nimport {\n type ColumnConfig,\n TableCanvas,\n} from '@daisforge/ui/components/TableCanvas';\n\ntype Row = {\n id: number;\n status: string;\n owner: string;\n priority: string;\n stage: string;\n task: string;\n};\n\nconst STATUSES = ['В работе', 'Готово', 'Отменено', 'На паузе'];\nconst OWNERS = ['Иванов', 'Петров', 'Сидоров'];\nconst PRIORITIES = ['Высокий', 'Средний', 'Низкий'];\n// Неслитый Select (per-row) — для проверки обычных ячеек рядом со слитыми.\nconst STAGES = ['Анализ', 'Разработка', 'Тест', 'Релиз'];\n\n// Блоки разной высоты: 4 строки, 3 строки, 2 строки. Все три select-колонки\n// слиты синхронно (одинаковые границы).\nconst INITIAL_ROWS: Row[] = [\n { id: 1, status: 'В работе', owner: 'Иванов', priority: 'Высокий', stage: 'Анализ', task: 'Задача 1' },\n { id: 2, status: 'В работе', owner: 'Иванов', priority: 'Высокий', stage: 'Разработка', task: 'Задача 2' },\n { id: 3, status: 'В работе', owner: 'Иванов', priority: 'Высокий', stage: 'Тест', task: 'Задача 3' },\n { id: 4, status: 'В работе', owner: 'Иванов', priority: 'Высокий', stage: 'Релиз', task: 'Задача 4' },\n { id: 5, status: 'Готово', owner: 'Петров', priority: 'Средний', stage: 'Анализ', task: 'Задача 5' },\n { id: 6, status: 'Готово', owner: 'Петров', priority: 'Средний', stage: 'Разработка', task: 'Задача 6' },\n { id: 7, status: 'Готово', owner: 'Петров', priority: 'Средний', stage: 'Тест', task: 'Задача 7' },\n { id: 8, status: 'Отменено', owner: 'Сидоров', priority: 'Низкий', stage: 'Анализ', task: 'Задача 8' },\n { id: 9, status: 'Отменено', owner: 'Сидоров', priority: 'Низкий', stage: 'Релиз', task: 'Задача 9' },\n];\n\nconst columns: readonly ColumnConfig<Row>[] = [\n {\n key: 'status',\n name: 'Статус — низ/лево',\n width: 220,\n // Выравнивание контента блока: вертикаль низ, горизонталь лево.\n mergedCellsAlign: { vertical: 'bottom', horizontal: 'left' },\n editingCell: {\n component: 'select',\n options: {\n type: 'constant',\n options: STATUSES.map((s) => ({ text: s, value: s })),\n },\n },\n },\n {\n key: 'owner',\n name: 'Ответственный — низ/право',\n width: 220,\n mergedCellsAlign: { vertical: 'bottom', horizontal: 'right' },\n editingCell: {\n component: 'select',\n options: {\n type: 'constant',\n options: OWNERS.map((s) => ({ text: s, value: s })),\n },\n },\n },\n {\n key: 'priority',\n name: 'Приоритет — центр/центр',\n width: 200,\n mergedCellsAlign: { vertical: 'center', horizontal: 'center' },\n editingCell: {\n component: 'select',\n options: {\n type: 'constant',\n options: PRIORITIES.map((s) => ({ text: s, value: s })),\n },\n },\n },\n {\n key: 'stage',\n name: 'Этап (Select, НЕ слит)',\n width: 200,\n editingCell: {\n component: 'select',\n options: {\n type: 'constant',\n options: STAGES.map((s) => ({ text: s, value: s })),\n },\n },\n },\n {\n key: 'task',\n name: 'Задача (текст, не слит)',\n width: 180,\n editingCell: { component: 'inputString' },\n },\n];\n\nexport const Example = () => {\n const [rows, setRows] = useState<Row[]>(INITIAL_ROWS);\n const beforeEditRef = useRef(rows);\n\n return (\n <TableCanvas\n tableConfig={{\n containerStyle: { height: '560px' },\n rowMarkers: { startIndex: 1 },\n columnsControl: { enable: true },\n rowSize: { default: 'medium', showInControl: true },\n fullScreenEnabled: true,\n mergeCells: {\n mergeByCellValues: ['status', 'owner', 'priority'],\n },\n cellsSelection: { mode: 'range-cell' },\n editing: {\n onRowsChange: setRows,\n rowKeyGetter: (r) => \\"
|
|
52529
|
+
},
|
|
52530
|
+
{
|
|
52531
|
+
"exportName": "Colspan",
|
|
52532
|
+
"displayName": "mergedCellsRegions: заголовки секций",
|
|
52533
|
+
"type": "full-code",
|
|
52534
|
+
"code": "import { useMemo, useRef, useState } from 'react';\nimport {\n Canvas,\n type ColumnConfig,\n TableCanvas,\n} from '@daisforge/ui/components/TableCanvas';\n\ntype Row = {\n id: number;\n kind: 'header' | 'data';\n label: string;\n a: string;\n b: string;\n};\n\n// Правило блока: данные одинаковы во всех его ячейках. Блок показывает свою\n// левую верхнюю видимую ячейку, а после закрепления или перестановки колонок\n// ею может стать другая колонка — заголовок при этом останется видимым.\nconst buildRows = (): Row[] => {\n const out: Row[] = [];\n let id = 1;\n for (let s = 0; s < 3; s += 1) {\n out.push({\n id: id++,\n kind: 'header',\n label: \\"
|
|
52535
|
+
},
|
|
52536
|
+
{
|
|
52537
|
+
"exportName": "Rectangular",
|
|
52538
|
+
"displayName": "mergedCellsRegions: прямоугольный блок",
|
|
52539
|
+
"type": "full-code",
|
|
52540
|
+
"code": "import { useRef, useState } from 'react';\nimport {\n Canvas,\n type ColumnConfig,\n TableCanvas,\n} from '@daisforge/ui/components/TableCanvas';\n\ntype Row = { id: number; a: string; b: string; c: string; d: string };\n\nconst INITIAL_ROWS: Row[] = Array.from({ length: 10 }, (_, i) => ({\n id: i + 1,\n a: \\"
|
|
52541
|
+
},
|
|
52542
|
+
{
|
|
52543
|
+
"exportName": "ControlledSpans",
|
|
52544
|
+
"displayName": "mergedCellsRegions: управление кнопками",
|
|
52545
|
+
"type": "full-code",
|
|
52546
|
+
"code": "import { useState } from 'react';\nimport { Button } from '@daisforge/ui';\nimport {\n type ColumnConfig,\n type MergedCellsRegion,\n type SortColumn,\n TableCanvas,\n} from '@daisforge/ui/components/TableCanvas';\n\ntype Row = {\n id: number;\n dept: string;\n role: string;\n person: string;\n plan: number;\n};\n\nconst GROUPS = [\n { dept: 'Отдел A', role: 'Аналитик', ids: [1, 2, 3] },\n { dept: 'Отдел B', role: 'Разработчик', ids: [4, 5, 6] },\n { dept: 'Отдел C', role: 'Тестировщик', ids: [7, 8, 9, 10] },\n];\nconst ROWS: Row[] = [];\nfor (const g of GROUPS) {\n for (const id of g.ids) {\n ROWS.push({\n id,\n dept: g.dept,\n role: g.role,\n person: \\"
|
|
52547
|
+
},
|
|
52548
|
+
{
|
|
52549
|
+
"exportName": "FormatInBlock",
|
|
52550
|
+
"displayName": "Форматирование и свой рендер в блоке",
|
|
52551
|
+
"type": "full-code",
|
|
52552
|
+
"code": "import { useState } from 'react';\nimport { Button } from '@daisforge/ui';\nimport {\n Canvas,\n type ColumnConfig,\n type MergedCellsRegion,\n TableCanvas,\n} from '@daisforge/ui/components/TableCanvas';\n\ntype Row = {\n id: number;\n dept: string;\n role: string;\n person: string;\n plan: number;\n fact: number;\n};\n\n// dept/role повторяются в данных: 3 отдела, в каждом 2 роли по 2 сотрудника.\nconst DEPTS = [\n { dept: 'Отдел A', roles: ['Аналитик', 'Разработчик'] },\n { dept: 'Отдел B', roles: ['Разработчик', 'Тестировщик'] },\n { dept: 'Отдел C', roles: ['Менеджер', 'Аналитик'] },\n];\nconst ROWS: Row[] = [];\nlet id = 1;\nfor (const d of DEPTS) {\n for (const role of d.roles) {\n for (let i = 0; i < 2; i += 1) {\n ROWS.push({\n id,\n dept: d.dept,\n role,\n person: \\"
|
|
52553
|
+
},
|
|
52554
|
+
{
|
|
52555
|
+
"exportName": "Showcase",
|
|
52556
|
+
"displayName": "mergeByCellValues: пример с серверными данными",
|
|
52557
|
+
"type": "full-code",
|
|
52558
|
+
"code": "import { useEffect, useMemo, useRef, useState } from 'react';\nimport {\n type ColumnConfig,\n type ColumnOrColumnGroupConfig,\n type SortColumn,\n TableCanvas,\n} from '@daisforge/ui/components/TableCanvas';\n\n// Строка-лист: сотрудник, показатели и путь предков, продублированный в строке.\n// Ключи пути (divPath/unitPath/teamPath) учитывают предков — по ним\n// объединяются колонки-предки, одинаковые имена в разных ветках не сливаются.\ntype Row = {\n id: string;\n division: string;\n unit: string;\n team: string;\n employee: string;\n plan: number;\n fact: number;\n divPath: string;\n unitPath: string;\n teamPath: string;\n};\n\n// Оргструктура «от бэка»: дивизион -> управление -> команда -> сотрудники.\nconst ORG = [\n {\n name: 'Розничный бизнес',\n units: [\n { name: 'Управление продаж', teams: ['Команда Север', 'Команда Юг'] },\n { name: 'Управление сервиса', teams: ['Команда Онлайн'] },\n ],\n },\n {\n name: 'Корпоративный бизнес',\n units: [\n { name: 'Управление КИБ', teams: ['Команда Крупные', 'Команда СМБ'] },\n ],\n },\n];\nconst SURNAMES = ['Иванов', 'Петрова', 'Сидоров', 'Кузнецова', 'Смирнов'];\n\nconst buildRows = (): Row[] => {\n const out: Row[] = [];\n let g = 0;\n for (const div of ORG) {\n for (const unit of div.units) {\n for (const team of unit.teams) {\n // По 12 сотрудников в команде — крупные блоки под merge и пагинацию.\n for (let i = 0; i < 12; i += 1) {\n const plan = 600000 + ((g * 37) % 18) * 100000;\n out.push({\n id: \\"
|
|
52559
|
+
},
|
|
52560
|
+
{
|
|
52561
|
+
"exportName": "SubRowsMerged",
|
|
52562
|
+
"displayName": "subRows: дерево с пагинацией",
|
|
52563
|
+
"type": "full-code",
|
|
52564
|
+
"code": "import { useEffect, useMemo, useRef, useState } from 'react';\nimport {\n type ColumnConfig,\n type SortColumn,\n TableCanvas,\n} from '@daisforge/ui/components/TableCanvas';\n\n// Узел дерева: узлы-предки несут своё поле (division/unit/team), листья — строки с показателями.\ntype Node = {\n id: string;\n division?: string;\n unit?: string;\n team?: string;\n employee?: string;\n plan?: number;\n fact?: number;\n subRows?: Node[];\n};\n\nconst ORG = [\n {\n name: 'Розничный бизнес',\n units: [\n { name: 'Управление продаж', teams: ['Команда Север', 'Команда Юг'] },\n { name: 'Управление сервиса', teams: ['Команда Онлайн'] },\n ],\n },\n {\n name: 'Корпоративный бизнес',\n units: [\n { name: 'Управление КИБ', teams: ['Команда Крупные', 'Команда СМБ'] },\n ],\n },\n];\nconst SURNAMES = ['Иванов', 'Петрова', 'Сидоров', 'Кузнецова', 'Смирнов'];\n\n// Дерево «от бэка»: дивизион -> управление -> команда -> сотрудники (листья).\nlet g = 0;\nconst TREE: Node[] = ORG.map((div, di) => ({\n id: \\"
|
|
52565
|
+
},
|
|
52566
|
+
{
|
|
52567
|
+
"exportName": "GroupingMerged",
|
|
52568
|
+
"displayName": "rowsGrouping: группировка пользователем",
|
|
52569
|
+
"type": "full-code",
|
|
52570
|
+
"code": "import { useRef, useState } from 'react';\nimport {\n type ColumnConfig,\n type SortColumn,\n TableCanvas,\n} from '@daisforge/ui/components/TableCanvas';\n\n// Плоские листья на входе, дерево строит сама таблица по groupByState.\ntype Row = {\n id: string;\n division: string;\n unit: string;\n team: string;\n employee: string;\n plan: number;\n fact: number;\n};\n\nconst ORG = [\n {\n name: 'Розничный бизнес',\n units: [\n { name: 'Управление продаж', teams: ['Команда Север', 'Команда Юг'] },\n { name: 'Управление сервиса', teams: ['Команда Онлайн'] },\n ],\n },\n {\n name: 'Корпоративный бизнес',\n units: [\n { name: 'Управление КИБ', teams: ['Команда Крупные', 'Команда СМБ'] },\n ],\n },\n];\nconst SURNAMES = ['Иванов', 'Петрова', 'Сидоров', 'Кузнецова', 'Смирнов'];\n\nconst buildRows = (): Row[] => {\n const out: Row[] = [];\n let g = 0;\n for (const div of ORG) {\n for (const unit of div.units) {\n for (const team of unit.teams) {\n for (let i = 0; i < 12; i += 1) {\n const plan = 600000 + ((g * 37) % 18) * 100000;\n out.push({\n id: \\"
|
|
52571
|
+
}
|
|
52572
|
+
]
|
|
52573
|
+
},
|
|
52088
52574
|
{
|
|
52089
52575
|
"component": "TableCanvas",
|
|
52090
52576
|
"feature": "ColumnResize",
|
|
@@ -52159,12 +52645,16 @@
|
|
|
52159
52645
|
"feature": "ColumnsControl",
|
|
52160
52646
|
"legacy": false,
|
|
52161
52647
|
"summary": "*tableConfig.columnsControl**",
|
|
52162
|
-
"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)",
|
|
52163
|
-
"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 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```",
|
|
52164
52650
|
"api": [
|
|
52165
52651
|
{
|
|
52166
52652
|
"typeName": "ColumnsControlConfig",
|
|
52167
|
-
"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 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};"
|
|
52168
52658
|
},
|
|
52169
52659
|
{
|
|
52170
52660
|
"typeName": "PinningMenuConfig",
|
|
@@ -52193,6 +52683,36 @@
|
|
|
52193
52683
|
"displayName": "ID",
|
|
52194
52684
|
"type": "full-code",
|
|
52195
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 }"
|
|
52196
52716
|
}
|
|
52197
52717
|
]
|
|
52198
52718
|
},
|
|
@@ -52506,7 +53026,7 @@
|
|
|
52506
53026
|
"feature": "CopyPasteFill",
|
|
52507
53027
|
"legacy": false,
|
|
52508
53028
|
"summary": "*tableConfig.cellTransfer**",
|
|
52509
|
-
"docs": "# Clipboard — копирование, вставка, fill handle\n\n**tableConfig.cellTransfer**\n\nФича реализует Copy (Ctrl+C), Paste (Ctrl+V) и Fill Handle (drag-to-fill) для TableCanvas.\n\n---\n\n## Формат данных\n\nДанные копируются и вставляются в формате **TSV (Tab-Separated Values)** — тот же\nформат, который использует Excel и Google Sheets. Значения разделяются `\\t` (tab)\nмежду колонками и `\\n` между строками.\n\nБлагодаря этому:\n\n- Скопированное из TableCanvas можно вставить в Excel / Google Sheets\n- Скопированное из Excel можно вставить в TableCanvas\n\n---\n\n## Copy (Ctrl+C / Cmd+C)\n\nКопирование работает всегда — и в режиме редактирования, и без него.\nОтключить можно только явно через `cellTransfer: { enabled: false }`.\n\nКопируется ровно то, что сейчас выделено в таблице (`selection.current.range`).\nФича не привязана к `highlightActiveType` — она работает с фактическим\nвыделением, а не с тем, как оно визуально подсвечивается.\n\n### Что копируется из ячейки\n\nДля обычной ячейки: `row[column.key]?.toString()`.\n\nДля кастомной canvas-ячейки (Canvas.Badge, Canvas.Text и т.д.) текст из canvas\nавтоматически извлечь нельзя. Поэтому используется `copyData` в конфиге\nколонки:\n\n```tsx\n{\n key: 'status',\n renderCell: ({ row }) => (\n <Canvas.Badge text={row.status} view=\"positive\" size=\"s\" />\n ),\n // Указываем, что копировать — текстовое значение из row\n copyData: (row) => row.status ?? '',\n}\n```\n\nЕсли `copyData` не указан, используется fallback на `row[column.key]?.toString()`.\nДля canvas-ячеек это может дать пустую строку или `[object Object]`, поэтому\n`copyData` рекомендуется всегда указывать для кастомных рендеров.\n\n### SubRows при копировании\n\nДля колонок с `subRow.keyOfColumnInSubRow` данные subrow-ячеек автоматически\nизвлекаются из нужного поля:\n\n```tsx\n{\n key: 'block',\n subRow: {\n keyOfColumnInSubRow: (lvl) => {\n switch (lvl) {\n case 1: return 'tribe';\n case 2: return 'product';\n default: return 'block';\n }\n },\n },\n}\n// Для parent (lvl=0): копирует row.block\n// Для subrow lvl=1: копирует row.tribe\n// Для subrow lvl=2: копирует row.product\n```\n\n---\n\n## Paste (Ctrl+V / Cmd+V)\n\nВставка работает только в режиме редактирования (`editing` активен).\n\nПорядок действий при вставке:\n\n1. Чтение TSV из clipboard (`navigator.clipboard.readText`)\n2. Парсинг в 2D-массив строк\n3. Определение целевой ячейки (из текущего selection)\n4. Применение значений начиная от целевой ячейки вправо и вниз\n\n### Валидация типов при вставке (type-check)\n\nПо умолчанию включена проверка `paste.validation: 'type-check'`:\n\n- **`inputNumber` / `contentFormat: 'number'`** — значение должно парситься в число. Если нет, ячейка пропускается.\n- **`select` (ComboBox)** — значение должно совпадать с одной из `options` (по `value` или `text`). Если нет, ячейка пропускается.\n- **`inputString`** — всегда валидно, строка вставляется как есть.\n\nНевалидные ячейки пропускаются, остальные вставляются нормально.\n\nОтключить: `paste: { validation: 'none' }`.\n\nРазделители для парсинга чисел берутся из `column.contentFormat`\n(`decimalSeparator`, `thousandSeparator`), а не из локали.\n\n### Readonly-ячейки\n\nПо умолчанию (`readonlyBehavior: 'skip'`) readonly-ячейки пропускаются,\nостальные вставляются нормально.\n\nПри `readonlyBehavior: 'abort'` любая readonly-ячейка в зоне вставки отменяет\nвсю вставку целиком (поведение Excel).\n\n### Выход за границы\n\nПо умолчанию (`overflowBehavior: 'truncate'`) данные обрезаются по границе\nтаблицы. То, что не влезло, теряется.\n\nПри `overflowBehavior: 'abort'` вставка отменяется, если данные не влезают.\n\n### Вставка в кастомные ячейки (Canvas.Badge и т.д.)\n\n`writeCellValue` пишет строку в `row[column.key]`. Кастомный рендер на следующем\nцикле получает обновлённый `row` и отрисовывает новое значение.\n\nЕсли `renderCell` ожидает в `row[key]` не строку, а объект, вставка строки\nсломает рендер. В этом случае используйте `onBeforePaste` для трансформации:\n\n```tsx\ncellTransfer: {\n onBeforePaste: (data, meta) => {\n // Трансформировать строки в нужные объекты\n return data.map((row, y) =>\n row.map((value, x) => {\n const cell = meta.targetCells[y]?.[x];\n if (cell?.column.key === 'complexField') {\n return JSON.stringify({ label: value, color: 'default' });\n }\n return value;\n })\n );\n },\n}\n```\n\n### SubRows при вставке\n\nРаботает аналогично копированию — через `keyOfColumnInSubRow`. Если у subrow\nданные в другом поле, `writeCellValue` запишет в правильный ключ.\n\nОтключить вставку в subrows: `paste: { allowSubRows: false }`.\n\n### Поток данных при вставке (pipeline)\n\nПри Ctrl+V значения проходят через цепочку проверок. Каждый шаг может отменить\nоперацию или пропустить отдельную ячейку:\n\n```\nCtrl+V\n │\n ▼\n1. editModeEnabled?\n └─ нет → СТОП (вставка только в editing)\n │\n ▼\n2. navigator.clipboard.readText() → parseTsv() → string[][]\n └─ пустой clipboard → СТОП\n │\n ▼\n3. onBeforePaste(data, meta)?\n └─ вернул false -> СТОП (пользователь отменил)\n └─ вернул модифицированный data → используем его\n │\n ▼\n4. overflowBehavior: данные выходят за границы?\n └─ 'abort' → СТОП\n └─ 'truncate' → обрезаем (default)\n │\n ▼\n5. readonlyBehavior: есть readonly-ячейки в зоне вставки?\n └─ 'abort' → СТОП (первый проход, до записи)\n └─ 'skip' → пропускаем эти ячейки (default)\n │\n ▼\n6. Для каждой ячейки:\n │\n ├─ shouldSkipCell?\n │ ├─ no-row / нет колонки → skip\n │ ├─ service-column → skip\n │ ├─ subrow + !allowSubRows → skip\n │ └─ not-editable → skip\n │\n ├─ validation: 'type-check'?\n │ ├─ inputNumber: не парсится в число → skip\n │ ├─ select: значения нет в options → skip\n │ └─ inputString: OK\n │\n └─ writeCellValue(row, column, lvl, value) → запись\n │\n ▼\n7. onRowsChange(newRows, { column, indexes })\n tree update → setRows → re-render\n```\n\nFill handle проходит тот же pipeline начиная с шага 6 (без clipboard, без\noverflow — TableCanvas сам ограничивает destination range). Перед записью вызывается\n`onBeforeFill(data, meta)` — аналог `onBeforePaste` для fill handle.\n\n---\n\n## Нотификации об ошибках\n\nОшибки copy / paste / fill дополнительно сообщаются во внешний модуль\n[Notifications](?path=/docs/локальные-компоненты-tablecanvas-notifications--docs)\nчерез `tableConfig.notifications.onNotification` — таблица UI не рисует, тост\nпоказывает потребитель (`type` = операция):\n\n- `paste` / `readonly-abort` — при `readonlyBehavior: 'abort'` в зоне вставки\n есть readonly-ячейка;\n- `paste` / `overflow-abort` — при `overflowBehavior: 'abort'` данные не влезли;\n- `paste` / `validation-skipped` (`warning`) — часть значений пропущена\n type-check валидацией;\n- `fill` / `readonly-abort` и `fill` / `validation-skipped` — то же для\n автозаполнения (fill handle);\n- `copy` / `paste` с code `multi-range-scattered` — 2D-разброс в\n `multi-range-cell`.\n\n## Перехват данных — onBeforeCopy / onBeforePaste\n\nКолбэки вызываются перед операцией. Получают:\n\n- Первый аргумент: `data: string[][]` — 2D-массив значений (TSV-формат)\n- Второй аргумент: `meta` — информация о ячейках\n\n### onBeforeCopy\n\n```tsx\ncellTransfer: {\n onBeforeCopy: (data, meta) => {\n // data — string[][] (что будет в clipboard)\n // meta.range — Rectangle выделения\n // meta.cells — CellTransferCellInfo[][] (row, column, lvl, rawValue, formattedValue)\n\n console.log('Копируем:', data);\n console.log('Колонки:', meta.cells[0]?.map(c => c.column.key));\n\n // Модифицировать данные:\n return data.map(row => row.map(val => val.toUpperCase()));\n\n // Или отменить копирование:\n return false;\n },\n}\n```\n\n### onBeforePaste\n\n```tsx\ncellTransfer: {\n onBeforePaste: (data, meta) => {\n // data — string[][] (что из clipboard)\n // meta.target — { col, row } верхний-левый угол вставки\n // meta.targetCells — CellTransferCellInfo[][] (инфа о ЦЕЛЕВЫХ ячейках)\n // meta.selection — GridSelection\n\n // Пример: ограничить кол-во строк\n if (data.length > 100) {\n alert('Слишком много строк для вставки');\n return false;\n }\n\n // Пример: трансформировать данные\n return data;\n },\n}\n```\n\n---\n\n## Fill Handle (drag-to-fill)\n\nВ правом-нижнем углу выделения появляется квадратик. Перетаскивая его мышью,\nможно размножить значения (как в Excel / Google Sheets).\n\nКвадратик и preview-рамку таблица рисует нативно — фича только применяет\nзначения source range в destination range.\n\n### Поведение\n\n- **Одна ячейка** — значение дублируется во все target-ячейки\n- **Диапазон N×M** — значения повторяются циклически\n- **Type-check валидация** — та же, что при paste (числа, select-опции)\n- **Readonly-ячейки** в destination пропускаются\n- **Квадратик скрывается**, если source-ячейка non-editable\n\n### Направления\n\nПо умолчанию `allowedDirections: 'orthogonal'` — snap к ближайшей оси\n(только строки или только колонки, не диагональ).\n\nВарианты: `'horizontal'`, `'vertical'`, `'orthogonal'`, `'any'`.\n\n### Перехват — onBeforeFill\n\nКолбэк `onBeforeFill` вызывается перед применением значений при fill handle.\nПолучает `data: string[][]` и `meta: FillMeta` (см. API — структура meta\nотличается от `CopyMeta` / `PasteMeta`).\n\n```tsx\ncellTransfer: {\n fillHandle: true,\n onBeforeFill: (data, meta) => {\n // data — string[][] (значения, которые будут вставлены)\n // meta.sourceRange — Rectangle источника\n // meta.destinationRange — Rectangle назначения\n // meta.sourceCells — CellTransferCellInfo[][] (исходные ячейки, включая row)\n // meta.targetCells — CellTransferCellInfo[][] (целевые ячейки до заполнения)\n\n const sourceRow = meta.sourceCells[0]?.[0]?.row;\n console.log('Исходная строка:', sourceRow);\n\n // Модифицировать данные:\n return data;\n\n // Или отменить:\n return false;\n },\n}\n```\n\n**Типичный сценарий:** при перетаскивании одной колонки нужно скопировать\nи соседние колонки из исходной строки. Source row доступен через\n`meta.sourceCells[rowIndex][colIndex].row`.\n\n### type в onRowsChange\n\nВторой аргумент `onRowsChange` содержит поле `type` (`'edit'` | `'paste'` | `'fill'`),\nуказывающее источник изменения строк. При `type === 'fill'` дополнительно\nпередаются `fillMeta` (FillMeta) и `fillResult` (результат `onBeforeFill`,\nесли он задан).\n\n---\n\n## Кастомные хоткеи\n\nПо умолчанию: Ctrl+C (copy), Ctrl+V (paste). На Mac — Cmd вместо Ctrl.\n\nХоткеи работают независимо от раскладки (RU/EN) — используется `event.code`\n(`'KeyC'`, `'KeyV'`), а не `event.key` (`'c'`, `'с'`).\n\n```tsx\ncellTransfer: {\n hotkeys: {\n copy: { code: 'KeyC', ctrl: true, alt: true }, // Ctrl+Alt+C\n paste: [\n { code: 'KeyV', ctrl: true }, // Ctrl+V (дефолт сохраняем)\n { code: 'Insert', shift: true }, // Shift+Insert (альтернатива)\n ],\n },\n}\n```\n\nЕсли задать только кастомный хоткей (без массива), дефолтный Ctrl+C / Ctrl+V\nперестаёт работать (replace-семантика). Чтобы сохранить оба варианта,\nпередавайте массив, как в примере для `paste` выше.\n\n---\n\n## Конфигурация\n\n```tsx\ntableConfig={{\n cellTransfer: {\n // Явно включить/выключить (copy работает всегда по умолчанию)\n enabled: true,\n\n // Хоткеи\n hotkeys: { copy: ..., paste: ... },\n\n // Настройки paste\n paste: {\n readonlyBehavior: 'skip' | 'abort', // default: 'skip'\n allowSubRows: true | false, // default: true\n overflowBehavior: 'truncate' | 'abort', // default: 'truncate'\n broadcast: true | false, // default: false\n validation: 'none' | 'type-check', // default: 'type-check'\n },\n\n // Fill handle\n fillHandle: true | false | {\n shape: 'square' | 'circle',\n size: number,\n allowedDirections: 'horizontal' | 'vertical' | 'orthogonal' | 'any',\n readonlyBehavior: 'skip' | 'abort',\n allowSubRows: boolean,\n },\n\n // Перехваты\n onBeforeCopy: (data, meta) => data | false,\n onBeforePaste: (data, meta) => data | false,\n onBeforeFill: (data, meta) => data | false,\n },\n}}\n```\n\n---\n\n## Debug\n\n```js\nwindow.__TABLE_CANVAS_CLIPBOARD_DEBUG__ = true;\n```\n\nВключите уровень \"Verbose\" в DevTools. Префиксы логов:\n\n- `[TableCanvas/cellTransfer]` — перехват хоткеев\n- `[TableCanvas/copy]` — копирование\n- `[TableCanvas/paste]` — вставка (включая skipped by validation)\n- `[TableCanvas/fillHandle]` — fill handle (source, dest, affected rows)\n\nПолное описание API типов см. на странице **Clipboard / API**.",
|
|
53029
|
+
"docs": "# Clipboard — копирование, вставка, fill handle\n\n**tableConfig.cellTransfer**\n\nФича реализует Copy (Ctrl+C), Paste (Ctrl+V) и Fill Handle (drag-to-fill) для TableCanvas.\n\n---\n\n## Формат данных\n\nДанные копируются и вставляются в формате **TSV (Tab-Separated Values)** — тот же\nформат, который использует Excel и Google Sheets. Значения разделяются `\\t` (tab)\nмежду колонками и `\\n` между строками.\n\nБлагодаря этому:\n\n- Скопированное из TableCanvas можно вставить в Excel / Google Sheets\n- Скопированное из Excel можно вставить в TableCanvas\n\n---\n\n## Copy (Ctrl+C / Cmd+C)\n\nКопирование работает всегда — и в режиме редактирования, и без него.\nОтключить можно только явно через `cellTransfer: { enabled: false }`.\n\nКопируется ровно то, что сейчас выделено в таблице (`selection.current.range`).\nФича не привязана к `highlightActiveType` — она работает с фактическим\nвыделением, а не с тем, как оно визуально подсвечивается.\n\n### Что копируется из ячейки\n\nДля обычной ячейки: `row[column.key]?.toString()`.\n\nДля кастомной canvas-ячейки (Canvas.Badge, Canvas.Text и т.д.) текст из canvas\nавтоматически извлечь нельзя. Поэтому используется `copyData` в конфиге\nколонки:\n\n```tsx\n{\n key: 'status',\n renderCell: ({ row }) => (\n <Canvas.Badge text={row.status} view=\"positive\" size=\"s\" />\n ),\n // Указываем, что копировать — текстовое значение из row\n copyData: (row) => row.status ?? '',\n}\n```\n\nЕсли `copyData` не указан, используется fallback на `row[column.key]?.toString()`.\nДля canvas-ячеек это может дать пустую строку или `[object Object]`, поэтому\n`copyData` рекомендуется всегда указывать для кастомных рендеров.\n\n### SubRows при копировании\n\nДля колонок с `subRow.keyOfColumnInSubRow` данные subrow-ячеек автоматически\nизвлекаются из нужного поля:\n\n```tsx\n{\n key: 'block',\n subRow: {\n keyOfColumnInSubRow: (lvl) => {\n switch (lvl) {\n case 1: return 'tribe';\n case 2: return 'product';\n default: return 'block';\n }\n },\n },\n}\n// Для parent (lvl=0): копирует row.block\n// Для subrow lvl=1: копирует row.tribe\n// Для subrow lvl=2: копирует row.product\n```\n\n---\n\n## Paste (Ctrl+V / Cmd+V)\n\nВставка работает только в режиме редактирования (`editing` активен).\n\nПорядок действий при вставке:\n\n1. Чтение TSV из clipboard (`navigator.clipboard.readText`)\n2. Парсинг в 2D-массив строк\n3. Определение целевой ячейки (из текущего selection)\n4. Применение значений начиная от целевой ячейки вправо и вниз\n\n### Валидация типов при вставке (type-check)\n\nПо умолчанию включена проверка `paste.validation: 'type-check'`:\n\n- **`inputNumber` / `contentFormat: 'number'`** — значение должно парситься в число. Если нет, ячейка пропускается.\n- **`select` (ComboBox)** — значение должно совпадать с одной из `options` (по `value` или `text`). Если нет, ячейка пропускается.\n- **`inputString`** — всегда валидно, строка вставляется как есть.\n\nНевалидные ячейки пропускаются, остальные вставляются нормально.\n\nОтключить: `paste: { validation: 'none' }`.\n\nРазделители для парсинга чисел берутся из `column.contentFormat`\n(`decimalSeparator`, `thousandSeparator`), а не из локали.\n\n### Readonly-ячейки\n\nПо умолчанию (`readonlyBehavior: 'skip'`) readonly-ячейки пропускаются,\nостальные вставляются нормально.\n\nПри `readonlyBehavior: 'abort'` любая readonly-ячейка в зоне вставки отменяет\nвсю вставку целиком (поведение Excel).\n\n### Выход за границы\n\nПо умолчанию (`overflowBehavior: 'truncate'`) данные обрезаются по границе\nтаблицы. То, что не влезло, теряется.\n\nПри `overflowBehavior: 'abort'` вставка отменяется, если данные не влезают.\n\n### Вставка в кастомные ячейки (Canvas.Badge и т.д.)\n\n`writeCellValue` пишет строку в `row[column.key]`. Кастомный рендер на следующем\nцикле получает обновлённый `row` и отрисовывает новое значение.\n\nЕсли `renderCell` ожидает в `row[key]` не строку, а объект, вставка строки\nсломает рендер. В этом случае используйте `onBeforePaste` для трансформации:\n\n```tsx\ncellTransfer: {\n onBeforePaste: (data, meta) => {\n // Трансформировать строки в нужные объекты\n return data.map((row, y) =>\n row.map((value, x) => {\n const cell = meta.targetCells[y]?.[x];\n if (cell?.column.key === 'complexField') {\n return JSON.stringify({ label: value, color: 'default' });\n }\n return value;\n })\n );\n },\n}\n```\n\n### SubRows при вставке\n\nРаботает аналогично копированию — через `keyOfColumnInSubRow`. Если у subrow\nданные в другом поле, `writeCellValue` запишет в правильный ключ.\n\nОтключить вставку в subrows: `paste: { allowSubRows: false }`.\n\n### Поток данных при вставке (pipeline)\n\nПри Ctrl+V значения проходят через цепочку проверок. Каждый шаг может отменить\nоперацию или пропустить отдельную ячейку:\n\n```\nCtrl+V\n │\n ▼\n1. editModeEnabled?\n └─ нет → СТОП (вставка только в editing)\n │\n ▼\n2. navigator.clipboard.readText() → parseTsv() → string[][]\n └─ пустой clipboard → СТОП\n │\n ▼\n3. onBeforePaste(data, meta)?\n └─ вернул false -> СТОП (пользователь отменил)\n └─ вернул модифицированный data → используем его\n │\n ▼\n4. overflowBehavior: данные выходят за границы?\n └─ 'abort' → СТОП\n └─ 'truncate' → обрезаем (default)\n │\n ▼\n5. readonlyBehavior: есть readonly-ячейки в зоне вставки?\n └─ 'abort' → СТОП (первый проход, до записи)\n └─ 'skip' → пропускаем эти ячейки (default)\n │\n ▼\n6. Для каждой ячейки:\n │\n ├─ shouldSkipCell?\n │ ├─ no-row / нет колонки → skip\n │ ├─ service-column → skip\n │ ├─ subrow + !allowSubRows → skip\n │ └─ not-editable → skip\n │\n ├─ validation: 'type-check'?\n │ ├─ inputNumber: не парсится в число → skip\n │ ├─ select: значения нет в options → skip\n │ └─ inputString: OK\n │\n └─ writeCellValue(row, column, lvl, value) → запись\n │\n ▼\n7. onRowsChange(newRows, { column, indexes })\n tree update → setRows → re-render\n```\n\nFill handle проходит ту же цепочку начиная с шага 6 (без clipboard и без\noverflow — зону протяжки таблица ограничивает сама). Перед записью вызывается\n`onBeforeFill(data, meta)` — аналог `onBeforePaste` для fill handle.\n\n---\n\n## Нотификации об ошибках\n\nОшибки copy / paste / fill дополнительно сообщаются во внешний модуль\n[Notifications](?path=/docs/локальные-компоненты-tablecanvas-notifications--docs)\nчерез `tableConfig.notifications.onNotification` — таблица UI не рисует, тост\nпоказывает потребитель (`type` = операция):\n\n- `paste` / `readonly-abort` — при `readonlyBehavior: 'abort'` в зоне вставки\n есть readonly-ячейка;\n- `paste` / `overflow-abort` — при `overflowBehavior: 'abort'` данные не влезли;\n- `paste` / `validation-skipped` (`warning`) — часть значений пропущена\n type-check валидацией;\n- `fill` / `readonly-abort` и `fill` / `validation-skipped` — то же для\n автозаполнения (fill handle);\n- `copy` / `paste` с code `multi-range-scattered` — 2D-разброс в\n `multi-range-cell`.\n\n## Перехват данных — onBeforeCopy / onBeforePaste\n\nКолбэки вызываются перед операцией. Получают:\n\n- Первый аргумент: `data: string[][]` — 2D-массив значений (TSV-формат)\n- Второй аргумент: `meta` — информация о ячейках\n\n### onBeforeCopy\n\n```tsx\ncellTransfer: {\n onBeforeCopy: (data, meta) => {\n // data — string[][] (что будет в clipboard)\n // meta.range — Rectangle выделения\n // meta.cells — CellTransferCellInfo[][] (row, column, lvl, rawValue, formattedValue)\n\n console.log('Копируем:', data);\n console.log('Колонки:', meta.cells[0]?.map(c => c.column.key));\n\n // Модифицировать данные:\n return data.map(row => row.map(val => val.toUpperCase()));\n\n // Или отменить копирование:\n return false;\n },\n}\n```\n\n### onBeforePaste\n\n```tsx\ncellTransfer: {\n onBeforePaste: (data, meta) => {\n // data — string[][] (что из clipboard)\n // meta.target — { col, row } верхний-левый угол вставки\n // meta.targetCells — CellTransferCellInfo[][] (инфа о ЦЕЛЕВЫХ ячейках)\n // meta.selection — GridSelection\n\n // Пример: ограничить кол-во строк\n if (data.length > 100) {\n alert('Слишком много строк для вставки');\n return false;\n }\n\n // Пример: трансформировать данные\n return data;\n },\n}\n```\n\n---\n\n## Fill Handle (drag-to-fill)\n\nВ правом-нижнем углу выделения появляется квадратик. Перетаскивая его мышью,\nможно размножить значения (как в Excel / Google Sheets).\n\nКвадратик и preview-рамку таблица рисует нативно — фича только применяет\nзначения source range в destination range.\n\n### Поведение\n\n- **Одна ячейка** — значение дублируется во все target-ячейки\n- **Диапазон N×M** — значения повторяются циклически\n- **Type-check валидация** — та же, что при paste (числа, select-опции)\n- **Readonly-ячейки** в destination пропускаются\n- **Квадратик скрывается**, если source-ячейка non-editable\n\n### Направления\n\nПо умолчанию `allowedDirections: 'orthogonal'` — snap к ближайшей оси\n(только строки или только колонки, не диагональ).\n\nВарианты: `'horizontal'`, `'vertical'`, `'orthogonal'`, `'any'`.\n\n### Перехват — onBeforeFill\n\nКолбэк `onBeforeFill` вызывается перед применением значений при fill handle.\nПолучает `data: string[][]` и `meta: FillMeta` (см. API — структура meta\nотличается от `CopyMeta` / `PasteMeta`).\n\n```tsx\ncellTransfer: {\n fillHandle: true,\n onBeforeFill: (data, meta) => {\n // data — string[][] (значения, которые будут вставлены)\n // meta.sourceRange — Rectangle источника\n // meta.destinationRange — Rectangle назначения\n // meta.sourceCells — CellTransferCellInfo[][] (исходные ячейки, включая row)\n // meta.targetCells — CellTransferCellInfo[][] (целевые ячейки до заполнения)\n\n const sourceRow = meta.sourceCells[0]?.[0]?.row;\n console.log('Исходная строка:', sourceRow);\n\n // Модифицировать данные:\n return data;\n\n // Или отменить:\n return false;\n },\n}\n```\n\n**Типичный сценарий:** при перетаскивании одной колонки нужно скопировать\nи соседние колонки из исходной строки. Source row доступен через\n`meta.sourceCells[rowIndex][colIndex].row`.\n\n### type в onRowsChange\n\nВторой аргумент `onRowsChange` содержит поле `type` (`'edit'` | `'paste'` | `'fill'`),\nуказывающее источник изменения строк. При `type === 'fill'` дополнительно\nпередаются `fillMeta` (FillMeta) и `fillResult` (результат `onBeforeFill`,\nесли он задан).\n\n---\n\n## Кастомные хоткеи\n\nПо умолчанию: Ctrl+C (copy), Ctrl+V (paste). На Mac — Cmd вместо Ctrl.\n\nХоткеи работают независимо от раскладки (RU/EN) — используется `event.code`\n(`'KeyC'`, `'KeyV'`), а не `event.key` (`'c'`, `'с'`).\n\n```tsx\ncellTransfer: {\n hotkeys: {\n copy: { code: 'KeyC', ctrl: true, alt: true }, // Ctrl+Alt+C\n paste: [\n { code: 'KeyV', ctrl: true }, // Ctrl+V (дефолт сохраняем)\n { code: 'Insert', shift: true }, // Shift+Insert (альтернатива)\n ],\n },\n}\n```\n\nЕсли задать только кастомный хоткей (без массива), дефолтный Ctrl+C / Ctrl+V\nперестаёт работать (replace-семантика). Чтобы сохранить оба варианта,\nпередавайте массив, как в примере для `paste` выше.\n\n---\n\n## Конфигурация\n\n```tsx\ntableConfig={{\n cellTransfer: {\n // Явно включить/выключить (copy работает всегда по умолчанию)\n enabled: true,\n\n // Хоткеи\n hotkeys: { copy: ..., paste: ... },\n\n // Настройки paste\n paste: {\n readonlyBehavior: 'skip' | 'abort', // default: 'skip'\n allowSubRows: true | false, // default: true\n overflowBehavior: 'truncate' | 'abort', // default: 'truncate'\n broadcast: true | false, // default: false\n validation: 'none' | 'type-check', // default: 'type-check'\n },\n\n // Fill handle\n fillHandle: true | false | {\n shape: 'square' | 'circle',\n size: number,\n allowedDirections: 'horizontal' | 'vertical' | 'orthogonal' | 'any',\n readonlyBehavior: 'skip' | 'abort',\n allowSubRows: boolean,\n },\n\n // Перехваты\n onBeforeCopy: (data, meta) => data | false,\n onBeforePaste: (data, meta) => data | false,\n onBeforeFill: (data, meta) => data | false,\n },\n}}\n```\n\n---\n\n## Debug\n\n```js\nwindow.__TABLE_CANVAS_CLIPBOARD_DEBUG__ = true;\n```\n\nВключите уровень \"Verbose\" в DevTools. Префиксы логов:\n\n- `[TableCanvas/cellTransfer]` — перехват хоткеев\n- `[TableCanvas/copy]` — копирование\n- `[TableCanvas/paste]` — вставка (включая skipped by validation)\n- `[TableCanvas/fillHandle]` — fill handle (source, dest, affected rows)\n\nПолное описание API типов см. на странице **Clipboard / API**.",
|
|
52510
53030
|
"apiDocs": "# Cell Transfer API (Copy / Paste / Fill)\n\n## CellTransferConfig (в TableConfig)\n\n```typescript\ntype CellTransferConfig = {\n /**\n * Явное включение/выключение всей фичи.\n * По умолчанию copy работает всегда, а paste и fill handle следуют\n * за `editModeEnabled`. При `false` отключается всё.\n */\n enabled?: boolean;\n /**\n * Переопределение хоткеев.\n * Можно передать один `HotkeyConfig` или массив альтернативных комбинаций.\n * По умолчанию: copy = Ctrl+C / Cmd+C, paste = Ctrl+V / Cmd+V.\n */\n hotkeys?: {\n /** Хоткей(и) для копирования */\n copy?: HotkeyConfig | HotkeyConfig[];\n /** Хоткей(и) для вставки */\n paste?: HotkeyConfig | HotkeyConfig[];\n };\n /** Настройки paste (readonly, overflow, broadcast, validation) */\n paste?: PasteConfig;\n /** Настройки fill handle. `true/false` — быстрое вкл/выкл без деталей */\n fillHandle?: boolean | FillHandleConfig;\n /**\n * Колбэк перед копированием.\n * Можно модифицировать данные (вернуть новый `string[][]`) или отменить\n * операцию (вернуть `false`).\n * Если onBeforeCopy нужен для side-эффектов, то функция должна вернуть data из первого аргумента без изменений.\n */\n onBeforeCopy?: (data: string[][], meta: CopyMeta) => string[][] | false;\n /**\n * Колбэк перед вставкой.\n * Можно модифицировать данные (вернуть новый `string[][]`) или отменить\n * операцию (вернуть `false`).\n * Если onBeforePaste нужен для side-эффектов, то функция должна вернуть data из первого аргумента без изменений.\n */\n onBeforePaste?: (data: string[][], meta: PasteMeta) => string[][] | false;\n /**\n * Колбэк перед fill handle (drag-to-fill).\n * Вызывается перед применением значений. Можно модифицировать данные\n * (вернуть новый `string[][]`) или отменить операцию (вернуть `false`).\n *\n * `meta.sourceCells` содержит полную информацию об исходных ячейках,\n * включая объекты строк (`row`) — позволяет получить source row\n * и использовать данные из соседних колонок.\n * Если onBeforeFill нужен для side-эффектов, то функция должна вернуть data из первого аргумента без изменений.\n */\n onBeforeFill?: (data: string[][], meta: FillMeta) => string[][] | false;\n};\n```\n\n## HotkeyConfig\n\n```typescript\ntype HotkeyConfig = {\n /** Физический код клавиши: `'KeyC'`, `'KeyV'`, `'Insert'` и т.д. */\n code: string;\n /** Нужно ли нажатие Ctrl (на Mac учитывается и Cmd). По умолчанию `true` */\n ctrl?: boolean;\n /** Нужно ли нажатие Shift. По умолчанию `false` */\n shift?: boolean;\n /** Нужно ли нажатие Alt. По умолчанию `false` */\n alt?: boolean;\n /** Нужно ли нажатие Meta (Cmd на Mac, Win на Windows). По умолчанию `false` */\n meta?: boolean;\n};\n```\n\nМожно передать массив — сработает любая из комбинаций:\n\n```tsx\nhotkeys: {\n copy: [\n { code: 'KeyC', ctrl: true },\n { code: 'Insert', ctrl: true }, // альтернативный хоткей\n ],\n}\n```\n\n## PasteConfig\n\n```typescript\ntype PasteConfig = {\n /**\n * Что делать с readonly-ячейками в зоне вставки.\n * `'skip'` пропускает их, `'abort'` отменяет всю вставку целиком.\n * По умолчанию `'skip'`.\n */\n readonlyBehavior?: ReadonlyBehavior;\n /** Разрешать ли вставку в subrow-ячейки. По умолчанию `true` */\n allowSubRows?: boolean;\n /**\n * Что делать при выходе данных за границы таблицы.\n * `'truncate'` обрезает лишнее, `'abort'` отменяет вставку.\n * По умолчанию `'truncate'`.\n */\n overflowBehavior?: OverflowBehavior;\n /**\n * Тиражирование источника на всё выделение (как в Excel).\n * Если `true` и в буфере одна строка/колонка, а выделение больше,\n * буфер повторится по соответствующей оси.\n * По умолчанию `false`.\n */\n broadcast?: boolean;\n /**\n * Режим валидации значений при вставке.\n * - `'none'` вставляет строку как есть без проверок\n * - `'type-check'` (по умолчанию) проверяет соответствие типу ячейки:\n * числовые поля должны парситься в число, select-поля должны содержать\n * значение из `options`. Невалидные ячейки пропускаются.\n */\n validation?: ValidationMode;\n};\n```\n\nПоле `validation: 'type-check'` (default) автоматически проверяет:\n\n- **inputNumber / contentFormat.type='number'** — значение должно парситься в число через разделители из `contentFormat`. Невалидные ячейки пропускаются.\n- **select** — значение должно совпадать с одной из options (value или text). Невалидные пропускаются.\n- **inputString / остальное** — всегда валидно.\n\nУстановите `validation: 'none'` чтобы вставлять сырые строки без проверок.\n\n## CellTransferCellInfo\n\nИнформация об одной ячейке. Используется как элемент двумерного массива `cells` внутри\nвсех meta-типов ниже (`CopyMeta`, `PasteMeta`, `FillMeta`).\n\n```typescript\ntype CellTransferCellInfo = {\n /** Объект строки, в которой находится ячейка */\n row: ObjectForExtending;\n /** Конфиг колонки (срез важных полей) */\n column: TransferColumnConfig;\n /** Индекс колонки в массиве columns */\n colIndex: number;\n /** Индекс строки в массиве flattenedRows */\n rowIndex: number;\n /** Уровень вложенности subrow: 0 — parent, 1+ — subrow */\n lvl: number;\n /** Сырое значение из `row[key]` или `row[subKey]` (без форматирования) */\n rawValue: unknown;\n /** Текстовое представление ячейки (то что попадает в TSV) */\n formattedValue: string;\n};\n```\n\n## Метаданные колбэков (Meta-типы)\n\nКаждый колбэк (`onBeforeCopy`, `onBeforePaste`, `onBeforeFill`) получает вторым\nаргументом свой meta-объект с контекстом операции.\n\n### CopyMeta (`onBeforeCopy`)\n\n```typescript\ntype CopyMeta = {\n /** Прямоугольный диапазон выделения в координатах таблицы */\n range: Rectangle;\n /** Двумерный массив информации о каждой ячейке, той же формы что data */\n cells: CellTransferCellInfo[][];\n};\n```\n\n### PasteMeta (`onBeforePaste`)\n\n```typescript\ntype PasteMeta = {\n /** Верхний-левый угол целевой области (куда начинается вставка) */\n target: { col: number; row: number };\n /** Двумерный массив информации о целевых ячейках, той же формы что data */\n targetCells: CellTransferCellInfo[][];\n /** Текущее выделение в таблице */\n selection: GridSelection;\n};\n```\n\n### FillMeta (`onBeforeFill`)\n\n```typescript\ntype FillMeta = {\n /** Исходный диапазон (откуда тянули) */\n sourceRange: Rectangle;\n /** Целевой диапазон (куда заполнили) */\n destinationRange: Rectangle;\n /** Двумерный массив информации об исходных ячейках */\n sourceCells: CellTransferCellInfo[][];\n /** Двумерный массив информации о целевых ячейках (до заполнения) */\n targetCells: CellTransferCellInfo[][];\n};\n```\n\n## RowsChangeType\n\nПоле `type` в `onRowsChange` указывает источник изменения строк.\n\n```typescript\ntype RowsChangeType = 'edit' | 'paste' | 'fill';\n```\n\n## FillHandleConfig\n\n```typescript\ntype FillHandleConfig = {\n /** Включён ли fill handle. По умолчанию включён если включён cellTransfer */\n enabled?: boolean;\n /** Форма квадратика. По умолчанию `'square'` */\n shape?: 'square' | 'circle';\n /** Размер квадратика в пикселях */\n size?: number;\n /** Толщина обводки квадратика в пикселях */\n outline?: number;\n /**\n * Разрешённые направления перетаскивания.\n * `'orthogonal'` (по умолчанию) разрешает только вдоль одной оси за раз.\n */\n allowedDirections?: AllowedFillDirections;\n /**\n * Поведение при попадании readonly-ячеек в destination.\n * См. `PasteConfig.readonlyBehavior`. По умолчанию `'skip'`.\n */\n readonlyBehavior?: ReadonlyBehavior;\n /** Разрешать ли fill в subrow-ячейки. По умолчанию `true` */\n allowSubRows?: boolean;\n};\n```\n\n## AllowedFillDirections / FillPatternEvent\n\n```typescript\ntype AllowedFillDirections =\n | 'horizontal'\n | 'vertical'\n | 'orthogonal'\n | 'any';\n```\n\n```typescript\ntype FillPatternEvent = {\n /** Исходный диапазон (откуда берутся значения) */\n patternSource: Rectangle;\n /** Целевой диапазон (куда тиражируются значения) */\n fillDestination: Rectangle;\n /** Вызов отменяет fill (данные не записываются) */\n preventDefault: () => void;\n};\n```\n\n## columnConfig.copyData\n\nТекстовое представление ячейки для копирования в буфер.\n\n```ts\ncopyData?: string | ((row: Row) => string);\n```\n\nЕсли `copyData` не задан, используется `row[column.key]?.toString()`.\n\n## Примеры\n\n### Базовое использование (работает из коробки)\n\n```tsx\n<TableCanvas\n tableConfig={{\n editing: {\n onRowsChange: setRows,\n rowKeyGetter: (r) => r.id,\n defaultEnabled: true,\n },\n }}\n columnConfig={columnConfig}\n rows={rows}\n/>\n```\n\nCopy (Ctrl+C) и Paste (Ctrl+V) работают автоматически в режиме редактирования.\n\n### Excel-like поведение paste\n\n```tsx\ntableConfig={{\n cellTransfer: {\n paste: {\n readonlyBehavior: 'abort', // как в Excel\n broadcast: true,\n },\n },\n}}\n```\n\n### Кастомные хоткеи + перехват\n\n```tsx\ntableConfig={{\n cellTransfer: {\n hotkeys: {\n copy: { code: 'KeyC', ctrl: true, alt: true },\n paste: { code: 'KeyV', ctrl: true, alt: true },\n },\n onBeforeCopy: (data) => {\n // логируем или модифицируем данные\n console.log('Copying:', data);\n return data;\n },\n onBeforePaste: (data) => {\n if (data.length > 100) {\n alert('Слишком много строк');\n return false;\n }\n return data;\n },\n },\n}}\n```\n\n### Кастомный copyData для canvas-ячейки\n\n```tsx\ncolumnConfig={[\n {\n key: 'status',\n name: 'Статус',\n renderCell: ({ row }) => (\n <Canvas.Badge\n text={row.status}\n view={row.status === 'Активный' ? 'positive' : 'warning'}\n />\n ),\n copyData: (row) => row.status ?? '', // копируем только текст\n },\n]}\n```",
|
|
52511
53031
|
"api": [
|
|
52512
53032
|
{
|
|
@@ -52559,37 +53079,37 @@
|
|
|
52559
53079
|
"exportName": "ClipboardFullDemo",
|
|
52560
53080
|
"displayName": "Полный пример (все возможности)",
|
|
52561
53081
|
"type": "full-code",
|
|
52562
|
-
"code": "() => {\n useEffect(() => {\n (\n window as unknown as Record<string, boolean>\n ).__TABLE_CANVAS_CLIPBOARD_DEBUG__ = true;\n }, []);\n\n const [rows, setRows] = useState(() => createRowsTree());\n const [highlightActiveType, setHighlightActiveType] =\n useState<HighlightActiveType>('row');\n const [selectionMode, setSelectionMode] =\n useState<CellsSelectionMode>('range-cell');\n\n const columns = useMemo(\n (): readonly ColumnConfig<TreeRow>[] => [\n {\n key: 'block',\n name: 'Блок',\n editingCell: {\n editable: (r) => r.block === BLOCKS[1],\n component: 'select',\n options: {\n type: 'constant',\n options: BLOCKS.map((i) => ({ text: i, value: i })),\n },\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 editingCell: {\n component: 'inputString',\n inputProps: { placeholder: 'Введите значение' },\n },\n isColumnWithArrow: true,\n },\n },\n {\n key: 'blockActivity',\n name: 'Активность блока',\n editingCell: { component: 'inputString' },\n renderCell: ({ row }) => (\n <Canvas.Container direction=\"row\" alignItems=\"center\" padding={8}>\n <Canvas.Badge\n text={row.blockActivity}\n view={row.blockActivity === 'Активный' ? 'positive' : 'warning'}\n size=\"s\"\n />\n </Canvas.Container>\n ),\n copyData: (row: TreeRow) => row.blockActivity ?? '',\n subRow: {\n keyOfColumnInSubRow: 'blockActivity',\n editingCell: { component: 'inputString' },\n },\n },\n {\n key: 'tribe',\n name: 'Трайб',\n editingCell: {\n component: 'select',\n options: {\n type: 'stateInRowContext',\n optionsKeyInRowContext: 'tribeOptions',\n },\n },\n renderCell: ({ row, theme }) => (\n <Canvas.Container padding={8}>\n <Canvas.Text color={theme.textDark}>{row.tribe}</Canvas.Text>\n </Canvas.Container>\n ),\n copyData: (row: TreeRow) => row.tribe ?? '',\n subRow: {\n keyOfColumnInSubRow: 'tribe',\n editingCell: { component: 'inputString' },\n },\n },\n {\n key: 'product',\n name: 'Продукт',\n editingCell: {\n component: 'select',\n options: {\n type: 'stateInRowContext',\n optionsKeyInRowContext: 'productOptions',\n },\n },\n subRow: {\n keyOfColumnInSubRow: 'product',\n editingCell: { component: 'inputString' },\n },\n },\n {\n key: 'q1',\n name: 'Q1',\n editingCell: { component: 'inputNumber' },\n contentFormat: {\n type: 'number',\n decimalSeparator: ',',\n thousandSeparator: ' ',\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n },\n subRow: {\n keyOfColumnInSubRow: 'q1',\n editingCell: { component: 'inputNumber' },\n },\n },\n {\n key: 'q2',\n name: 'Q2',\n contentFormat: 'number',\n editingCell: { component: 'inputNumber' },\n subRow: {\n keyOfColumnInSubRow: 'q2',\n editingCell: { component: 'inputNumber' },\n },\n },\n {\n key: 'q3',\n name: 'Q3',\n contentFormat: 'number',\n editingCell: { component: 'inputNumber' },\n subRow: {\n keyOfColumnInSubRow: 'q3',\n editingCell: { component: 'inputNumber' },\n },\n },\n {\n key: 'q4',\n name: 'Q4',\n contentFormat: 'number',\n editingCell: { component: 'inputNumber' },\n subRow: {\n keyOfColumnInSubRow: 'q4',\n editingCell: { component: 'inputNumber' },\n },\n },\n ],\n [],\n );\n\n const rowContextValue = useMemo(\n () => ({\n tribeOptions: TRIBES.map((i) => ({ text: i, value: i })),\n productOptions: PRODUCTS.map((i) => ({ text: i, value: i })),\n }),\n [],\n );\n\n const savedRowsRef = useRef<null | typeof rows>(null);\n\n return (\n <div>\n <div\n style={{ display: 'flex', gap: 12, maxWidth: 760, marginBottom: 12 }}\n >\n <Select\n label=\"Режим выделения\"\n value={selectionMode}\n onChange={(value) => setSelectionMode(value as CellsSelectionMode)}\n items={SELECTION_MODE_OPTIONS}\n />\n <Select\n label=\"highlightActiveType (подсветка)\"\n value={highlightActiveType}\n onChange={(value) =>\n setHighlightActiveType(value as HighlightActiveType)\n }\n items={HIGHLIGHT_ACTIVE_TYPE_OPTIONS}\n />\n </div>\n\n <
|
|
53082
|
+
"code": "() => {\n useEffect(() => {\n (\n window as unknown as Record<string, boolean>\n ).__TABLE_CANVAS_CLIPBOARD_DEBUG__ = true;\n }, []);\n\n const [rows, setRows] = useState(() => createRowsTree());\n const [highlightActiveType, setHighlightActiveType] =\n useState<HighlightActiveType>('row');\n const [selectionMode, setSelectionMode] =\n useState<CellsSelectionMode>('range-cell');\n\n const columns = useMemo(\n (): readonly ColumnConfig<TreeRow>[] => [\n {\n key: 'block',\n name: 'Блок',\n editingCell: {\n editable: (r) => r.block === BLOCKS[1],\n component: 'select',\n options: {\n type: 'constant',\n options: BLOCKS.map((i) => ({ text: i, value: i })),\n },\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 editingCell: {\n component: 'inputString',\n inputProps: { placeholder: 'Введите значение' },\n },\n isColumnWithArrow: true,\n },\n },\n {\n key: 'blockActivity',\n name: 'Активность блока',\n editingCell: { component: 'inputString' },\n renderCell: ({ row }) => (\n <Canvas.Container direction=\"row\" alignItems=\"center\" padding={8}>\n <Canvas.Badge\n text={row.blockActivity}\n view={row.blockActivity === 'Активный' ? 'positive' : 'warning'}\n size=\"s\"\n />\n </Canvas.Container>\n ),\n copyData: (row: TreeRow) => row.blockActivity ?? '',\n subRow: {\n keyOfColumnInSubRow: 'blockActivity',\n editingCell: { component: 'inputString' },\n },\n },\n {\n key: 'tribe',\n name: 'Трайб',\n editingCell: {\n component: 'select',\n options: {\n type: 'stateInRowContext',\n optionsKeyInRowContext: 'tribeOptions',\n },\n },\n renderCell: ({ row, theme }) => (\n <Canvas.Container padding={8}>\n <Canvas.Text color={theme.textDark}>{row.tribe}</Canvas.Text>\n </Canvas.Container>\n ),\n copyData: (row: TreeRow) => row.tribe ?? '',\n subRow: {\n keyOfColumnInSubRow: 'tribe',\n editingCell: { component: 'inputString' },\n },\n },\n {\n key: 'product',\n name: 'Продукт',\n editingCell: {\n component: 'select',\n options: {\n type: 'stateInRowContext',\n optionsKeyInRowContext: 'productOptions',\n },\n },\n subRow: {\n keyOfColumnInSubRow: 'product',\n editingCell: { component: 'inputString' },\n },\n },\n {\n key: 'q1',\n name: 'Q1',\n editingCell: { component: 'inputNumber' },\n contentFormat: {\n type: 'number',\n decimalSeparator: ',',\n thousandSeparator: ' ',\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n },\n subRow: {\n keyOfColumnInSubRow: 'q1',\n editingCell: { component: 'inputNumber' },\n },\n },\n {\n key: 'q2',\n name: 'Q2',\n contentFormat: 'number',\n editingCell: { component: 'inputNumber' },\n subRow: {\n keyOfColumnInSubRow: 'q2',\n editingCell: { component: 'inputNumber' },\n },\n },\n {\n key: 'q3',\n name: 'Q3',\n contentFormat: 'number',\n editingCell: { component: 'inputNumber' },\n subRow: {\n keyOfColumnInSubRow: 'q3',\n editingCell: { component: 'inputNumber' },\n },\n },\n {\n key: 'q4',\n name: 'Q4',\n contentFormat: 'number',\n editingCell: { component: 'inputNumber' },\n subRow: {\n keyOfColumnInSubRow: 'q4',\n editingCell: { component: 'inputNumber' },\n },\n },\n ],\n [],\n );\n\n const rowContextValue = useMemo(\n () => ({\n tribeOptions: TRIBES.map((i) => ({ text: i, value: i })),\n productOptions: PRODUCTS.map((i) => ({ text: i, value: i })),\n }),\n [],\n );\n\n const savedRowsRef = useRef<null | typeof rows>(null);\n\n return (\n <div>\n <div\n style={{ display: 'flex', gap: 12, maxWidth: 760, marginBottom: 12 }}\n >\n <Select\n label=\"Режим выделения\"\n value={selectionMode}\n onChange={(value) => setSelectionMode(value as CellsSelectionMode)}\n items={SELECTION_MODE_OPTIONS}\n />\n <Select\n label=\"highlightActiveType (подсветка)\"\n value={highlightActiveType}\n onChange={(value) =>\n setHighlightActiveType(value as HighlightActiveType)\n }\n items={HIGHLIGHT_ACTIVE_TYPE_OPTIONS}\n />\n </div>\n\n <StoryHint>\n <b>Copy:</b> работает всегда (Ctrl+C). <b>Paste/Fill:</b> только в\n режиме редактирования.\n <br />\n <b>Выделение строк:</b> клик/драг по колонке нумерации — строка(и);{' '}\n <b>Ctrl/Cmd+клик</b> по номерам — набор отдельных строк (группа).\n Скопированное (Ctrl+C) можно вставить (Ctrl+V) на выделенные строки.\n <br />\n <b>Выделение колонок:</b> клик по шапке (Ctrl/Shift — мультивыбор),\n copy/paste по колонкам.\n <br />\n <b>Колонки:</b> Блок (select, readonly часть), Активность\n (Canvas.Badge + copyData), Трайб (Canvas.Text + copyData + select),\n Продукт (select), Q1 (число + contentFormat), Q2-Q4 (число).\n <br />\n <b>Debug:</b> логи включены (DevTools → Verbose).\n </StoryHint>\n\n <TableCanvas\n tableConfig={{\n containerStyle: { height: '700px' },\n // Подсветка строки — отдельная визуальная ось (Фаза 2+).\n highlightActiveType,\n // Нумерация строк: клик/драг по ней выделяет строку(и); Ctrl/Meta —\n // накопительный выбор отдельных строк. Copy/Paste работают по строкам.\n rowMarkers: { startIndex: 1 },\n // Режим выделения ячеек: по нему работают copy/paste и рамка.\n // Выделение колонок по клику на шапку (по умолчанию включено).\n cellsSelection: {\n mode: selectionMode,\n enableColumnSelection: true,\n },\n rowSize: { showInControl: true, default: 'big' },\n editing: {\n onEnableEditing(enableEditorMode) {\n savedRowsRef.current = JSON.parse(JSON.stringify(rows));\n enableEditorMode();\n },\n onCancel(disableEditorMode) {\n if (savedRowsRef.current) setRows(savedRowsRef.current);\n disableEditorMode();\n },\n onSave(disableEditorMode) {\n savedRowsRef.current = null;\n disableEditorMode();\n },\n onRowsChange: setRows,\n rowKeyGetter: (r) => `${r.id}`,\n rowEditable: (r) => r.block !== BLOCKS[1],\n },\n subRows: {\n getSubRows: (row) => row?.subRows,\n rowKeyGetter: (row) => row.id,\n },\n resizableColumn: true,\n }}\n columnConfig={columns}\n rows={rows}\n rowContextValue={rowContextValue}\n />\n </div>\n );\n }"
|
|
52563
53083
|
},
|
|
52564
53084
|
{
|
|
52565
53085
|
"exportName": "InterceptCopyPaste",
|
|
52566
53086
|
"displayName": "Перехват onBeforeCopy / onBeforePaste",
|
|
52567
53087
|
"type": "full-code",
|
|
52568
|
-
"code": "() => {\n const [rows, setRows] = useState(createRows);\n\n const columnConfig = useMemo<readonly ColumnConfig<Row>[]>(\n () => [\n {\n key: 'id',\n name: 'ID',\n width: 90,\n editingCell: { component: 'inputNumber' },\n },\n {\n key: 'task',\n name: 'Title',\n width: 260,\n editingCell: { component: 'inputString' },\n },\n {\n key: 'priority',\n name: 'Priority',\n width: 180,\n editingCell: { component: 'inputString' },\n },\n {\n key: 'issueType',\n name: 'Issue Type',\n width: 180,\n editingCell: { component: 'inputString' },\n },\n {\n key: 'complete',\n name: '% Complete',\n width: 160,\n editingCell: { component: 'inputNumber' },\n },\n ],\n [],\n );\n\n return (\n <div>\n <
|
|
53088
|
+
"code": "() => {\n const [rows, setRows] = useState(createRows);\n\n const columnConfig = useMemo<readonly ColumnConfig<Row>[]>(\n () => [\n {\n key: 'id',\n name: 'ID',\n width: 90,\n editingCell: { component: 'inputNumber' },\n },\n {\n key: 'task',\n name: 'Title',\n width: 260,\n editingCell: { component: 'inputString' },\n },\n {\n key: 'priority',\n name: 'Priority',\n width: 180,\n editingCell: { component: 'inputString' },\n },\n {\n key: 'issueType',\n name: 'Issue Type',\n width: 180,\n editingCell: { component: 'inputString' },\n },\n {\n key: 'complete',\n name: '% Complete',\n width: 160,\n editingCell: { component: 'inputNumber' },\n },\n ],\n [],\n );\n\n return (\n <div>\n <StoryHint>\n <b>onBeforeCopy:</b> при Ctrl+C в консоль выводятся скопированные\n данные, колонки и rawValue каждой ячейки.\n <br />\n <b>onBeforePaste:</b> при Ctrl+V выводятся вставляемые данные и info о\n target-ячейках. Если вставляется больше 5 строк, вставка блокируется\n (return false).\n </StoryHint>\n\n <TableCanvas\n tableConfig={{\n containerStyle: { height: '500px' },\n rowSize: { default: 'medium', showInControl: true },\n cellTransfer: {\n onBeforeCopy: (data, meta) => {\n console.log('[onBeforeCopy] data:', data);\n console.log(\n '[onBeforeCopy] колонки:',\n meta.cells[0]?.map((c) => c.column.key),\n );\n console.log(\n '[onBeforeCopy] rawValues:',\n meta.cells.map((row) => row.map((c) => c.rawValue)),\n );\n return data;\n },\n onBeforePaste: (data, meta) => {\n console.log('[onBeforePaste] data:', data);\n console.log('[onBeforePaste] target:', meta.target);\n console.log(\n '[onBeforePaste] targetCells:',\n meta.targetCells.map((row) =>\n row.map(\n (c) =>\n `${c.column.key} (${\n c.column.editingCell ? 'editable' : 'readonly'\n })`,\n ),\n ),\n );\n if (data.length > 5) {\n console.warn('[onBeforePaste] Блокировка: больше 5 строк');\n return false;\n }\n return data;\n },\n },\n editing: {\n onRowsChange: setRows,\n rowKeyGetter: (r) => `${r.id}`,\n defaultEnabled: true,\n },\n resizableColumn: true,\n }}\n columnConfig={columnConfig}\n rows={rows}\n />\n </div>\n );\n }"
|
|
52569
53089
|
},
|
|
52570
53090
|
{
|
|
52571
53091
|
"exportName": "CopyDataExample",
|
|
52572
53092
|
"displayName": "copyData для кастомных ячеек",
|
|
52573
53093
|
"type": "full-code",
|
|
52574
|
-
"code": "() => {\n const [rows, setRows] = useState(createRows);\n\n const columnConfig = useMemo<readonly ColumnConfig<Row>[]>(\n () => [\n {\n key: 'id',\n name: 'ID',\n width: 80,\n editingCell: { component: 'inputNumber' },\n },\n {\n key: 'task',\n name: 'Title',\n width: 240,\n editingCell: { component: 'inputString' },\n },\n {\n key: 'priority',\n name: 'Priority (Badge + copyData)',\n width: 220,\n editingCell: { component: 'inputString' },\n renderCell: ({ row }) => (\n <Canvas.Container direction=\"row\" alignItems=\"center\" padding={8}>\n <Canvas.Badge\n text={row.priority}\n view={row.priority === 'Critical' ? 'negative' : 'default'}\n size=\"s\"\n />\n </Canvas.Container>\n ),\n copyData: (row: Row) => row.priority ?? '',\n },\n {\n key: 'issueType',\n name: 'Type (Text + copyData)',\n width: 200,\n editingCell: { component: 'inputString' },\n renderCell: ({ row, theme }) => (\n <Canvas.Container padding={8}>\n <Canvas.Text color={theme.textDark}>{row.issueType}</Canvas.Text>\n </Canvas.Container>\n ),\n copyData: (row: Row) => row.issueType ?? '',\n },\n {\n key: 'complete',\n name: '% Complete',\n width: 140,\n editingCell: { component: 'inputNumber' },\n },\n ],\n [],\n );\n\n return (\n <div>\n <
|
|
53094
|
+
"code": "() => {\n const [rows, setRows] = useState(createRows);\n\n const columnConfig = useMemo<readonly ColumnConfig<Row>[]>(\n () => [\n {\n key: 'id',\n name: 'ID',\n width: 80,\n editingCell: { component: 'inputNumber' },\n },\n {\n key: 'task',\n name: 'Title',\n width: 240,\n editingCell: { component: 'inputString' },\n },\n {\n key: 'priority',\n name: 'Priority (Badge + copyData)',\n width: 220,\n editingCell: { component: 'inputString' },\n renderCell: ({ row }) => (\n <Canvas.Container direction=\"row\" alignItems=\"center\" padding={8}>\n <Canvas.Badge\n text={row.priority}\n view={row.priority === 'Critical' ? 'negative' : 'default'}\n size=\"s\"\n />\n </Canvas.Container>\n ),\n copyData: (row: Row) => row.priority ?? '',\n },\n {\n key: 'issueType',\n name: 'Type (Text + copyData)',\n width: 200,\n editingCell: { component: 'inputString' },\n renderCell: ({ row, theme }) => (\n <Canvas.Container padding={8}>\n <Canvas.Text color={theme.textDark}>{row.issueType}</Canvas.Text>\n </Canvas.Container>\n ),\n copyData: (row: Row) => row.issueType ?? '',\n },\n {\n key: 'complete',\n name: '% Complete',\n width: 140,\n editingCell: { component: 'inputNumber' },\n },\n ],\n [],\n );\n\n return (\n <div>\n <StoryHint>\n <b>Priority</b> — Canvas.Badge с <code>copyData</code>. <b>Type</b> —\n Canvas.Text с <code>copyData</code>.\n <br />\n Выделите ячейку Priority → Ctrl+C → вставьте в блокнот: скопируется\n текст бейджа (например "Critical"), а не пустая строка.\n </StoryHint>\n\n <TableCanvas\n tableConfig={{\n containerStyle: { height: '400px' },\n rowSize: { default: 'medium', showInControl: true },\n editing: {\n onRowsChange: setRows,\n rowKeyGetter: (r) => `${r.id}`,\n defaultEnabled: true,\n },\n }}\n columnConfig={columnConfig}\n rows={rows}\n />\n </div>\n );\n }"
|
|
52575
53095
|
},
|
|
52576
53096
|
{
|
|
52577
53097
|
"exportName": "TypeCheckValidation",
|
|
52578
53098
|
"displayName": "Валидация типов при вставке",
|
|
52579
53099
|
"type": "full-code",
|
|
52580
|
-
"code": "() => {\n useEffect(() => {\n (\n window as unknown as Record<string, boolean>\n ).__TABLE_CANVAS_CLIPBOARD_DEBUG__ = true;\n }, []);\n\n const [rows, setRows] = useState(createRows);\n\n const columnConfig = useMemo<readonly ColumnConfig<Row>[]>(\n () => [\n { key: 'id', name: 'ID', width: 80 },\n {\n key: 'task',\n name: 'Title (строка)',\n width: 240,\n editingCell: { component: 'inputString' },\n },\n {\n key: 'priority',\n name: 'Priority (select)',\n width: 180,\n editingCell: {\n component: 'select',\n options: {\n type: 'constant',\n options: [\n { value: 'Critical', text: 'Critical' },\n { value: 'High', text: 'High' },\n { value: 'Medium', text: 'Medium' },\n { value: 'Low', text: 'Low' },\n ],\n },\n },\n },\n {\n key: 'complete',\n name: '% Complete (число)',\n width: 180,\n editingCell: { component: 'inputNumber' },\n contentFormat: {\n type: 'number',\n decimalSeparator: ',',\n thousandSeparator: ' ',\n },\n },\n ],\n [],\n );\n\n return (\n <div>\n <
|
|
53100
|
+
"code": "() => {\n useEffect(() => {\n (\n window as unknown as Record<string, boolean>\n ).__TABLE_CANVAS_CLIPBOARD_DEBUG__ = true;\n }, []);\n\n const [rows, setRows] = useState(createRows);\n\n const columnConfig = useMemo<readonly ColumnConfig<Row>[]>(\n () => [\n { key: 'id', name: 'ID', width: 80 },\n {\n key: 'task',\n name: 'Title (строка)',\n width: 240,\n editingCell: { component: 'inputString' },\n },\n {\n key: 'priority',\n name: 'Priority (select)',\n width: 180,\n editingCell: {\n component: 'select',\n options: {\n type: 'constant',\n options: [\n { value: 'Critical', text: 'Critical' },\n { value: 'High', text: 'High' },\n { value: 'Medium', text: 'Medium' },\n { value: 'Low', text: 'Low' },\n ],\n },\n },\n },\n {\n key: 'complete',\n name: '% Complete (число)',\n width: 180,\n editingCell: { component: 'inputNumber' },\n contentFormat: {\n type: 'number',\n decimalSeparator: ',',\n thousandSeparator: ' ',\n },\n },\n ],\n [],\n );\n\n return (\n <div>\n <StoryHint>\n <b>Priority</b> — select (Critical / High / Medium / Low). Вставка\n "Unknown" пропустится.\n <br />\n <b>% Complete</b> — число. Вставка "hello" пропустится.\n <br />\n <b>Title</b> — строка, принимает всё.\n <br />\n Debug логи включены — смотрите{' '}\n <code>[TableCanvas/paste] skipped by validation</code> в консоли.\n </StoryHint>\n\n <TableCanvas\n tableConfig={{\n containerStyle: { height: '400px' },\n rowSize: { default: 'medium', showInControl: true },\n editing: {\n onRowsChange: setRows,\n rowKeyGetter: (r) => `${r.id}`,\n defaultEnabled: true,\n },\n }}\n columnConfig={columnConfig}\n rows={rows}\n />\n </div>\n );\n }"
|
|
52581
53101
|
},
|
|
52582
53102
|
{
|
|
52583
53103
|
"exportName": "FillHandleWithSourceRow",
|
|
52584
53104
|
"displayName": "Fill Handle — доступ к source row (onBeforeFill)",
|
|
52585
53105
|
"type": "full-code",
|
|
52586
|
-
"code": "() => {\n const [rows, setRows] = useState(createRows);\n const savedRowsRef = useRef<Row[] | null>(null);\n\n const columnConfig = useMemo<readonly ColumnConfig<Row>[]>(\n () => [\n {\n key: 'id',\n name: 'ID',\n width: 80,\n editingCell: { component: 'inputNumber' },\n },\n {\n key: 'task',\n name: 'Title',\n width: 260,\n editingCell: { component: 'inputString' },\n },\n {\n key: 'priority',\n name: 'Priority',\n width: 180,\n editingCell: { component: 'inputString' },\n },\n {\n key: 'issueType',\n name: 'Issue Type',\n width: 180,\n editingCell: { component: 'inputString' },\n },\n {\n key: 'complete',\n name: '% Complete',\n width: 160,\n editingCell: { component: 'inputNumber' },\n },\n ],\n [],\n );\n\n return (\n <div>\n <
|
|
53106
|
+
"code": "() => {\n const [rows, setRows] = useState(createRows);\n const savedRowsRef = useRef<Row[] | null>(null);\n\n const columnConfig = useMemo<readonly ColumnConfig<Row>[]>(\n () => [\n {\n key: 'id',\n name: 'ID',\n width: 80,\n editingCell: { component: 'inputNumber' },\n },\n {\n key: 'task',\n name: 'Title',\n width: 260,\n editingCell: { component: 'inputString' },\n },\n {\n key: 'priority',\n name: 'Priority',\n width: 180,\n editingCell: { component: 'inputString' },\n },\n {\n key: 'issueType',\n name: 'Issue Type',\n width: 180,\n editingCell: { component: 'inputString' },\n },\n {\n key: 'complete',\n name: '% Complete',\n width: 160,\n editingCell: { component: 'inputNumber' },\n },\n ],\n [],\n );\n\n return (\n <div>\n <StoryHint>\n Выделите ячейку в колонке <b>% Complete</b> и перетащите fill handle\n вниз.\n <br />\n <b>onRowsChange</b> получает <code>type: 'fill'</code> и{' '}\n <code>fillMeta</code> с source row, что позволяет дополнительно\n скопировать <b>priority</b> из исходной строки.\n </StoryHint>\n\n <TableCanvas\n tableConfig={{\n containerStyle: { height: '500px' },\n highlightActiveType: 'range-cell',\n rowSize: { default: 'medium', showInControl: true },\n cellTransfer: {\n fillHandle: true,\n onBeforeFill: (data, meta) => {\n console.log(\n '[onBeforeFill] source row:',\n meta.sourceCells[0]?.[0]?.row,\n );\n console.log('[onBeforeFill] data:', data);\n return data;\n },\n },\n editing: {\n onEnableEditing(enableEditorMode) {\n savedRowsRef.current = JSON.parse(JSON.stringify(rows));\n enableEditorMode();\n },\n onCancel(disableEditorMode) {\n if (savedRowsRef.current) {\n setRows(savedRowsRef.current);\n savedRowsRef.current = null;\n }\n disableEditorMode();\n },\n onRowsChange: (newRows, { indexes, column, type, fillMeta }) => {\n if (type === 'fill' && fillMeta && column.key === 'complete') {\n const sourceRow = fillMeta.sourceCells[0]?.[0]?.row as\n | Row\n | undefined;\n\n if (sourceRow) {\n const updated = newRows.map((row, i) =>\n indexes.includes(i)\n ? { ...row, priority: sourceRow.priority }\n : row,\n );\n setRows(updated);\n return;\n }\n }\n\n setRows(newRows);\n },\n rowKeyGetter: (r) => `${r.id}`,\n defaultEnabled: false,\n },\n resizableColumn: true,\n }}\n columnConfig={columnConfig}\n rows={rows}\n />\n </div>\n );\n }"
|
|
52587
53107
|
},
|
|
52588
53108
|
{
|
|
52589
53109
|
"exportName": "CustomHotkeys",
|
|
52590
53110
|
"displayName": "Кастомные хоткеи",
|
|
52591
53111
|
"type": "full-code",
|
|
52592
|
-
"code": "() => {\n const [rows, setRows] = useState(createRows);\n\n const columnConfig = useMemo<readonly ColumnConfig<Row>[]>(\n () => [\n {\n key: 'id',\n name: 'ID',\n width: 80,\n editingCell: { component: 'inputNumber' },\n },\n {\n key: 'task',\n name: 'Title',\n width: 260,\n editingCell: { component: 'inputString' },\n },\n {\n key: 'priority',\n name: 'Priority',\n width: 180,\n editingCell: { component: 'inputString' },\n },\n {\n key: 'complete',\n name: '% Complete',\n width: 160,\n editingCell: { component: 'inputNumber' },\n },\n ],\n [],\n );\n\n return (\n <div>\n <
|
|
53112
|
+
"code": "() => {\n const [rows, setRows] = useState(createRows);\n\n const columnConfig = useMemo<readonly ColumnConfig<Row>[]>(\n () => [\n {\n key: 'id',\n name: 'ID',\n width: 80,\n editingCell: { component: 'inputNumber' },\n },\n {\n key: 'task',\n name: 'Title',\n width: 260,\n editingCell: { component: 'inputString' },\n },\n {\n key: 'priority',\n name: 'Priority',\n width: 180,\n editingCell: { component: 'inputString' },\n },\n {\n key: 'complete',\n name: '% Complete',\n width: 160,\n editingCell: { component: 'inputNumber' },\n },\n ],\n [],\n );\n\n return (\n <div>\n <StoryHint>\n Copy: <b>Ctrl+Alt+C</b>. Paste: <b>Ctrl+Alt+V</b>.\n <br />\n Обычные Ctrl+C / Ctrl+V для этой таблицы не работают — хук блокирует\n дефолт, когда задан кастомный хоткей.\n </StoryHint>\n\n <TableCanvas\n tableConfig={{\n containerStyle: { height: '400px' },\n rowSize: { default: 'medium', showInControl: true },\n cellTransfer: {\n hotkeys: {\n copy: { code: 'KeyC', ctrl: true, alt: true },\n paste: { code: 'KeyV', ctrl: true, alt: true },\n },\n },\n editing: {\n onRowsChange: setRows,\n rowKeyGetter: (r) => `${r.id}`,\n defaultEnabled: true,\n },\n }}\n columnConfig={columnConfig}\n rows={rows}\n />\n </div>\n );\n }"
|
|
52593
53113
|
}
|
|
52594
53114
|
]
|
|
52595
53115
|
},
|
|
@@ -52637,7 +53157,7 @@
|
|
|
52637
53157
|
"legacy": false,
|
|
52638
53158
|
"summary": "*tableConfig.\\*.domMetadata**",
|
|
52639
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).",
|
|
52640
|
-
"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 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```",
|
|
52641
53161
|
"api": [
|
|
52642
53162
|
{
|
|
52643
53163
|
"typeName": "DomMetadata",
|
|
@@ -52653,7 +53173,7 @@
|
|
|
52653
53173
|
},
|
|
52654
53174
|
{
|
|
52655
53175
|
"typeName": "ColumnsControlConfig",
|
|
52656
|
-
"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 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};"
|
|
52657
53177
|
}
|
|
52658
53178
|
],
|
|
52659
53179
|
"stories": [
|
|
@@ -52833,11 +53353,11 @@
|
|
|
52833
53353
|
"legacy": false,
|
|
52834
53354
|
"summary": "*tableConfig.filtering**",
|
|
52835
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)",
|
|
52836
|
-
"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\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 * потребителей. Таблица 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```",
|
|
52837
53357
|
"api": [
|
|
52838
53358
|
{
|
|
52839
53359
|
"typeName": "FilteringConfig",
|
|
52840
|
-
"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\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 *"
|
|
52841
53361
|
},
|
|
52842
53362
|
{
|
|
52843
53363
|
"typeName": "FilterComponentInPopoverProps",
|
|
@@ -52938,7 +53458,7 @@
|
|
|
52938
53458
|
"exportName": "HighlightActiveRowControlled",
|
|
52939
53459
|
"displayName": "Контролируемая подсветка строки (controlled)",
|
|
52940
53460
|
"type": "full-code",
|
|
52941
|
-
"code": "import {\n type ColumnConfig,\n type HighlightActiveType,\n type CellsSelectionMode,\n type SIZE_GLIDE_INSTANCE as RowSize,\n TableCanvas,\n} from '@daisforge/ui/components/TableCanvas';\n\nconst HIGHLIGHT_ACTIVE_TYPE_OPTIONS: readonly HighlightActiveType[] = [\n 'row',\n 'disabled',\n];\nconst SELECTION_MODE_OPTIONS: readonly CellsSelectionMode[] = [\n 'range-cell',\n 'multi-range-cell',\n 'cell',\n 'disabled',\n];\nconst ROW_SIZE_OPTIONS: readonly RowSize[] = ['big', 'medium', 'small'];\nconst ROW_MARKER_WIDTH_BY_SIZE: Record<RowSize, number> = {\n big: 48,\n medium: 32,\n small: 24,\n};\nconst COLUMN_CONFIG: readonly ColumnConfig<Row>[] = [\n { key: 'id', name: 'ID', width: 90 },\n { key: 'task', name: 'Title', width: 260 },\n { key: 'priority', name: 'Priority', width: 180 },\n { key: 'issueType', name: 'Issue Type', width: 180 },\n { key: 'complete', name: '% Complete', width: 160 },\n];\nconst getRowSelectionKey = (row: Row) => row.id + row.issueType;\n\n() => {\n const [rows] = useState(createRows);\n const columnConfig = useMemo<readonly ColumnConfig<TableRow>[]>(\n () => COLUMN_CONFIG,\n [],\n );\n\n const highlightActiveRowState = useState<number | undefined>(undefined);\n const [highlightActiveRow, setHighlightActiveRow] = highlightActiveRowState;\n\n return (\n <>\n <div\n style={{\n display: 'flex',\n gap: 8,\n flexWrap: 'wrap',\n marginBottom: 12,\n }}\n >\n <Button onClick={() => setHighlightActiveRow(2)}>\n Подсветить строку №3\n </Button>\n <Button onClick={() => setHighlightActiveRow(undefined)}>\n Сбросить подсветку строки\n </Button>\n </div>\n\n <
|
|
53461
|
+
"code": "import {\n type ColumnConfig,\n type HighlightActiveType,\n type CellsSelectionMode,\n type SIZE_GLIDE_INSTANCE as RowSize,\n TableCanvas,\n} from '@daisforge/ui/components/TableCanvas';\n\nconst HIGHLIGHT_ACTIVE_TYPE_OPTIONS: readonly HighlightActiveType[] = [\n 'row',\n 'disabled',\n];\nconst SELECTION_MODE_OPTIONS: readonly CellsSelectionMode[] = [\n 'range-cell',\n 'multi-range-cell',\n 'cell',\n 'disabled',\n];\nconst ROW_SIZE_OPTIONS: readonly RowSize[] = ['big', 'medium', 'small'];\nconst ROW_MARKER_WIDTH_BY_SIZE: Record<RowSize, number> = {\n big: 48,\n medium: 32,\n small: 24,\n};\nconst COLUMN_CONFIG: readonly ColumnConfig<Row>[] = [\n { key: 'id', name: 'ID', width: 90 },\n { key: 'task', name: 'Title', width: 260 },\n { key: 'priority', name: 'Priority', width: 180 },\n { key: 'issueType', name: 'Issue Type', width: 180 },\n { key: 'complete', name: '% Complete', width: 160 },\n];\nconst getRowSelectionKey = (row: Row) => row.id + row.issueType;\n\n() => {\n const [rows] = useState(createRows);\n const columnConfig = useMemo<readonly ColumnConfig<TableRow>[]>(\n () => COLUMN_CONFIG,\n [],\n );\n\n const highlightActiveRowState = useState<number | undefined>(undefined);\n const [highlightActiveRow, setHighlightActiveRow] = highlightActiveRowState;\n\n return (\n <>\n <div\n style={{\n display: 'flex',\n gap: 8,\n flexWrap: 'wrap',\n marginBottom: 12,\n }}\n >\n <Button onClick={() => setHighlightActiveRow(2)}>\n Подсветить строку №3\n </Button>\n <Button onClick={() => setHighlightActiveRow(undefined)}>\n Сбросить подсветку строки\n </Button>\n </div>\n\n <StoryHint>\n Подсветка активной строки — <b>controlled</b> через{' '}\n <code>tableConfig.highlightActiveRow.state</code>. Кнопки\n задают/сбрасывают внешний стейт; клик по строке тоже обновляет его.\n Подсвеченная строка: <b>{highlightActiveRow ?? '—'}</b>.\n </StoryHint>\n\n <TableCanvas\n tableConfig={{\n containerStyle: { height: '600px' },\n highlightActiveType: 'row',\n rowMarkers: { startIndex: 1 },\n highlightActiveRow: { state: highlightActiveRowState },\n }}\n columnConfig={columnConfig}\n rows={rows}\n />\n </>\n );\n }"
|
|
52942
53462
|
},
|
|
52943
53463
|
{
|
|
52944
53464
|
"exportName": "HighlightActiveTypeSplitView",
|
|
@@ -53047,7 +53567,7 @@
|
|
|
53047
53567
|
"exportName": "Notifications",
|
|
53048
53568
|
"displayName": "Подписка на события (onNotification)",
|
|
53049
53569
|
"type": "full-code",
|
|
53050
|
-
"code": "() => {\n const [rows, setRows] = useState(createRows);\n const columnConfig = useMemo(() => COLUMNS, []);\n const [log, setLog] = useState<TableNotification[]>([]);\n\n return (\n <div>\n <
|
|
53570
|
+
"code": "() => {\n const [rows, setRows] = useState(createRows);\n const columnConfig = useMemo(() => COLUMNS, []);\n const [log, setLog] = useState<TableNotification[]>([]);\n\n return (\n <div>\n <StoryHint>\n Режим <b>multi-range-cell</b>. Как спровоцировать события:\n <br />• <b>copy / multi-range-scattered</b> — Ctrl-выдели ячейки в\n РАЗНЫХ строках и колонках → Ctrl+C.\n <br />• <b>paste / multi-range-scattered</b> — тот же 2D-выбор →\n Ctrl+V.\n <br />• <b>paste / readonly-abort</b> — вставь в диапазон, задевающий\n колонку ID.\n <br />• <b>paste / overflow-abort</b> — вставь большой блок у\n нижнего/правого края.\n <br />• <b>paste / validation-skipped</b> — вставь текст в колонку «%\n (число)».\n <br />• <b>fill / readonly-abort</b>, <b>fill / validation-skipped</b>\n — то же протаскиванием fill-handle.\n </StoryHint>\n\n <div style={{ display: 'flex', gap: 16 }}>\n <div style={{ flex: 1, minWidth: 0 }}>\n <TableCanvas\n tableConfig={{\n containerStyle: { height: '520px' },\n cellsSelection: { mode: 'multi-range-cell' },\n rowMarkers: { startIndex: 1 },\n cellTransfer: {\n enabled: true,\n paste: {\n readonlyBehavior: 'abort',\n overflowBehavior: 'abort',\n },\n },\n editing: {\n onRowsChange: setRows,\n rowKeyGetter: (r) => `${r.id}`,\n defaultEnabled: true,\n },\n notifications: {\n onNotification: (event) =>\n setLog((prev) => [event, ...prev].slice(0, 20)),\n },\n }}\n columnConfig={columnConfig}\n rows={rows}\n />\n </div>\n\n <div style={{ width: 340, fontSize: 12 }}>\n <div\n style={{\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n marginBottom: 8,\n }}\n >\n <b>Полученные события ({log.length})</b>\n <button\n type=\"button\"\n onClick={() => setLog([])}\n style={{\n padding: '4px 10px',\n borderRadius: 8,\n border: '1px solid #c7d2e0',\n background: '#fff',\n cursor: 'pointer',\n }}\n >\n Очистить\n </button>\n </div>\n {log.length === 0 && (\n <div style={{ color: '#8893a5' }}>Пока пусто</div>\n )}\n {log.map((event, i) => (\n <div\n key={i}\n style={{\n borderLeft: `3px solid ${LEVEL_COLOR[event.level]}`,\n padding: '6px 10px',\n marginBottom: 6,\n background: '#fafbfc',\n }}\n >\n <div\n style={{ color: LEVEL_COLOR[event.level], fontWeight: 600 }}\n >\n {event.type} · {event.code} · {event.level}\n </div>\n <div style={{ color: '#556' }}>{event.message}</div>\n </div>\n ))}\n </div>\n </div>\n </div>\n );\n }"
|
|
53051
53571
|
}
|
|
53052
53572
|
]
|
|
53053
53573
|
},
|
|
@@ -53149,11 +53669,11 @@
|
|
|
53149
53669
|
"legacy": false,
|
|
53150
53670
|
"summary": "*tableConfig.rowMarkers**",
|
|
53151
53671
|
"docs": "# RowMarkers (TableCanvas)\n\n**tableConfig.rowMarkers**\n\nСервисный столбец с нумерацией строк. Frozen, вставляется первым, исключён из reorder/pin/hide/sort/grouping. Поддерживает плоский и древовидный (`subRows`) режимы любой глубины вложенности.\n\n## Быстрый старт\n\n```tsx\n<TableCanvas\n tableConfig={{\n rowMarkers: {\n startIndex: 1,\n },\n }}\n columnConfig={columnConfig}\n rows={rows}\n/>\n```\n\n## `flatIndex` vs `rowIndex`\n\nЕсли ветка свернута, но нужно сохранить «сквозные» номера — используйте `flatIndex`.\n\n- полностью раскрыто: `1, 2, 3, 4, 5`\n- после сворачивания середины: `1, 2, 5` (а не `1, 2, 3`)\n\n`rowIndex` зависит только от видимых строк — номера будут «прыгать».\n\n## Частичная перерисовка\n\n`getRowMarker` должна быть чистой функцией. Вызывается не только при полной отрисовке таблицы, но и при ховере/скролле — для одной ячейки. Не используйте внешние переменные-счётчики — используйте аргументы (`siblingPath`, `flatIndex`, `siblingIndex`, `parentKey`), они всегда актуальны.\n\n> Подробнее о типах — [RowMarkers API](?path=/docs/локальные-компоненты-tablecanvas-rowmarkers-api--docs)",
|
|
53152
|
-
"apiDocs": "# RowMarkers API\n\n## RowMarkersTableConfig\n\n```typescript\ntype 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 *
|
|
53672
|
+
"apiDocs": "# RowMarkers API\n\n## RowMarkersTableConfig\n\n```typescript\ntype 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```",
|
|
53153
53673
|
"api": [
|
|
53154
53674
|
{
|
|
53155
53675
|
"typeName": "RowMarkersTableConfig",
|
|
53156
|
-
"source": "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 *
|
|
53676
|
+
"source": "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};"
|
|
53157
53677
|
}
|
|
53158
53678
|
],
|
|
53159
53679
|
"stories": [
|
|
@@ -53219,11 +53739,11 @@
|
|
|
53219
53739
|
"legacy": false,
|
|
53220
53740
|
"summary": "*tableConfig.rowsGrouping + columnConfig.rowsGrouping**",
|
|
53221
53741
|
"docs": "# RowsGrouping (TableCanvas)\n\n**tableConfig.rowsGrouping + columnConfig.rowsGrouping**\n\nГруппировка строк таблицы по значениям колонок с поддержкой вложенных группировок.\n\n## Ключевые особенности\n\n- Управляемое состояние группировки через `groupByState`\n- Кнопка с выпадающим списком для выбора группировок в controlBlock\n- Кастомный рендер сгруппированных строк через `renderGroupCell`\n- Кастомные элементы в выпадающем списке через `groupButton.defaultCustomItems`\n- Возможность замены данных группированных строк через `groupRowReplaceTo`\n\n## Особенности\n\n- `rowKeyGetter` должен возвращать уникальный идентификатор строки\n- `groupedColumnProps` позволяет настроить колонку с группировкой (ширину, рендер и т.д.)\n- В `columnConfig.rowsGrouping` можно указать `groupByColumn: false` для исключения колонки из группировки\n- `columnGroupLabel` переопределяет лейбл в выпадающем списке (default: `columnConfig.key`)\n\n> Подробнее о типах — [RowsGrouping API](?path=/docs/локальные-компоненты-tablecanvas-rowsgrouping-api--docs)",
|
|
53222
|
-
"apiDocs": "# RowsGrouping API\n\n## RowsGrouping\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 * Функция определения уникального id строки\n */\n rowKeyGetter: (row: RowType) => string | number;\n /**\n * Показывать ли кнопку «Группировать» в controlBlock.\n * При `false` кнопка скрыта и не участвует в компрессии,\n * но группировка строк продолжает работать от внешнего `groupByState`.\n * @default true\n */\n showInControl?: boolean;\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 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 renderGroupCell?: (\n props: RenderGroupCellProps<RowType, ColumnConfig>,\n ) => CanvasContent;\n};\n```",
|
|
53742
|
+
"apiDocs": "# RowsGrouping API\n\n## RowsGrouping\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```",
|
|
53223
53743
|
"api": [
|
|
53224
53744
|
{
|
|
53225
53745
|
"typeName": "RowsGrouping",
|
|
53226
|
-
"source": "type 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 * Функция определения уникального id строки\n */\n rowKeyGetter: (row: RowType) => string | number;\n /**\n * Показывать ли кнопку «Группировать» в controlBlock.\n * При `false` кнопка скрыта и не участвует в компрессии,\n * но группировка строк продолжает работать от внешнего `groupByState`.\n * @default true\n */\n showInControl?: boolean;\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 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 renderGroupCell?: (\n props: RenderGroupCellProps<RowType, ColumnConfig>,\n ) => CanvasContent;\n};"
|
|
53746
|
+
"source": "type 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};"
|
|
53227
53747
|
}
|
|
53228
53748
|
],
|
|
53229
53749
|
"stories": [
|
|
@@ -53358,7 +53878,7 @@
|
|
|
53358
53878
|
"feature": "CellsSelection",
|
|
53359
53879
|
"legacy": false,
|
|
53360
53880
|
"summary": "Выделение в таблице задаётся пропом **`tableConfig.cellsSelection.mode`** — это",
|
|
53361
|
-
"docs": "# CellsSelection\n\nВыделение в таблице задаётся пропом **`tableConfig.cellsSelection.mode`** — это\nфактическое нативное выделение ячеек. По нему работают copy/paste, рамка\nвыделения, fill-handle и затемнение шапки/нумерации.\n\n> Это **отдельная ось** от `highlightActiveType` (визуальная подсветка строки) и\n> от `selecting` (выбор строк чекбоксами).\n\n## Значения cellsSelection.mode\n\n- `'range-cell'` — выделение диапазона ячеек (по умолчанию). Тянем мышкой.\n- `'multi-range-cell'` — как `range-cell`, но **Ctrl/Cmd** докидывает несколько\n диапазонов (см. ниже).\n- `'cell'` — выделение одной ячейки.\n- `'disabled'` — выделение ячеек отключено.\n\n## Мультивыбор диапазонов (multi-range-cell)\n\nПри `cellsSelection: { mode: 'multi-range-cell' }` можно выделить несколько прямоугольных\nдиапазонов: тянем мышкой первый, затем **Ctrl/Cmd + клик/драг** докидываем\nостальные. Заливка и рамка — у всех выделенных.\n\n**Copy (Ctrl+C)** работает для разрозненного выбора, если все ячейки лежат:\n\n- в пределах **одной колонки** — значения копируются подряд, пустые промежутки\n между ними схлопываются;\n- либо в пределах **одной строки** — аналогично по
|
|
53881
|
+
"docs": "# CellsSelection\n\nВыделение в таблице задаётся пропом **`tableConfig.cellsSelection.mode`** — это\nфактическое нативное выделение ячеек. По нему работают copy/paste, рамка\nвыделения, fill-handle и затемнение шапки/нумерации.\n\n> Это **отдельная ось** от `highlightActiveType` (визуальная подсветка строки) и\n> от `selecting` (выбор строк чекбоксами).\n\n## Значения cellsSelection.mode\n\n- `'range-cell'` — выделение диапазона ячеек (по умолчанию). Тянем мышкой.\n- `'multi-range-cell'` — как `range-cell`, но **Ctrl/Cmd** докидывает несколько\n диапазонов (см. ниже).\n- `'cell'` — выделение одной ячейки.\n- `'disabled'` — выделение ячеек отключено.\n\n## Мультивыбор диапазонов (multi-range-cell)\n\nПри `cellsSelection: { mode: 'multi-range-cell' }` можно выделить несколько прямоугольных\nдиапазонов: тянем мышкой первый, затем **Ctrl/Cmd + клик/драг** докидываем\nостальные. Заливка и рамка — у всех выделенных.\n\n**Copy (Ctrl+C)** работает для разрозненного выбора, если все ячейки лежат:\n\n- в пределах **одной колонки** — значения копируются подряд, пустые промежутки\n между ними схлопываются;\n- либо в пределах **одной строки** — аналогично по горизонтали;\n- либо куски складываются в **сплошной прямоугольник** без дыр — тогда он\n копируется как обычный диапазон.\n\nРазброс сразу **по строкам и колонкам** (2D) не переносится — copy/paste для него\nне срабатывают. Об этом таблица сообщает через модуль\n[Notifications](?path=/docs/локальные-компоненты-tablecanvas-notifications--docs)\n(`copy` / `paste`, code `multi-range-scattered`). Сама таблица тост не рисует:\nподключите `notifications.onNotification` и покажите ошибку пользователю — иначе\nотказ копирования выглядит как молчаливая поломка.\n\n**Paste (Ctrl+V)** зеркально: вставка идёт в выбранные ячейки подряд, схлопывая\nпромежутки. Полный интерактивный пример copy/paste — в разделе\n**Copy-Paste-Fill**.\n\n## Оси выделения\n\nВыделение работает по трём независимым осям. Любая из них поддерживает\ncopy/paste (**Ctrl+C / Ctrl+V**) по текущему выделению.\n\n- **Ячейки / диапазон** — мышью по области данных, зависит от `cellsSelection.mode`.\n- **Колонки** — клик по шапке колонки.\n- **Строки** — клик/драг по колонке нумерации (`rowMarkers`).\n\n### Выделение колонок\n\nКлик по шапке выделяет колонку целиком:\n\n- **Клик** — одна колонка.\n- **Shift + клик** — смежный диапазон колонок (рисуется нативно, с fill-handle).\n- **Ctrl/Cmd + клик** — несмежный выбор: добавить/убрать колонку.\n\nКлик по иконкам сортировки/фильтрации в шапке выделение **не** вызывает.\nУправляется флагом `cellsSelection.enableColumnSelection` (по умолчанию `true`).\n\n### Выделение строк\n\nКлик/драг по колонке нумерации выделяет строку(и):\n\n- **Клик / драг** — смежный диапазон строк (рисуется нативно, с fill-handle).\n- **Ctrl/Cmd + клик** — несмежный выбор отдельных строк.\n\nТребует включённой колонки нумерации (`rowMarkers`). Управляется флагом\n`cellsSelection.enableRowSelection` (по умолчанию `true`).\n\n## Включение / выключение осей\n\nВыделение колонок и строк можно выключать независимо через `tableConfig.cellsSelection`:\n\n```ts\n<TableCanvas\n tableConfig={{\n rowMarkers: { startIndex: 1 },\n cellsSelection: {\n enableColumnSelection: false, // клик по шапке не выделяет колонку\n enableRowSelection: false, // клик по нумерации не выделяет строку\n },\n }}\n/>;\n```\n\nОба флага по умолчанию `true`. Выделение ячеек/диапазона при этом продолжает\nработать — оно управляется отдельным `cellsSelection.mode`.\n\n## Controlled-режим\n\nВыделением можно управлять снаружи через `state`-кортеж:\n\n```ts\nconst gridSelectionState = useState<GridSelection>(EMPTY_SELECTION);\n\n<TableCanvas\n tableConfig={{\n cellsSelection: { mode: 'range-cell', state: gridSelectionState }, // [value, setter]\n }}\n/>;\n```\n\nСброс: `setter({ current: undefined, rows: CompactSelection.empty(), columns: CompactSelection.empty() })`.\nКонтролируется нативное выделение (ячейки/диапазон/смежные строки и колонки);\nнесмежный Ctrl-выбор колонок/строк — внутренний (own-state), снаружи не задаётся.\n\n`CompactSelection` и тип `GridSelection` реэкспортируются из\n`@daisforge/ui/components/TableCanvas`.\n\n> Подробнее о типах — [CellsSelection API](?path=/docs/локальные-компоненты-tablecanvas-cellsselection-api--docs)",
|
|
53362
53882
|
"apiDocs": "# CellsSelection API\n\n## CellsSelectionMode\n\nРежим фактического (нативного) выделения ячеек — `tableConfig.cellsSelection.mode`.\n\n```typescript\ntype CellsSelectionMode =\n | 'cell'\n | 'range-cell'\n | 'multi-range-cell'\n | 'disabled';\n```\n\n## Controlled-режим\n\n`tableConfig.cellsSelection.state` — внешний (controlled) контроль нативного выделения,\n`state`-кортеж `[GridSelection, setter]`:\n\n```ts\ncellsSelection?: {\n state?: [\n GridSelection,\n React.Dispatch<React.SetStateAction<GridSelection>>\n ];\n};\n```\n\n- Сброс: `setter({ current: undefined, rows: CompactSelection.empty(), columns: CompactSelection.empty() })`.\n- Контролирует нативное выделение (ячейки/диапазон/смежные строки и колонки).\n Несмежный Ctrl-выбор колонок/строк — внутренний.\n- `CompactSelection` (значение) и `GridSelection` (тип) реэкспортируются из\n `@daisforge/ui/components/TableCanvas`.\n\n## CellsSelectionConfig\n\nКонфиг выделения колонок (`tableConfig.cellsSelection`).\n\n```typescript\ntype 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```",
|
|
53363
53883
|
"api": [
|
|
53364
53884
|
{
|
|
@@ -53375,25 +53895,25 @@
|
|
|
53375
53895
|
"exportName": "SelectionModes",
|
|
53376
53896
|
"displayName": "Режимы выделения (cellsSelection.mode)",
|
|
53377
53897
|
"type": "full-code",
|
|
53378
|
-
"code": "import {\n type ColumnConfig,\n CompactSelection,\n type GridSelection,\n type CellsSelectionMode,\n TableCanvas,\n} from '@daisforge/ui/components/TableCanvas';\n\nconst SELECTION_MODE_OPTIONS: Array<{ label: string; value: CellsSelectionMode }> = [\n { label: 'range-cell', value: 'range-cell' },\n { label: 'multi-range-cell', value: 'multi-range-cell' },\n { label: 'cell', value: 'cell' },\n { label: 'disabled', value: 'disabled' },\n];\n\nconst EMPTY_SELECTION: GridSelection = {\n current: undefined,\n rows: CompactSelection.empty(),\n columns: CompactSelection.empty(),\n};\n\nconst COLUMN_CONFIG: readonly ColumnConfig<Row>[] = [\n { key: 'id', name: 'ID', width: 90 },\n { key: 'task', name: 'Title', width: 260 },\n { key: 'priority', name: 'Priority', width: 180 },\n { key: 'issueType', name: 'Issue Type', width: 180 },\n { key: 'complete', name: '% Complete', width: 160 },\n];\n\n() => {\n const [rows] = useState(createRows);\n const [selectionMode, setSelectionMode] =\n useState<CellsSelectionMode>('range-cell');\n const columnConfig = useMemo(() => COLUMN_CONFIG, []);\n\n return (\n <div>\n <div style={{ maxWidth: 320, marginBottom: 12 }}>\n <Select\n label=\"Режим выделения\"\n value={selectionMode}\n onChange={(value) => setSelectionMode(value as CellsSelectionMode)}\n items={SELECTION_MODE_OPTIONS}\n />\n </div>\n\n <
|
|
53898
|
+
"code": "import {\n type ColumnConfig,\n CompactSelection,\n type GridSelection,\n type CellsSelectionMode,\n TableCanvas,\n} from '@daisforge/ui/components/TableCanvas';\n\nconst SELECTION_MODE_OPTIONS: Array<{ label: string; value: CellsSelectionMode }> = [\n { label: 'range-cell', value: 'range-cell' },\n { label: 'multi-range-cell', value: 'multi-range-cell' },\n { label: 'cell', value: 'cell' },\n { label: 'disabled', value: 'disabled' },\n];\n\nconst EMPTY_SELECTION: GridSelection = {\n current: undefined,\n rows: CompactSelection.empty(),\n columns: CompactSelection.empty(),\n};\n\nconst COLUMN_CONFIG: readonly ColumnConfig<Row>[] = [\n { key: 'id', name: 'ID', width: 90 },\n { key: 'task', name: 'Title', width: 260 },\n { key: 'priority', name: 'Priority', width: 180 },\n { key: 'issueType', name: 'Issue Type', width: 180 },\n { key: 'complete', name: '% Complete', width: 160 },\n];\n\n() => {\n const [rows] = useState(createRows);\n const [selectionMode, setSelectionMode] =\n useState<CellsSelectionMode>('range-cell');\n const columnConfig = useMemo(() => COLUMN_CONFIG, []);\n\n return (\n <div>\n <div style={{ maxWidth: 320, marginBottom: 12 }}>\n <Select\n label=\"Режим выделения\"\n value={selectionMode}\n onChange={(value) => setSelectionMode(value as CellsSelectionMode)}\n items={SELECTION_MODE_OPTIONS}\n />\n </div>\n\n <StoryHint>\n <b>range-cell</b> — тянем мышкой диапазон ячеек.{' '}\n <b>multi-range-cell</b> — то же + Ctrl/Cmd копит несколько диапазонов.{' '}\n <b>cell</b> — одиночная ячейка. <b>disabled</b> — выделение ячеек\n отключено.\n <br />\n Клик/драг по колонке нумерации → выделение строки (Ctrl — группа).\n Клик по шапке → выделение колонки (Shift — диапазон, Ctrl — несмежно).\n Copy/Paste (Ctrl+C/V) работают по выделению.\n </StoryHint>\n\n <TableCanvas\n tableConfig={{\n containerStyle: { height: '600px' },\n cellsSelection: { mode: selectionMode },\n rowMarkers: { startIndex: 1 },\n editing: {\n onRowsChange: () => undefined,\n rowKeyGetter: (r) => `${r.id}`,\n defaultEnabled: true,\n },\n }}\n columnConfig={columnConfig}\n rows={rows}\n />\n </div>\n );\n }"
|
|
53379
53899
|
},
|
|
53380
53900
|
{
|
|
53381
53901
|
"exportName": "Controlled",
|
|
53382
53902
|
"displayName": "Контролируемое выделение извне (controlled)",
|
|
53383
53903
|
"type": "full-code",
|
|
53384
|
-
"code": "import {\n type ColumnConfig,\n CompactSelection,\n type GridSelection,\n type CellsSelectionMode,\n TableCanvas,\n} from '@daisforge/ui/components/TableCanvas';\n\nconst SELECTION_MODE_OPTIONS: Array<{ label: string; value: CellsSelectionMode }> = [\n { label: 'range-cell', value: 'range-cell' },\n { label: 'multi-range-cell', value: 'multi-range-cell' },\n { label: 'cell', value: 'cell' },\n { label: 'disabled', value: 'disabled' },\n];\n\nconst EMPTY_SELECTION: GridSelection = {\n current: undefined,\n rows: CompactSelection.empty(),\n columns: CompactSelection.empty(),\n};\n\nconst COLUMN_CONFIG: readonly ColumnConfig<Row>[] = [\n { key: 'id', name: 'ID', width: 90 },\n { key: 'task', name: 'Title', width: 260 },\n { key: 'priority', name: 'Priority', width: 180 },\n { key: 'issueType', name: 'Issue Type', width: 180 },\n { key: 'complete', name: '% Complete', width: 160 },\n];\n\n() => {\n const [rows] = useState(createRows);\n const columnConfig = useMemo(() => COLUMN_CONFIG, []);\n\n const gridSelectionState = useState<GridSelection>(EMPTY_SELECTION);\n const [gridSelection, setGridSelection] = gridSelectionState;\n\n const summary = gridSelection.current\n ? `x=${gridSelection.current.range.x} y=${gridSelection.current.range.y} w=${gridSelection.current.range.width} h=${gridSelection.current.range.height}`\n : 'нет выделения';\n\n return (\n <div>\n <div\n style={{\n display: 'flex',\n gap: 8,\n flexWrap: 'wrap',\n marginBottom: 12,\n }}\n >\n <Button onClick={() => setGridSelection(EMPTY_SELECTION)}>\n Сбросить выделение\n </Button>\n <Button\n onClick={() =>\n setGridSelection({\n current: {\n cell: [1, 0],\n range: { x: 1, y: 0, width: 2, height: 3 },\n rangeStack: [],\n },\n rows: CompactSelection.empty(),\n columns: CompactSelection.empty(),\n })\n }\n >\n Выделить Title:Priority (строки 1–3)\n </Button>\n </div>\n\n <
|
|
53904
|
+
"code": "import {\n type ColumnConfig,\n CompactSelection,\n type GridSelection,\n type CellsSelectionMode,\n TableCanvas,\n} from '@daisforge/ui/components/TableCanvas';\n\nconst SELECTION_MODE_OPTIONS: Array<{ label: string; value: CellsSelectionMode }> = [\n { label: 'range-cell', value: 'range-cell' },\n { label: 'multi-range-cell', value: 'multi-range-cell' },\n { label: 'cell', value: 'cell' },\n { label: 'disabled', value: 'disabled' },\n];\n\nconst EMPTY_SELECTION: GridSelection = {\n current: undefined,\n rows: CompactSelection.empty(),\n columns: CompactSelection.empty(),\n};\n\nconst COLUMN_CONFIG: readonly ColumnConfig<Row>[] = [\n { key: 'id', name: 'ID', width: 90 },\n { key: 'task', name: 'Title', width: 260 },\n { key: 'priority', name: 'Priority', width: 180 },\n { key: 'issueType', name: 'Issue Type', width: 180 },\n { key: 'complete', name: '% Complete', width: 160 },\n];\n\n() => {\n const [rows] = useState(createRows);\n const columnConfig = useMemo(() => COLUMN_CONFIG, []);\n\n const gridSelectionState = useState<GridSelection>(EMPTY_SELECTION);\n const [gridSelection, setGridSelection] = gridSelectionState;\n\n const summary = gridSelection.current\n ? `x=${gridSelection.current.range.x} y=${gridSelection.current.range.y} w=${gridSelection.current.range.width} h=${gridSelection.current.range.height}`\n : 'нет выделения';\n\n return (\n <div>\n <div\n style={{\n display: 'flex',\n gap: 8,\n flexWrap: 'wrap',\n marginBottom: 12,\n }}\n >\n <Button onClick={() => setGridSelection(EMPTY_SELECTION)}>\n Сбросить выделение\n </Button>\n <Button\n onClick={() =>\n setGridSelection({\n current: {\n cell: [1, 0],\n range: { x: 1, y: 0, width: 2, height: 3 },\n rangeStack: [],\n },\n rows: CompactSelection.empty(),\n columns: CompactSelection.empty(),\n })\n }\n >\n Выделить Title:Priority (строки 1–3)\n </Button>\n </div>\n\n <StoryHint>\n Выделение — <b>controlled</b> через{' '}\n <code>tableConfig.cellsSelection.state</code> ([value, setter]).\n Кнопки задают/сбрасывают внешний стейт, таблица реагирует.\n Контролируется нативная ось (ячейки/диапазон/смежные строки и\n колонки); несмежный Ctrl-выбор — внутренний.\n <br />\n Текущее выделение: <b>{summary}</b>.\n </StoryHint>\n\n <TableCanvas\n tableConfig={{\n containerStyle: { height: '600px' },\n cellsSelection: { mode: 'range-cell', state: gridSelectionState },\n rowMarkers: { startIndex: 1 },\n }}\n columnConfig={columnConfig}\n rows={rows}\n />\n </div>\n );\n }"
|
|
53385
53905
|
},
|
|
53386
53906
|
{
|
|
53387
53907
|
"exportName": "MultiRangeSelect",
|
|
53388
53908
|
"displayName": "Мультивыбор диапазонов (multi-range-cell)",
|
|
53389
53909
|
"type": "full-code",
|
|
53390
|
-
"code": "import {\n type ColumnConfig,\n CompactSelection,\n type GridSelection,\n type CellsSelectionMode,\n TableCanvas,\n} from '@daisforge/ui/components/TableCanvas';\n\nconst SELECTION_MODE_OPTIONS: Array<{ label: string; value: CellsSelectionMode }> = [\n { label: 'range-cell', value: 'range-cell' },\n { label: 'multi-range-cell', value: 'multi-range-cell' },\n { label: 'cell', value: 'cell' },\n { label: 'disabled', value: 'disabled' },\n];\n\nconst EMPTY_SELECTION: GridSelection = {\n current: undefined,\n rows: CompactSelection.empty(),\n columns: CompactSelection.empty(),\n};\n\nconst COLUMN_CONFIG: readonly ColumnConfig<Row>[] = [\n { key: 'id', name: 'ID', width: 90 },\n { key: 'task', name: 'Title', width: 260 },\n { key: 'priority', name: 'Priority', width: 180 },\n { key: 'issueType', name: 'Issue Type', width: 180 },\n { key: 'complete', name: '% Complete', width: 160 },\n];\n\n() => {\n const [rows] = useState(createRows);\n const columnConfig = useMemo(() => COLUMN_CONFIG, []);\n\n return (\n <div>\n <
|
|
53910
|
+
"code": "import {\n type ColumnConfig,\n CompactSelection,\n type GridSelection,\n type CellsSelectionMode,\n TableCanvas,\n} from '@daisforge/ui/components/TableCanvas';\n\nconst SELECTION_MODE_OPTIONS: Array<{ label: string; value: CellsSelectionMode }> = [\n { label: 'range-cell', value: 'range-cell' },\n { label: 'multi-range-cell', value: 'multi-range-cell' },\n { label: 'cell', value: 'cell' },\n { label: 'disabled', value: 'disabled' },\n];\n\nconst EMPTY_SELECTION: GridSelection = {\n current: undefined,\n rows: CompactSelection.empty(),\n columns: CompactSelection.empty(),\n};\n\nconst COLUMN_CONFIG: readonly ColumnConfig<Row>[] = [\n { key: 'id', name: 'ID', width: 90 },\n { key: 'task', name: 'Title', width: 260 },\n { key: 'priority', name: 'Priority', width: 180 },\n { key: 'issueType', name: 'Issue Type', width: 180 },\n { key: 'complete', name: '% Complete', width: 160 },\n];\n\n() => {\n const [rows] = useState(createRows);\n const columnConfig = useMemo(() => COLUMN_CONFIG, []);\n // Таблица сама тосты не рисует: ошибки copy/paste приходят в notifications,\n // показ — на стороне потребителя. Здесь показываем последнее событие плашкой.\n const [lastNotification, setLastNotification] = useState<string | null>(\n null,\n );\n\n return (\n <div>\n <StoryHint>\n <b>multi-range-cell</b>: тяни мышкой диапазон, затем <b>Ctrl/Cmd</b> +\n клик/драг — докидывай ещё диапазоны. У всех выделенных — заливка и\n рамка.\n <br />\n <b>Copy (Ctrl+C):</b> работает, если разрозненный выбор в пределах{' '}\n <b>одной колонки</b> или <b>одной строки</b> — промежутки схлопываются\n (значения копируются подряд), либо если куски складываются в сплошной\n прямоугольник. Разброс сразу по строкам и колонкам не копируется — в{' '}\n <b>notifications</b> уходит ошибка (плашка ниже).\n <br />\n <b>Paste</b> со схлопыванием промежутков — в режиме редактирования,\n см. <b>Copy-Paste-Fill</b>.\n </StoryHint>\n\n {lastNotification && (\n <p\n style={{\n fontSize: 13,\n marginBottom: 8,\n padding: '6px 10px',\n borderRadius: 6,\n background: '#fdecec',\n color: '#a33',\n }}\n >\n notifications: {lastNotification}\n </p>\n )}\n\n <TableCanvas\n tableConfig={{\n containerStyle: { height: '600px' },\n cellsSelection: { mode: 'multi-range-cell' },\n rowMarkers: { startIndex: 1 },\n notifications: {\n onNotification: (event) =>\n setLastNotification(\n `[${event.type}/${event.level}] ${event.message} (${event.code})`,\n ),\n },\n }}\n columnConfig={columnConfig}\n rows={rows}\n />\n </div>\n );\n }"
|
|
53391
53911
|
},
|
|
53392
53912
|
{
|
|
53393
53913
|
"exportName": "EnableToggles",
|
|
53394
53914
|
"displayName": "Включение/выключение колонок и строк",
|
|
53395
53915
|
"type": "full-code",
|
|
53396
|
-
"code": "import {\n type ColumnConfig,\n CompactSelection,\n type GridSelection,\n type CellsSelectionMode,\n TableCanvas,\n} from '@daisforge/ui/components/TableCanvas';\n\nconst SELECTION_MODE_OPTIONS: Array<{ label: string; value: CellsSelectionMode }> = [\n { label: 'range-cell', value: 'range-cell' },\n { label: 'multi-range-cell', value: 'multi-range-cell' },\n { label: 'cell', value: 'cell' },\n { label: 'disabled', value: 'disabled' },\n];\n\nconst EMPTY_SELECTION: GridSelection = {\n current: undefined,\n rows: CompactSelection.empty(),\n columns: CompactSelection.empty(),\n};\n\nconst COLUMN_CONFIG: readonly ColumnConfig<Row>[] = [\n { key: 'id', name: 'ID', width: 90 },\n { key: 'task', name: 'Title', width: 260 },\n { key: 'priority', name: 'Priority', width: 180 },\n { key: 'issueType', name: 'Issue Type', width: 180 },\n { key: 'complete', name: '% Complete', width: 160 },\n];\n\n() => {\n const [rows] = useState(createRows);\n const columnConfig = useMemo(() => COLUMN_CONFIG, []);\n const [enableColumnSelection, setEnableColumnSelection] = useState(true);\n const [enableRowSelection, setEnableRowSelection] = useState(true);\n\n return (\n <div>\n <div style={{ display: 'flex', gap: 20, marginBottom: 12 }}>\n <Checkbox\n checked={enableColumnSelection}\n onChange={(e) => setEnableColumnSelection(e.target.checked)}\n label={<div>enableColumnSelection</div>}\n />\n <Checkbox\n checked={enableRowSelection}\n onChange={(e) => setEnableRowSelection(e.target.checked)}\n label={<div>enableRowSelection</div>}\n />\n </div>\n\n <
|
|
53916
|
+
"code": "import {\n type ColumnConfig,\n CompactSelection,\n type GridSelection,\n type CellsSelectionMode,\n TableCanvas,\n} from '@daisforge/ui/components/TableCanvas';\n\nconst SELECTION_MODE_OPTIONS: Array<{ label: string; value: CellsSelectionMode }> = [\n { label: 'range-cell', value: 'range-cell' },\n { label: 'multi-range-cell', value: 'multi-range-cell' },\n { label: 'cell', value: 'cell' },\n { label: 'disabled', value: 'disabled' },\n];\n\nconst EMPTY_SELECTION: GridSelection = {\n current: undefined,\n rows: CompactSelection.empty(),\n columns: CompactSelection.empty(),\n};\n\nconst COLUMN_CONFIG: readonly ColumnConfig<Row>[] = [\n { key: 'id', name: 'ID', width: 90 },\n { key: 'task', name: 'Title', width: 260 },\n { key: 'priority', name: 'Priority', width: 180 },\n { key: 'issueType', name: 'Issue Type', width: 180 },\n { key: 'complete', name: '% Complete', width: 160 },\n];\n\n() => {\n const [rows] = useState(createRows);\n const columnConfig = useMemo(() => COLUMN_CONFIG, []);\n const [enableColumnSelection, setEnableColumnSelection] = useState(true);\n const [enableRowSelection, setEnableRowSelection] = useState(true);\n\n return (\n <div>\n <div style={{ display: 'flex', gap: 20, marginBottom: 12 }}>\n <Checkbox\n checked={enableColumnSelection}\n onChange={(e) => setEnableColumnSelection(e.target.checked)}\n label={<div>enableColumnSelection</div>}\n />\n <Checkbox\n checked={enableRowSelection}\n onChange={(e) => setEnableRowSelection(e.target.checked)}\n label={<div>enableRowSelection</div>}\n />\n </div>\n\n <StoryHint>\n Сними галочку — клик по шапке (колонки) или по колонке нумерации\n (строки) перестанет выделять. Выделение ячеек мышью при этом\n продолжает работать.\n </StoryHint>\n\n <TableCanvas\n tableConfig={{\n containerStyle: { height: '600px' },\n cellsSelection: {\n mode: 'range-cell',\n enableColumnSelection,\n enableRowSelection,\n },\n rowMarkers: { startIndex: 1 },\n }}\n columnConfig={columnConfig}\n rows={rows}\n />\n </div>\n );\n }"
|
|
53397
53917
|
}
|
|
53398
53918
|
]
|
|
53399
53919
|
},
|
|
@@ -53499,11 +54019,11 @@
|
|
|
53499
54019
|
"legacy": false,
|
|
53500
54020
|
"summary": "*tableConfig.subRows + columnConfig.subRow**",
|
|
53501
54021
|
"docs": "# SubRows (TableCanvas)\n\n**tableConfig.subRows + columnConfig.subRow**\n\nИерархичное отображение данных с вложенными строками. Поддерживает произвольную глубину вложенности.\n\nКонфигурация состоит из двух частей:\n\n- **`tableConfig.subRows`** — дерево данных: функция получения дочерних строк, ключ строки, состояние раскрытия\n- **`columnConfig[].subRow`** — отображение на уровне колонки: маппинг ключей, рендер ячеек, стрелка раскрытия\n\n## tableConfig.subRows\n\n- **`getSubRows`** `(row) => RowType[] | undefined` — функция получения дочерних строк\n- **`rowKeyGetter`** `(row) => RowIdType` — уникальный ключ строки\n- **`expandedIdsState`** `[Set, setter]` — внешний стейт развёрнутых строк (опционально, иначе внутренний useState)\n\n## columnConfig.subRow\n\n- **`isColumnWithArrow`** `boolean | ((props) => boolean)` — стрелка раскрытия в этой колонке (default: `false`)\n- **`hideHeaderExpandAllArrow`** `boolean` — скрыть кнопку «развернуть все» в header (default: `false`)\n- **`parentKeyAsDefault`** `boolean` — использовать ключ родителя как fallback (default: `false`)\n- **`keyOfColumnInSubRow`** `string | number | ((lvl) => string | number)` — маппинг ключей колонок для каждого уровня\n- **`contentFormat`** `ContentFormat` — формат содержимого подстрок\n- **`renderSubRowCell`** `RenderSubRowCell` — кастомный рендер ячеек подстрок\n\n> Подробнее о типах — [SubRows API](?path=/docs/локальные-компоненты-tablecanvas-subrows-api--docs)",
|
|
53502
|
-
"apiDocs": "# SubRows API\n\n## SubRows\n\n```typescript\ntype SubRows<RowType, RowIdType> = {\n /**\n *
|
|
54022
|
+
"apiDocs": "# SubRows API\n\n## SubRows\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```",
|
|
53503
54023
|
"api": [
|
|
53504
54024
|
{
|
|
53505
54025
|
"typeName": "SubRows",
|
|
53506
|
-
"source": "type SubRows<RowType, RowIdType> = {\n /**\n *
|
|
54026
|
+
"source": "type 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};"
|
|
53507
54027
|
}
|
|
53508
54028
|
],
|
|
53509
54029
|
"stories": [
|
|
@@ -53511,7 +54031,7 @@
|
|
|
53511
54031
|
"exportName": "SubRows",
|
|
53512
54032
|
"displayName": "Иерархичный вид",
|
|
53513
54033
|
"type": "full-code",
|
|
53514
|
-
"code": "import { ColumnConfig, TableCanvas } from '@daisforge/ui/components/TableCanvas';\n\n() => {\n const [rows] = useState(() =>
|
|
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 }"
|
|
53515
54035
|
}
|
|
53516
54036
|
]
|
|
53517
54037
|
},
|
|
@@ -53542,7 +54062,7 @@
|
|
|
53542
54062
|
"feature": "ThemeOverride",
|
|
53543
54063
|
"legacy": false,
|
|
53544
54064
|
"summary": "*columnConfig.themeOverride**",
|
|
53545
|
-
"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` левый край ячейки рассчитывается формулой `
|
|
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)",
|
|
53546
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```",
|
|
53547
54067
|
"api": [
|
|
53548
54068
|
{
|
|
@@ -53592,8 +54112,8 @@
|
|
|
53592
54112
|
"feature": "Tooltip",
|
|
53593
54113
|
"legacy": false,
|
|
53594
54114
|
"summary": "*tableConfig.tooltip + columnConfig.cellTooltip / headerCellTooltip**",
|
|
53595
|
-
"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).",
|
|
53596
|
-
"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```",
|
|
53597
54117
|
"api": [
|
|
53598
54118
|
{
|
|
53599
54119
|
"typeName": "CanvasNodeTooltipConfig",
|
|
@@ -53601,7 +54121,7 @@
|
|
|
53601
54121
|
},
|
|
53602
54122
|
{
|
|
53603
54123
|
"typeName": "CanvasNodeTooltipProps",
|
|
53604
|
-
"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};"
|
|
53605
54125
|
},
|
|
53606
54126
|
{
|
|
53607
54127
|
"typeName": "TooltipConfigResult",
|
|
@@ -53613,7 +54133,7 @@
|
|
|
53613
54133
|
},
|
|
53614
54134
|
{
|
|
53615
54135
|
"typeName": "TableConfigTooltip",
|
|
53616
|
-
"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};"
|
|
53617
54137
|
},
|
|
53618
54138
|
{
|
|
53619
54139
|
"typeName": "CanvasPortalHoverDetail",
|
|
@@ -53623,33 +54143,39 @@
|
|
|
53623
54143
|
"stories": [
|
|
53624
54144
|
{
|
|
53625
54145
|
"exportName": "DefaultTooltipStory",
|
|
53626
|
-
"displayName": "Встроенный тултип
|
|
54146
|
+
"displayName": "Встроенный тултип (drag-иконка в шапке)",
|
|
53627
54147
|
"type": "full-code",
|
|
53628
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)}"
|
|
53629
54149
|
},
|
|
53630
54150
|
{
|
|
53631
54151
|
"exportName": "ColumnTooltipStringStory",
|
|
53632
|
-
"displayName": "cellTooltip
|
|
54152
|
+
"displayName": "cellTooltip: строка",
|
|
53633
54153
|
"type": "full-code",
|
|
53634
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)}"
|
|
53635
54155
|
},
|
|
53636
54156
|
{
|
|
53637
54157
|
"exportName": "ColumnTooltipObjectStory",
|
|
53638
|
-
"displayName": "cellTooltip
|
|
54158
|
+
"displayName": "cellTooltip: объект",
|
|
53639
54159
|
"type": "full-code",
|
|
53640
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)}"
|
|
53641
54161
|
},
|
|
53642
54162
|
{
|
|
53643
54163
|
"exportName": "ColumnTooltipMultilineStory",
|
|
53644
|
-
"displayName": "cellTooltip
|
|
54164
|
+
"displayName": "cellTooltip: preserveLineBreaks",
|
|
53645
54165
|
"type": "full-code",
|
|
53646
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)}"
|
|
53647
54167
|
},
|
|
53648
54168
|
{
|
|
53649
54169
|
"exportName": "ButtonWithTooltipStory",
|
|
53650
|
-
"displayName": "Canvas.Button tooltip
|
|
54170
|
+
"displayName": "Canvas.Button: tooltip",
|
|
53651
54171
|
"type": "full-code",
|
|
53652
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)}"
|
|
53653
54179
|
}
|
|
53654
54180
|
]
|
|
53655
54181
|
},
|
|
@@ -55000,7 +55526,7 @@
|
|
|
55000
55526
|
},
|
|
55001
55527
|
"TableCanvas.ColumnConfig": {
|
|
55002
55528
|
"name": "ColumnConfig",
|
|
55003
|
-
"definition": "export type ColumnConfig<\n Row extends ObjectForExtending,\n SummRow = unknown,\n CustomCtxs extends ObjectForExtending = {},\n> = ColumnDefaultOmitted<Row, SummRow, CustomCtxs> & {\n renderCell?: (cellInfo: CellInfo<Row, SummRow, CustomCtxs>) => CellContent;\n renderCellPreview?: RenderCellPreview<Row, SummRow, CustomCtxs>;\n /**\n * Если в поле name был передан jsx, то нужно заполнить nameAsString для указания label в разделе Настройки столбцов, либо для отображения label в фильтрах в правом сайдбаре (но приоритет для фильтро будет ниже, чем то, что указали в filtering.sidebarConfig.items, там отдельно можно перезаписать label для фильтров сайдабара)\n */\n nameAsString?: string;\n /**\n * Текстовое представление ячейки для копирования в clipboard (Ctrl+C).\n * Если не задан, используется `row[column.key]?.toString()`.\n * Для кастомных canvas-ячеек (бейджи, кнопки) рекомендуется указывать явно.\n */\n copyData?: string | ((row: Row) => string);\n sortingType?: 'stringSort' | 'numberSort' | Comparator<Row>;\n searching?: {\n valueInRow: (row: Row) => string | number;\n };\n filtering?: {\n keyInFilterState: string;\n /**\n * Обязательно передать в случае НЕ ручной фильтрации. Если на уровне tableConfig.manualFiltering = false или не задан. Иначе фильтрация не отработает.\n */\n valueInRow?: (row: Row) => string | number;\n /**\n * ```FilterCb - (filterValue: string, rowValue: string) => boolean```\n */\n } & (\n | {\n component: 'input';\n filter: 'includes' | 'startWith' | 'equal' | FilterCb<'single'>;\n }\n | {\n component: 'select';\n beforeList?: (\n props: FilterComponentInPopoverProps<\n ObjectForExtending,\n ColumnConfig<Row, SummRow>\n >,\n ) => ReactNode;\n filter:\n | {\n typeOfValue: 'single';\n /**\n * Обязательно передать в случае НЕ ручной фильтрации. Если на уровне tableConfig.manualFiltering = false или не задан. Иначе фильтрация не отработает.\n */\n filteringType?: FilterCb<'single'>;\n }\n | {\n typeOfValue: 'multiple';\n /**\n * Обязательно передать в случае НЕ ручной фильтрации. Если на уровне tableConfig.manualFiltering = false или не задан. Иначе фильтрация не отработает.\n */\n filteringType?: FilterCb<'multiple'>;\n };\n selectOptions:\n | {\n type: 'constant';\n options: SelectOptions[];\n }\n | {\n type: 'stateInHeaderContext';\n /**\n * тип optionsState, который будет в HeaderContext:\n * ```ts\n * {\n * value: string | number;\n * text: string | number;\n * }[];\n * ```\n */\n optionsKeyInHeaderContext: string;\n };\n /**\n * Максимальна высота выпадающего списка в фильтрах колонок / правом сайдбаре.\n * @default \"360px\"\n */\n listMaxHeight?: string;\n }\n | {\n component: 'custom';\n customRender: (\n props: FilterComponentInPopoverProps<\n ObjectForExtending,\n ColumnConfig<Row, SummRow>\n >,\n ) => ReactNode;\n filter?: (filterValue: unknown, rowValue: unknown) => boolean;\n compareWithClearedValue?: (\n clearedValue: unknown,\n currV: unknown,\n ) => boolean;\n }\n );\n\n contentFormat?: ContentFormat;\n\n editingCell?: Editing<Row, SummRow>;\n\n subRow?: {\n /**\n * @default false\n */\n isColumnWithArrow?: boolean | ((props: { keyText: KeyText }) => boolean);\n /**\n * @default false\n */\n hideHeaderExpandAllArrow?: boolean;\n /**\n * @default false\n */\n parentKeyAsDefault?: boolean;\n /**\n * @default undefined\n */\n contentFormat?: ContentFormat;\n\n renderSubRowCell?: RenderSubRowCell<ObjectForExtending>;\n } & (\n | {\n keyOfColumnInSubRow:\n | string\n | number\n | ((lvl: number) => string | number);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n editingCell: Editing<any, any>;\n }\n | {\n editingCell?: undefined;\n keyOfColumnInSubRow?:\n | string\n | number\n | ((lvl: number) => string | number);\n }\n );\n rowsGrouping?: ColumnRowsGrouping<Row, ColumnConfig<Row, SummRow>>;\n keyText?: KeyTextColumnConfig<Row, SummRow>;\n /**\n * Переопределение темы на уровне ячейки. Позволяет менять фон и паддинги для конкретных ячеек.\n * @param cellInfo — информация о ячейке (row, column, ctxs, theme)\n * @param lvl — уровень вложенности (0 для обычных строк, 1+ для subRows)\n * @returns Partial<Theme> — объект переопределений (bgCell, cellHorizontalPadding и др.)\n */\n themeOverride?: (\n cellInfo: CellInfo<Row, SummRow, CustomCtxs>,\n lvl: number,\n ) => CellThemeOverrideResult | undefined;\n /**\n * Выравнивание текста в объединённой шапке этой колонки. Действует, когда шапка\n * колонки объединена (`tableConfig.columnsGrouping.squashEmptyCells`); перекрывает\n * табличный `columnsGrouping.squashedHeaderAlign`.\n */\n squashedHeaderAlign?: HeaderAlignment;\n
|
|
55529
|
+
"definition": "export type ColumnConfig<\n Row extends ObjectForExtending,\n SummRow = unknown,\n CustomCtxs extends ObjectForExtending = {},\n> = ColumnDefaultOmitted<Row, SummRow, CustomCtxs> & {\n renderCell?: (cellInfo: CellInfo<Row, SummRow, CustomCtxs>) => CellContent;\n renderCellPreview?: RenderCellPreview<Row, SummRow, CustomCtxs>;\n /**\n * Если в поле name был передан jsx, то нужно заполнить nameAsString для указания label в разделе Настройки столбцов, либо для отображения label в фильтрах в правом сайдбаре (но приоритет для фильтро будет ниже, чем то, что указали в filtering.sidebarConfig.items, там отдельно можно перезаписать label для фильтров сайдабара)\n */\n nameAsString?: string;\n /**\n * Текстовое представление ячейки для копирования в clipboard (Ctrl+C).\n * Если не задан, используется `row[column.key]?.toString()`.\n * Для кастомных canvas-ячеек (бейджи, кнопки) рекомендуется указывать явно.\n */\n copyData?: string | ((row: Row) => string);\n sortingType?: 'stringSort' | 'numberSort' | Comparator<Row>;\n searching?: {\n valueInRow: (row: Row) => string | number;\n };\n filtering?: {\n keyInFilterState: string;\n /**\n * Обязательно передать в случае НЕ ручной фильтрации. Если на уровне tableConfig.manualFiltering = false или не задан. Иначе фильтрация не отработает.\n */\n valueInRow?: (row: Row) => string | number;\n /**\n * ```FilterCb - (filterValue: string, rowValue: string) => boolean```\n */\n } & (\n | {\n component: 'input';\n filter: 'includes' | 'startWith' | 'equal' | FilterCb<'single'>;\n }\n | {\n component: 'select';\n beforeList?: (\n props: FilterComponentInPopoverProps<\n ObjectForExtending,\n ColumnConfig<Row, SummRow>\n >,\n ) => ReactNode;\n filter:\n | {\n typeOfValue: 'single';\n /**\n * Обязательно передать в случае НЕ ручной фильтрации. Если на уровне tableConfig.manualFiltering = false или не задан. Иначе фильтрация не отработает.\n */\n filteringType?: FilterCb<'single'>;\n }\n | {\n typeOfValue: 'multiple';\n /**\n * Обязательно передать в случае НЕ ручной фильтрации. Если на уровне tableConfig.manualFiltering = false или не задан. Иначе фильтрация не отработает.\n */\n filteringType?: FilterCb<'multiple'>;\n };\n selectOptions:\n | {\n type: 'constant';\n options: SelectOptions[];\n }\n | {\n type: 'stateInHeaderContext';\n /**\n * тип optionsState, который будет в HeaderContext:\n * ```ts\n * {\n * value: string | number;\n * text: string | number;\n * }[];\n * ```\n */\n optionsKeyInHeaderContext: string;\n };\n /**\n * Максимальна высота выпадающего списка в фильтрах колонок / правом сайдбаре.\n * @default \"360px\"\n */\n listMaxHeight?: string;\n }\n | {\n component: 'custom';\n customRender: (\n props: FilterComponentInPopoverProps<\n ObjectForExtending,\n ColumnConfig<Row, SummRow>\n >,\n ) => ReactNode;\n filter?: (filterValue: unknown, rowValue: unknown) => boolean;\n compareWithClearedValue?: (\n clearedValue: unknown,\n currV: unknown,\n ) => boolean;\n }\n );\n\n contentFormat?: ContentFormat;\n\n editingCell?: Editing<Row, SummRow>;\n\n /**\n * Настройки колонки для дерева subRows (шеврон, свой контент и редактор на\n * вложенных уровнях). Работает только в виде дерева. При\n * `subRows.view: 'merged'` не действует: там листья рисуются как обычные\n * строки, вложенных уровней нет.\n */\n subRow?: {\n /**\n * @default false\n */\n isColumnWithArrow?: boolean | ((props: { keyText: KeyText }) => boolean);\n /**\n * @default false\n */\n hideHeaderExpandAllArrow?: boolean;\n /**\n * @default false\n */\n parentKeyAsDefault?: boolean;\n /**\n * @default undefined\n */\n contentFormat?: ContentFormat;\n\n renderSubRowCell?: RenderSubRowCell<ObjectForExtending>;\n } & (\n | {\n keyOfColumnInSubRow:\n | string\n | number\n | ((lvl: number) => string | number);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n editingCell: Editing<any, any>;\n }\n | {\n editingCell?: undefined;\n keyOfColumnInSubRow?:\n | string\n | number\n | ((lvl: number) => string | number);\n }\n );\n rowsGrouping?: ColumnRowsGrouping<Row, ColumnConfig<Row, SummRow>>;\n keyText?: KeyTextColumnConfig<Row, SummRow>;\n /**\n * Переопределение темы на уровне ячейки. Позволяет менять фон и паддинги для конкретных ячеек.\n * @param cellInfo — информация о ячейке (row, column, ctxs, theme)\n * @param lvl — уровень вложенности (0 для обычных строк, 1+ для subRows)\n * @returns Partial<Theme> — объект переопределений (bgCell, cellHorizontalPadding и др.)\n */\n themeOverride?: (\n cellInfo: CellInfo<Row, SummRow, CustomCtxs>,\n lvl: number,\n ) => CellThemeOverrideResult | undefined;\n /**\n * Выравнивание текста в объединённой шапке этой колонки. Действует, когда шапка\n * колонки объединена (`tableConfig.columnsGrouping.squashEmptyCells`); перекрывает\n * табличный `columnsGrouping.squashedHeaderAlign`.\n */\n squashedHeaderAlign?: HeaderAlignment;\n /**\n * Выравнивание контента в объединённых ячейках этой колонки. Перекрывает общий\n * дефолт; важнее только выравнивание конкретного региона.\n *\n * Значение — одинаково для всех блоков колонки. Функция (row) => выравнивание —\n * по данным строки: разным блокам можно задать разное выравнивание (в том числе\n * в merged-видах группировки/subRows, где блоки формирует таблица).\n…",
|
|
55004
55530
|
"importPath": "@daisforge/ui/components/TableCanvas",
|
|
55005
55531
|
"importStatement": "import { ColumnConfig } from '@daisforge/ui/components/TableCanvas';",
|
|
55006
55532
|
"sourceFile": "packages/ui-kit/src/components/TableCanvas/types/column-config.type.ts"
|
|
@@ -55035,7 +55561,7 @@
|
|
|
55035
55561
|
},
|
|
55036
55562
|
"ColumnGlideInstance": {
|
|
55037
55563
|
"name": "ColumnGlideInstance",
|
|
55038
|
-
"definition": "export type ColumnGlideInstance<\n R extends ObjectForExtending,\n SR,\n CustomCtxs extends ObjectForExtending = {},\n> = {\n key: string;\n name: string | CanvasEl;\n nameAsString?: string;\n readonly width?: number;\n isServiceColumn?: boolean;\n isErrorCell?: (row: R) => boolean;\n frozen?: boolean;\n /** Минимальная ширина колонки (px). Ограничивает ресайз и начальную ширину снизу. */\n minWidth?: number;\n /** Максимальная ширина колонки (px). Ограничивает ресайз и начальную ширину сверху. */\n maxWidth?: number;\n /** Максимальная ширина колонки при auto-sizing и grow-распределении (px). Не ограничивает ручной ресайз. */\n maxAutoWidth?: number;\n renderHeaderCell?: (\n cellInfo: HeaderCellInfoGlideInstance<R, SR, CustomCtxs>,\n ) => CanvasContent;\n renderCell?: (\n cellInfo: CellInfoGlideInstance<R, SR, CustomCtxs>,\n ) => CellContent;\n contentAlign?: 'left' | 'right' | 'center';\n copyData?: string | ((row: R) => string);\n editable?: boolean | ((row: R) => boolean);\n renderEditCell?: (\n cellInfo: EditingCellInfoGlideInstance<R, SR, CustomCtxs>,\n ) => ReactNode;\n /**\n * Кастомный рендер preview-ячейки (при двойном клике на readonly-ячейку).\n * 'none' — отключает превью. 'cellEditorAsPreview' — стандартный текстовый превью.\n * Функция — полностью кастомный рендер.\n */\n renderCellPreview?:\n | 'none'\n | 'cellEditorAsPreview'\n | ((\n cellInfo: PreviewCellInfoGlideInstance<R, SR, CustomCtxs>,\n ) => ReactNode);\n renderSummaryCell?: (\n cellInfo: SummaryCellInfoGlideInstance<R, SR, CustomCtxs>,\n ) => CellContent;\n colSpan?:\n | number\n | ((cellInfo: CellInfoGlideInstance<R, SR, CustomCtxs>) => number);\n /** Выравнивание в
|
|
55564
|
+
"definition": "export type ColumnGlideInstance<\n R extends ObjectForExtending,\n SR,\n CustomCtxs extends ObjectForExtending = {},\n> = {\n key: string;\n name: string | CanvasEl;\n nameAsString?: string;\n readonly width?: number;\n isServiceColumn?: boolean;\n isErrorCell?: (row: R) => boolean;\n frozen?: boolean;\n /** Минимальная ширина колонки (px). Ограничивает ресайз и начальную ширину снизу. */\n minWidth?: number;\n /** Максимальная ширина колонки (px). Ограничивает ресайз и начальную ширину сверху. */\n maxWidth?: number;\n /** Максимальная ширина колонки при auto-sizing и grow-распределении (px). Не ограничивает ручной ресайз. */\n maxAutoWidth?: number;\n renderHeaderCell?: (\n cellInfo: HeaderCellInfoGlideInstance<R, SR, CustomCtxs>,\n ) => CanvasContent;\n renderCell?: (\n cellInfo: CellInfoGlideInstance<R, SR, CustomCtxs>,\n ) => CellContent;\n contentAlign?: 'left' | 'right' | 'center';\n copyData?: string | ((row: R) => string);\n editable?: boolean | ((row: R) => boolean);\n renderEditCell?: (\n cellInfo: EditingCellInfoGlideInstance<R, SR, CustomCtxs>,\n ) => ReactNode;\n /**\n * Кастомный рендер preview-ячейки (при двойном клике на readonly-ячейку).\n * 'none' — отключает превью. 'cellEditorAsPreview' — стандартный текстовый превью.\n * Функция — полностью кастомный рендер.\n */\n renderCellPreview?:\n | 'none'\n | 'cellEditorAsPreview'\n | ((\n cellInfo: PreviewCellInfoGlideInstance<R, SR, CustomCtxs>,\n ) => ReactNode);\n renderSummaryCell?: (\n cellInfo: SummaryCellInfoGlideInstance<R, SR, CustomCtxs>,\n ) => CellContent;\n colSpan?:\n | number\n | ((cellInfo: CellInfoGlideInstance<R, SR, CustomCtxs>) => number);\n /** Объединение строк: (cellInfo) => [перваяСтрока, последняяСтрока] | null (см. TableGlide RowSpan). */\n rowSpan?: (\n cellInfo: CellInfoGlideInstance<R, SR, CustomCtxs>,\n ) => readonly [number, number] | null;\n /** Выравнивание контента в объединённой ячейке тела; в adaptColumn идёт в glide как `spanAlign`. */\n spanAlign?:\n | SpanCellAlign\n | ((\n cellInfo: CellInfoGlideInstance<R, SR, CustomCtxs>,\n ) => SpanCellAlign | undefined);\n /** Выравнивание в объединённой шапке; в adaptColumn идёт в glide как `spanGroupHeaderAlign`. */\n squashedHeaderAlign?: HeaderAlignment;\n /** Тултип для ячеек этой колонки. Строка, объект или функция (context) => config | null. */\n cellTooltip?:\n | CanvasNodeTooltipConfig\n | ((context: {\n row: R;\n column: ColumnGlideInstance<R, SR, CustomCtxs>;\n ctxs: CtxsType<CustomCtxs>;\n refTable?: React.Ref<DataEditorRef>;\n colInd?: number;\n rowInd?: number;\n theme?: Theme;\n }) => CanvasNodeTooltipConfig | null);\n /** Тултип для шапки колонки. Строка, объект или функция (context) => config | null. */\n headerCellTooltip?:\n | CanvasNodeTooltipConfig\n | ((context: {\n column: ColumnGlideInstance<R, SR, CustomCtxs>;\n ctxs: CtxsType<CustomCtxs>;\n refTable?: React.Ref<DataEditorRef>;\n colInd?: number;\n theme?: Theme;\n }) => CanvasNodeTooltipConfig | null);\n columnThemeOverride?: (\n cellInfo: CellInfoGlideInstance<R, SR, CustomCtxs>,\n ) => CellThemeOverrideResult | undefined;\n};",
|
|
55039
55565
|
"importPath": "@daisforge/ui/components/TableCanvas",
|
|
55040
55566
|
"importStatement": "import { ColumnGlideInstance } from '@daisforge/ui/components/TableCanvas';",
|
|
55041
55567
|
"sourceFile": "packages/ui-kit/src/components/TableCanvas/TableGlideInstance/type.ts"
|
|
@@ -55427,7 +55953,7 @@
|
|
|
55427
55953
|
},
|
|
55428
55954
|
"TableCanvas.ColumnRowsGrouping": {
|
|
55429
55955
|
"name": "ColumnRowsGrouping",
|
|
55430
|
-
"definition": "export 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 renderGroupCell?: (\n props: RenderGroupCellProps<RowType, ColumnConfig>,\n ) => CanvasContent;\n};",
|
|
55956
|
+
"definition": "export 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};",
|
|
55431
55957
|
"internal": true,
|
|
55432
55958
|
"importNotice": "Тип \"ColumnRowsGrouping\" не экспортируется из публичной точки входа — импортировать его нельзя. Определение приведено для понимания структуры: опишите нужную форму по месту либо возьмите её из типа, который экспортирован.",
|
|
55433
55959
|
"sourceFile": "packages/ui-kit/src/components/TableCanvas/feature-rows-grouping/types.ts"
|
|
@@ -55455,7 +55981,7 @@
|
|
|
55455
55981
|
},
|
|
55456
55982
|
"TableGlide.CellInfo": {
|
|
55457
55983
|
"name": "CellInfo",
|
|
55458
|
-
"definition": "export type CellInfo<R extends ObjectForExtending, SR = unknown> = {\n row: R;\n column: ColumnGlideLast<R, SR>;\n colInd: number;\n rowInd: number;\n ctxs: ObjectForExtending;\n theme: Theme;\n /** Состояние наведения для ячейки, которую сейчас рендерит renderCell. */\n hovered: CellHoverState;\n /** Состояние активного выделения для ячейки, которую сейчас рендерит renderCell. */\n active: CellActiveState;\n};",
|
|
55984
|
+
"definition": "export type CellInfo<R extends ObjectForExtending, SR = unknown> = {\n row: R;\n column: ColumnGlideLast<R, SR>;\n colInd: number;\n rowInd: number;\n ctxs: ObjectForExtending;\n theme: Theme;\n /** Состояние наведения для ячейки, которую сейчас рендерит renderCell. */\n hovered: CellHoverState;\n /** Состояние активного выделения для ячейки, которую сейчас рендерит renderCell. */\n active: CellActiveState;\n // Есть только у верхней-левой ячейки объединённого блока. align — выравнивание\n // блока (пусто = по центру). По нему ячейка-select расставляет контент и\n // уголок по высоте всего блока.\n __mergedCell?: { align?: SpanCellAlign };\n};",
|
|
55459
55985
|
"internal": true,
|
|
55460
55986
|
"importNotice": "Тип \"CellInfo\" не экспортируется из публичной точки входа — импортировать его нельзя. Определение приведено для понимания структуры: опишите нужную форму по месту либо возьмите её из типа, который экспортирован.",
|
|
55461
55987
|
"sourceFile": "packages/ui-kit/src/components/TableGlide/types.ts"
|
|
@@ -55488,6 +56014,13 @@
|
|
|
55488
56014
|
"importStatement": "import { HeaderAlignment } from '@daisforge/ui/components/TableCanvas';",
|
|
55489
56015
|
"sourceFile": "packages/ui-kit/src/components/TableCanvas/types/columns-grouping.type.ts"
|
|
55490
56016
|
},
|
|
56017
|
+
"MergedCellsAlign": {
|
|
56018
|
+
"name": "MergedCellsAlign",
|
|
56019
|
+
"definition": "export type MergedCellsAlign = {\n /** По горизонтали. @default из `contentFormat.alignContent` колонки, иначе 'left' */\n horizontal?: 'left' | 'center' | 'right';\n /** По вертикали. @default 'center' */\n vertical?: 'top' | 'center' | 'bottom';\n};",
|
|
56020
|
+
"importPath": "@daisforge/ui/components/TableCanvas",
|
|
56021
|
+
"importStatement": "import { MergedCellsAlign } from '@daisforge/ui/components/TableCanvas';",
|
|
56022
|
+
"sourceFile": "packages/ui-kit/src/components/TableCanvas/types/merged-cells.type.ts"
|
|
56023
|
+
},
|
|
55491
56024
|
"CanvasEl": {
|
|
55492
56025
|
"name": "CanvasEl",
|
|
55493
56026
|
"definition": "export type CanvasEl = ReactElement;",
|
|
@@ -55537,6 +56070,13 @@
|
|
|
55537
56070
|
"importStatement": "import { SummaryCellInfoGlideInstance } from '@daisforge/ui/components/TableCanvas';",
|
|
55538
56071
|
"sourceFile": "packages/ui-kit/src/components/TableCanvas/TableGlideInstance/type.ts"
|
|
55539
56072
|
},
|
|
56073
|
+
"SpanCellAlign": {
|
|
56074
|
+
"name": "SpanCellAlign",
|
|
56075
|
+
"definition": "export type SpanCellAlign = {\n /** По горизонтали. @default из contentAlign колонки, иначе 'left' */\n horizontal?: 'left' | 'center' | 'right';\n /** По вертикали. @default 'center' */\n vertical?: 'top' | 'center' | 'bottom';\n};",
|
|
56076
|
+
"internal": true,
|
|
56077
|
+
"importNotice": "Тип \"SpanCellAlign\" не экспортируется из публичной точки входа — импортировать его нельзя. Определение приведено для понимания структуры: опишите нужную форму по месту либо возьмите её из типа, который экспортирован.",
|
|
56078
|
+
"sourceFile": "packages/ui-kit/src/components/TableGlide/types.ts"
|
|
56079
|
+
},
|
|
55540
56080
|
"CanvasNodeTooltipConfig": {
|
|
55541
56081
|
"name": "CanvasNodeTooltipConfig",
|
|
55542
56082
|
"definition": "export type CanvasNodeTooltipConfig =\n | string\n | (CanvasNodeTooltipProps & {\n /** Текст тултипа (только string, не ReactNode). */\n text: string;\n /** Задержка перед показом (мс). По умолчанию 0. */\n mouseEnterDelay?: number;\n /** Задержка перед скрытием после ухода мыши (мс). По умолчанию 0. */\n mouseLeaveDelay?: number;\n });",
|
|
@@ -55546,7 +56086,7 @@
|
|
|
55546
56086
|
},
|
|
55547
56087
|
"CtxsType": {
|
|
55548
56088
|
"name": "CtxsType",
|
|
55549
|
-
"definition": "export type CtxsType<Customs extends ObjectForExtending | void = {}> = {\n selectingRowCtx: SelectingContextType;\n headerCtx: HeaderContextValueTypeInstance<ObjectForExtending>;\n expandedRowsCtx: {\n expandedRowsIds: ExpandedRowsContextV | null;\n setExpandedRowsIds: ExpandedRowsChangeContextV | null;\n handleExpandRowDetail: HandleExpandDetail<ObjectForExtending>;\n expandButtonColumnKey: string | undefined;\n };\n rowCtx: ObjectForExtending;\n} & Customs;",
|
|
56089
|
+
"definition": "export type CtxsType<Customs extends ObjectForExtending | void = {}> = {\n selectingRowCtx: SelectingContextType;\n headerCtx: HeaderContextValueTypeInstance<ObjectForExtending>;\n expandedRowsCtx: {\n expandedRowsIds: ExpandedRowsContextV | null;\n setExpandedRowsIds: ExpandedRowsChangeContextV | null;\n handleExpandRowDetail: HandleExpandDetail<ObjectForExtending>;\n expandButtonColumnKey: string | undefined;\n };\n rowCtx: ObjectForExtending;\n /**\n * Высота ОДНОГО header-ряда (листового и каждого групп-уровня — они равны).\n * Нужна рендерам шапки, чтобы позиционировать контент в ПОСЛЕДНЕМ (листовом)\n * уровне слитой многоуровневой шапки (напр. общий чекбокс прижимается к низу).\n */\n headerHeight: number;\n /** Число групп-уровней шапки (0 — одноуровневая шапка). */\n groupHeaderLevels: number;\n} & Customs;",
|
|
55550
56090
|
"internal": true,
|
|
55551
56091
|
"importNotice": "Тип \"CtxsType\" не экспортируется из публичной точки входа — импортировать его нельзя. Определение приведено для понимания структуры: опишите нужную форму по месту либо возьмите её из типа, который экспортирован.",
|
|
55552
56092
|
"sourceFile": "packages/ui-kit/src/components/TableCanvas/types/ctxs.type.ts"
|
|
@@ -55630,7 +56170,7 @@
|
|
|
55630
56170
|
},
|
|
55631
56171
|
"ColumnGlideCustoms": {
|
|
55632
56172
|
"name": "ColumnGlideCustoms",
|
|
55633
|
-
"definition": "export type ColumnGlideCustoms<R extends ObjectForExtending, SR = unknown> = {\n id: string;\n /** Служебные колонки (marker / checkbox / row instruments) живут по отдельным правилам подсветки. */\n isServiceColumn?: boolean;\n /** Внутренний helper для cell-level error outline, совпадающий по семантике с Table editing error. */\n isErrorCell?: (row: R) => boolean;\n renderHeaderCell?: (cellInfo: HeaderCellInfo<R, SR>) => CanvasContent;\n /** Текстовое представление ячейки для копирования в clipboard (Ctrl+C). */\n copyData?: string | ((row: R) => string);\n editable?: boolean | ((row: R) => boolean);\n contentAlign?: 'right' | 'left' | 'center';\n renderCell?: ColumnGlideGetCellContent<R, SR>;\n renderEditCell?: (cellInfo: EditingCellInfoGlide<R, SR>) => CellContent;\n renderSummaryCell?: (summaryCellInfo: SummaryCellInfo<R, SR>) => CellContent;\n colSpan?: ColSpan<R, SR>;\n /** Тултип для ячеек этой колонки. Строка, объект или функция (context) => config | null. */\n cellTooltip?:\n | CanvasNodeTooltipConfig\n | ((context: {\n row: R;\n column: ColumnGlideLast<R, SR>;\n ctxs: ObjectForExtending;\n refTable?: Ref<DataEditorRef>;\n colInd?: number;\n rowInd?: number;\n theme?: Theme;\n }) => CanvasNodeTooltipConfig | null);\n /** Тултип для шапки этой колонки. Строка, объект или функция (context) => config | null. */\n headerCellTooltip?:\n | CanvasNodeTooltipConfig\n | ((context: {\n column: ColumnGlideLast<R, SR>;\n ctxs: ObjectForExtending;\n refTable?: Ref<DataEditorRef>;\n colInd?: number;\n theme?: Theme;\n }) => CanvasNodeTooltipConfig | null);\n columnThemeOverride?: (\n cellInfo: CellInfo<R, SR>\n ) => CellThemeOverrideResult | undefined;\n /** Управление preview для колонки. true — включить overlay, 'none' — отключить (в т.ч. стандартный). */\n hasPreview?: boolean | 'none';\n /** Минимальная ширина колонки (px). Ограничивает ресайз и начальную ширину снизу. */\n minWidth?: number;\n /** Максимальная ширина колонки (px). Ограничивает ресайз и начальную ширину сверху. */\n maxWidth?: number;\n};",
|
|
56173
|
+
"definition": "export type ColumnGlideCustoms<R extends ObjectForExtending, SR = unknown> = {\n id: string;\n /** Служебные колонки (marker / checkbox / row instruments) живут по отдельным правилам подсветки. */\n isServiceColumn?: boolean;\n /** Внутренний helper для cell-level error outline, совпадающий по семантике с Table editing error. */\n isErrorCell?: (row: R) => boolean;\n renderHeaderCell?: (cellInfo: HeaderCellInfo<R, SR>) => CanvasContent;\n /** Текстовое представление ячейки для копирования в clipboard (Ctrl+C). */\n copyData?: string | ((row: R) => string);\n editable?: boolean | ((row: R) => boolean);\n contentAlign?: 'right' | 'left' | 'center';\n renderCell?: ColumnGlideGetCellContent<R, SR>;\n renderEditCell?: (cellInfo: EditingCellInfoGlide<R, SR>) => CellContent;\n renderSummaryCell?: (summaryCellInfo: SummaryCellInfo<R, SR>) => CellContent;\n colSpan?: ColSpan<R, SR>;\n rowSpan?: RowSpan<R, SR>;\n /** Выравнивание контента в объединённых ячейках колонки; функция — если нужно задавать для каждого блока отдельно. */\n spanAlign?: SpanCellAlign | ((cellInfo: CellInfo<R, SR>) => SpanCellAlign | undefined);\n /** Тултип для ячеек этой колонки. Строка, объект или функция (context) => config | null. */\n cellTooltip?:\n | CanvasNodeTooltipConfig\n | ((context: {\n row: R;\n column: ColumnGlideLast<R, SR>;\n ctxs: ObjectForExtending;\n refTable?: Ref<DataEditorRef>;\n colInd?: number;\n rowInd?: number;\n theme?: Theme;\n }) => CanvasNodeTooltipConfig | null);\n /** Тултип для шапки этой колонки. Строка, объект или функция (context) => config | null. */\n headerCellTooltip?:\n | CanvasNodeTooltipConfig\n | ((context: {\n column: ColumnGlideLast<R, SR>;\n ctxs: ObjectForExtending;\n refTable?: Ref<DataEditorRef>;\n colInd?: number;\n theme?: Theme;\n }) => CanvasNodeTooltipConfig | null);\n columnThemeOverride?: (\n cellInfo: CellInfo<R, SR>\n ) => CellThemeOverrideResult | undefined;\n /** Управление preview для колонки. true — включить overlay, 'none' — отключить (в т.ч. стандартный). */\n hasPreview?: boolean | 'none';\n /** Минимальная ширина колонки (px). Ограничивает ресайз и начальную ширину снизу. */\n minWidth?: number;\n /** Максимальная ширина колонки (px). Ограничивает ресайз и начальную ширину сверху. */\n maxWidth?: number;\n};",
|
|
55634
56174
|
"internal": true,
|
|
55635
56175
|
"importNotice": "Тип \"ColumnGlideCustoms\" не экспортируется из публичной точки входа — импортировать его нельзя. Определение приведено для понимания структуры: опишите нужную форму по месту либо возьмите её из типа, который экспортирован.",
|
|
55636
56176
|
"sourceFile": "packages/ui-kit/src/components/TableGlide/types.ts"
|
|
@@ -55882,9 +56422,9 @@
|
|
|
55882
56422
|
},
|
|
55883
56423
|
"PopupDFSize": {
|
|
55884
56424
|
"name": "PopupDFSize",
|
|
55885
|
-
"definition": "export type PopupDFSize = 's' | 'm';",
|
|
55886
|
-
"
|
|
55887
|
-
"
|
|
56425
|
+
"definition": "export type PopupDFSize = 's' | 'm' | 'l';",
|
|
56426
|
+
"importPath": "@daisforge/ui",
|
|
56427
|
+
"importStatement": "import { PopupDFSize } from '@daisforge/ui';",
|
|
55888
56428
|
"sourceFile": "packages/ui-kit/src/components/PopupDF/types.ts"
|
|
55889
56429
|
},
|
|
55890
56430
|
"SplitViewAdaptiveContent": {
|
|
@@ -55980,7 +56520,7 @@
|
|
|
55980
56520
|
},
|
|
55981
56521
|
"TableCanvas.TableConfig": {
|
|
55982
56522
|
"name": "TableConfig",
|
|
55983
|
-
"definition": "export 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 *
|
|
56523
|
+
"definition": "export 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 * блок описан кл…",
|
|
55984
56524
|
"importPath": "@daisforge/ui/components/TableCanvas",
|
|
55985
56525
|
"importStatement": "import { TableConfig } from '@daisforge/ui/components/TableCanvas';",
|
|
55986
56526
|
"sourceFile": "packages/ui-kit/src/components/TableCanvas/types/table-config.type.ts"
|
|
@@ -56554,7 +57094,7 @@
|
|
|
56554
57094
|
},
|
|
56555
57095
|
"TableCanvas.DefaultOmittedKeys": {
|
|
56556
57096
|
"name": "DefaultOmittedKeys",
|
|
56557
|
-
"definition": "export type DefaultOmittedKeys = Extract<\n keyof ColumnGlideInstance<ObjectForExtending, unknown, ObjectForExtending>,\n | 'editable'\n | 'frozen'\n | 'isServiceColumn'\n | 'isErrorCell'\n | 'renderEditCell'\n | 'renderCellPreview'\n | 'renderCell'\n | 'columnThemeOverride'\n>;",
|
|
57097
|
+
"definition": "export type DefaultOmittedKeys = Extract<\n keyof ColumnGlideInstance<ObjectForExtending, unknown, ObjectForExtending>,\n | 'editable'\n | 'frozen'\n | 'isServiceColumn'\n | 'isErrorCell'\n | 'renderEditCell'\n | 'renderCellPreview'\n | 'renderCell'\n | 'columnThemeOverride'\n // Объединение ячеек тела задаётся только через tableConfig.mergeCells\n // (mergeByCellValues / mergedCellsRegions). Колоночные colSpan/rowSpan убраны:\n // они позиционные и небезопасны при реордере. Внутри (ColumnConfigInternal)\n // остаются как труба, в которую mergeCells синтезирует объединения.\n | 'colSpan'\n | 'rowSpan'\n // Выравнивание блока публично задаётся через mergedCellsAlign / mergeCells.align.\n | 'spanAlign'\n>;",
|
|
56558
57098
|
"internal": true,
|
|
56559
57099
|
"importNotice": "Тип \"DefaultOmittedKeys\" не экспортируется из публичной точки входа — импортировать его нельзя. Определение приведено для понимания структуры: опишите нужную форму по месту либо возьмите её из типа, который экспортирован.",
|
|
56560
57100
|
"sourceFile": "packages/ui-kit/src/components/TableCanvas/types/glide-type.ts"
|
|
@@ -56708,7 +57248,7 @@
|
|
|
56708
57248
|
},
|
|
56709
57249
|
"CanvasNodeTooltipProps": {
|
|
56710
57250
|
"name": "CanvasNodeTooltipProps",
|
|
56711
|
-
"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};",
|
|
56712
57252
|
"importPath": "@daisforge/ui/components/TableCanvas",
|
|
56713
57253
|
"importStatement": "import { CanvasNodeTooltipProps } from '@daisforge/ui/components/TableCanvas';",
|
|
56714
57254
|
"sourceFile": "packages/ui-kit/src/components/TableGlide/lib/canvas/utils/portalHoverEvents.ts"
|
|
@@ -56783,6 +57323,13 @@
|
|
|
56783
57323
|
"importNotice": "Тип \"ColSpan\" не экспортируется из публичной точки входа — импортировать его нельзя. Определение приведено для понимания структуры: опишите нужную форму по месту либо возьмите её из типа, который экспортирован.",
|
|
56784
57324
|
"sourceFile": "packages/ui-kit/src/components/TableGlide/types.ts"
|
|
56785
57325
|
},
|
|
57326
|
+
"RowSpan": {
|
|
57327
|
+
"name": "RowSpan",
|
|
57328
|
+
"definition": "export type RowSpan<R extends ObjectForExtending, SR> = (\n cellInfo: CellInfo<R, SR>\n) => readonly [number, number] | null;",
|
|
57329
|
+
"internal": true,
|
|
57330
|
+
"importNotice": "Тип \"RowSpan\" не экспортируется из публичной точки входа — импортировать его нельзя. Определение приведено для понимания структуры: опишите нужную форму по месту либо возьмите её из типа, который экспортирован.",
|
|
57331
|
+
"sourceFile": "packages/ui-kit/src/components/TableGlide/types.ts"
|
|
57332
|
+
},
|
|
56786
57333
|
"TableCanvas.DomMetadata": {
|
|
56787
57334
|
"name": "DomMetadata",
|
|
56788
57335
|
"definition": "export type 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};",
|
|
@@ -56981,7 +57528,7 @@
|
|
|
56981
57528
|
},
|
|
56982
57529
|
"TableCanvas.SubRows": {
|
|
56983
57530
|
"name": "SubRows",
|
|
56984
|
-
"definition": "export type SubRows<RowType, RowIdType> = {\n /**\n *
|
|
57531
|
+
"definition": "export type 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};",
|
|
56985
57532
|
"internal": true,
|
|
56986
57533
|
"importNotice": "Тип \"SubRows\" не экспортируется из публичной точки входа — импортировать его нельзя. Определение приведено для понимания структуры: опишите нужную форму по месту либо возьмите её из типа, который экспортирован.",
|
|
56987
57534
|
"sourceFile": "packages/ui-kit/src/components/TableCanvas/feature-tree/types.ts"
|
|
@@ -56995,7 +57542,7 @@
|
|
|
56995
57542
|
},
|
|
56996
57543
|
"TableCanvas.RowsGrouping": {
|
|
56997
57544
|
"name": "RowsGrouping",
|
|
56998
|
-
"definition": "export type 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 * Функция определения уникального id строки\n */\n rowKeyGetter: (row: RowType) => string | number;\n /**\n * Показывать ли кнопку «Группировать» в controlBlock.\n * При `false` кнопка скрыта и не участвует в компрессии,\n * но группировка строк продолжает работать от внешнего `groupByState`.\n * @default true\n */\n showInControl?: boolean;\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 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};",
|
|
57545
|
+
"definition": "export type 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};",
|
|
56999
57546
|
"internal": true,
|
|
57000
57547
|
"importNotice": "Тип \"RowsGrouping\" не экспортируется из публичной точки входа — импортировать его нельзя. Определение приведено для понимания структуры: опишите нужную форму по месту либо возьмите её из типа, который экспортирован.",
|
|
57001
57548
|
"sourceFile": "packages/ui-kit/src/components/TableCanvas/feature-rows-grouping/types.ts"
|
|
@@ -57037,7 +57584,7 @@
|
|
|
57037
57584
|
},
|
|
57038
57585
|
"TableCanvas.ColumnsControlConfig": {
|
|
57039
57586
|
"name": "ColumnsControlConfig",
|
|
57040
|
-
"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 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};",
|
|
57041
57588
|
"internal": true,
|
|
57042
57589
|
"importNotice": "Тип \"ColumnsControlConfig\" не экспортируется из публичной точки входа — импортировать его нельзя. Определение приведено для понимания структуры: опишите нужную форму по месту либо возьмите её из типа, который экспортирован.",
|
|
57043
57590
|
"sourceFile": "packages/ui-kit/src/components/TableCanvas/feature-column-control/types.ts"
|
|
@@ -57644,6 +58191,13 @@
|
|
|
57644
58191
|
"importStatement": "import { CellTransferConfig } from '@daisforge/ui/components/TableCanvas';",
|
|
57645
58192
|
"sourceFile": "packages/ui-kit/src/components/TableCanvas/feature-cell-transfer/types.ts"
|
|
57646
58193
|
},
|
|
58194
|
+
"MergedCellsRegion": {
|
|
58195
|
+
"name": "MergedCellsRegion",
|
|
58196
|
+
"definition": "export type MergedCellsRegion = {\n rowKeys: Array<string | number>;\n colKeys: string[];\n /** Выравнивание контента этого блока. Важнее колоночного и общего. */\n mergedCellsAlign?: MergedCellsAlign;\n};",
|
|
58197
|
+
"importPath": "@daisforge/ui/components/TableCanvas",
|
|
58198
|
+
"importStatement": "import { MergedCellsRegion } from '@daisforge/ui/components/TableCanvas';",
|
|
58199
|
+
"sourceFile": "packages/ui-kit/src/components/TableCanvas/types/table-config.type.ts"
|
|
58200
|
+
},
|
|
57647
58201
|
"TableNotificationsConfig": {
|
|
57648
58202
|
"name": "TableNotificationsConfig",
|
|
57649
58203
|
"definition": "export interface TableNotificationsConfig {\n /** Вызывается на каждое событие таблицы (ошибки copy/paste и т.д.). */\n onNotification: (event: TableNotification) => void;\n}",
|
|
@@ -57653,14 +58207,14 @@
|
|
|
57653
58207
|
},
|
|
57654
58208
|
"RowMarkersTableConfig": {
|
|
57655
58209
|
"name": "RowMarkersTableConfig",
|
|
57656
|
-
"definition": "export 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 *
|
|
58210
|
+
"definition": "export 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};",
|
|
57657
58211
|
"importPath": "@daisforge/ui/components/TableCanvas",
|
|
57658
58212
|
"importStatement": "import { RowMarkersTableConfig } from '@daisforge/ui/components/TableCanvas';",
|
|
57659
58213
|
"sourceFile": "packages/ui-kit/src/components/TableCanvas/types/table-config.type.ts"
|
|
57660
58214
|
},
|
|
57661
58215
|
"TableConfigTooltip": {
|
|
57662
58216
|
"name": "TableConfigTooltip",
|
|
57663
|
-
"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};",
|
|
57664
58218
|
"importPath": "@daisforge/ui/components/TableCanvas",
|
|
57665
58219
|
"importStatement": "import { TableConfigTooltip } from '@daisforge/ui/components/TableCanvas';",
|
|
57666
58220
|
"sourceFile": "packages/ui-kit/src/components/TableCanvas/types/table-config.type.ts"
|