@daisforge/ui 1.22.0 → 1.23.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/AiAgentPopup-CLGSjg5L.cjs +11 -0
- package/chunks/AiAgentPopup-CtMhai1X.mjs +797 -0
- package/chunks/AnalyticalWidget-Bvcm1qpU.cjs +43 -0
- package/chunks/AnalyticalWidget-CRfihris.mjs +352 -0
- package/chunks/ApprovalCenter-D7K7J-QB.cjs +1 -0
- package/chunks/{ApprovalCenter-DLKZP2AO.mjs → ApprovalCenter-dJpI91uN.mjs} +10 -10
- package/chunks/BlockTitle-CcYYHiOo.cjs +1 -0
- package/chunks/{BlockTitle-DsXxImR6.mjs → BlockTitle-DCmM-9AN.mjs} +2 -2
- package/chunks/{Container-DbZwlfIM.mjs → Container-C7PzvUwd.mjs} +1 -1
- package/chunks/{Container-DHnX1sHY.cjs → Container-bVqI3en9.cjs} +1 -1
- package/chunks/{EmptyState-DH1xawxg.cjs → EmptyState-D-bmtvmy.cjs} +1 -1
- package/chunks/{EmptyState-CUCseg9M.mjs → EmptyState-ZsOlvU4d.mjs} +1 -1
- package/chunks/{FiltersActions-BJ5gD6Nx.mjs → FiltersActions-CS27WxA6.mjs} +15 -15
- package/chunks/FiltersActions-Cie245Po.cjs +1 -0
- package/chunks/{FormSegmentGroup-BYQ6yMK1.cjs → FormSegmentGroup-CNIqOYfm.cjs} +1 -1
- package/chunks/{FormSegmentGroup-C9qYxYT9.mjs → FormSegmentGroup-DwTRM58f.mjs} +1 -1
- package/chunks/{GridDND-DK6SAO8q.cjs → GridDND-Bwmr7gla.cjs} +1 -1
- package/chunks/{GridDND-CqvpXgCY.mjs → GridDND-DC5VoxEY.mjs} +83 -83
- package/chunks/{LeftPanel-C5SsoRJS.mjs → LeftPanel-C10BLKIn.mjs} +1 -1
- package/chunks/{LeftPanel-AyuV7bGS.cjs → LeftPanel-upGFk7jM.cjs} +1 -1
- package/chunks/{ListOfFilters-CfV2bs_4.mjs → ListOfFilters-CEWrWotU.mjs} +3 -3
- package/chunks/{ListOfFilters-mqTsQbq_.cjs → ListOfFilters-DNi-z1cn.cjs} +1 -1
- package/chunks/MassActions-DJiKcC6r.cjs +1 -0
- package/chunks/{MassActions-C6LY-g9r.mjs → MassActions-NLCRjIHw.mjs} +46 -46
- package/chunks/PageTitle-Bg4PNEXS.cjs +9 -0
- package/chunks/{PageTitle-DkfAiZM4.mjs → PageTitle-CXtNgH-b.mjs} +7 -7
- package/chunks/{SplitView-BqS1Jbo4.mjs → SplitView-BzamJzNc.mjs} +17 -17
- package/chunks/{SplitView-DNmd4sJe.cjs → SplitView-DeJ3V-kq.cjs} +1 -1
- package/chunks/Stories-CNlL0Bcb.cjs +1 -0
- package/chunks/{Stories-BnHxMCEZ.mjs → Stories-UUV0GNEV.mjs} +33 -33
- package/chunks/{Table-vv1HTrxe.cjs → Table-CZludfzU.cjs} +6 -6
- package/chunks/{Table-tUWuA3Ri.mjs → Table-FrYs56BB.mjs} +1597 -1586
- package/chunks/{TableCanvas-BX5aciu7.mjs → TableCanvas-CasYPFSm.mjs} +5872 -5633
- package/chunks/TableCanvas-DFne0YHS.cjs +30 -0
- package/chunks/TableGlide-BKSjSgBn.mjs +9131 -0
- package/chunks/TableGlide-C2_HrWEA.cjs +1 -0
- package/chunks/{styles-CJ5y9FKW.mjs → styles-CJPkBVWK.mjs} +6 -6
- package/chunks/{styles-kUWPuNSD.cjs → styles-CpC_FuBg.cjs} +1 -1
- package/chunks/{utils-u1KJ37g3.mjs → utils-Hu77fGGe.mjs} +102 -102
- package/chunks/{utils-ChDQGRjv.cjs → utils-OQNruMpn.cjs} +5 -5
- package/components/AiAgentPopover/index.cjs +1 -1
- package/components/AiAgentPopover/index.mjs +1 -1
- package/components/AiAgentPopup/AiAgentInput.d.ts +3 -0
- package/components/AiAgentPopup/AiAgentLeftPanel.d.ts +6 -0
- package/components/AiAgentPopup/AiAgentPopup.constants.d.ts +32 -0
- package/components/AiAgentPopup/AiAgentPopup.d.ts +3 -0
- package/components/AiAgentPopup/AiAgentPopup.styled.d.ts +33 -0
- package/components/AiAgentPopup/AiAgentPopup.types.d.ts +83 -0
- package/components/AiAgentPopup/AiAgentPopup.utils.d.ts +12 -0
- package/components/AiAgentPopup/AiAgentSurface.d.ts +6 -0
- package/components/AiAgentPopup/hooks/useDrag.d.ts +18 -0
- package/components/AiAgentPopup/hooks/useIsDarkTheme.d.ts +1 -0
- package/components/AiAgentPopup/hooks/usePopupPosition.d.ts +20 -0
- package/components/AiAgentPopup/hooks/usePopupResize.d.ts +40 -0
- package/components/AiAgentPopup/hooks/useStateStorage.d.ts +6 -0
- package/components/AiAgentPopup/index.cjs +1 -0
- package/components/AiAgentPopup/index.d.ts +3 -0
- package/components/AiAgentPopup/index.mjs +5 -0
- package/components/AnalyticalWidget/AnalyticalWidget.d.ts +8 -24
- package/components/AnalyticalWidget/components/AnalyticalWidgetButtons/AnalyticalWidgetIconButtonDots.d.ts +8 -24
- 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 +2 -2
- package/components/AnalyticalWidget/components/AnalyticalWidgetHeader/index.cjs +1 -1
- package/components/AnalyticalWidget/components/AnalyticalWidgetHeader/index.mjs +2 -2
- 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/Autocomplete/Autocomplete.d.ts +128 -128
- package/components/AutocompleteSearch/index.cjs +1 -1
- package/components/AutocompleteSearch/index.mjs +2 -2
- package/components/BlockGradientScroll/index.cjs +1 -1
- package/components/BlockGradientScroll/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/Collapse/index.cjs +1 -1
- package/components/Collapse/index.mjs +1 -1
- package/components/Combobox/index.cjs +1 -1
- package/components/Combobox/index.mjs +1 -1
- package/components/EmptyState/components/index.cjs +1 -1
- package/components/EmptyState/components/index.mjs +1 -1
- package/components/EmptyState/index.cjs +1 -1
- package/components/EmptyState/index.mjs +1 -1
- 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/IconButton/index.cjs +1 -1
- package/components/IconButton/index.mjs +1 -1
- package/components/LeftPanel/components/index.cjs +1 -1
- package/components/LeftPanel/components/index.mjs +1 -1
- package/components/LeftPanel/hooks/index.cjs +1 -1
- package/components/LeftPanel/hooks/index.mjs +1 -1
- package/components/LeftPanel/index.cjs +1 -1
- package/components/LeftPanel/index.mjs +1 -1
- package/components/LeftPanel/utils/index.cjs +1 -1
- package/components/LeftPanel/utils/index.mjs +1 -1
- 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/ModalDF/index.cjs +1 -1
- package/components/ModalDF/index.mjs +1 -1
- package/components/Notification/index.cjs +1 -1
- package/components/Notification/index.mjs +6 -6
- 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 +9 -9
- package/components/PopoverDF/styled.d.ts +1 -23
- package/components/PopupDF/index.cjs +1 -1
- package/components/PopupDF/index.mjs +118 -143
- package/components/SplitView/index.cjs +1 -1
- package/components/SplitView/index.mjs +1 -1
- package/components/SplitView/utils/index.cjs +1 -1
- package/components/SplitView/utils/index.mjs +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/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-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-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/index.cjs +1 -1
- package/components/Table/feature-filtering/index.mjs +1 -1
- package/components/Table/feature-filtering/popover.d.ts +1 -23
- 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/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 +128 -128
- 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-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/types/utils.type.d.ts +1 -1
- package/components/Table/utils/index.cjs +1 -1
- package/components/Table/utils/index.mjs +1 -1
- 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/TableGlideInstance.d.ts +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 +6 -6
- package/components/TableCanvas/TableGlideInstance/type.d.ts +3 -0
- package/components/TableCanvas/TableGlideInstance/utils/column/index.cjs +1 -1
- package/components/TableCanvas/TableGlideInstance/utils/column/index.mjs +2 -2
- 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/contexts.d.ts +8 -2
- package/components/TableCanvas/feature-cell-transfer/index.cjs +1 -1
- package/components/TableCanvas/feature-cell-transfer/index.mjs +13 -13
- package/components/TableCanvas/feature-collapse-table/index.cjs +1 -1
- package/components/TableCanvas/feature-collapse-table/index.mjs +2 -2
- package/components/TableCanvas/feature-column-control/ColumnsList/index.cjs +1 -1
- package/components/TableCanvas/feature-column-control/ColumnsList/index.mjs +2 -2
- package/components/TableCanvas/feature-column-control/index.cjs +1 -1
- package/components/TableCanvas/feature-column-control/index.mjs +4 -4
- package/components/TableCanvas/feature-columns-grouping/index.cjs +1 -1
- package/components/TableCanvas/feature-columns-grouping/index.mjs +3 -3
- 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 +6 -6
- package/components/TableCanvas/feature-filtering/combobox/index.cjs +1 -1
- package/components/TableCanvas/feature-filtering/combobox/index.mjs +4 -4
- package/components/TableCanvas/feature-filtering/filter-list-block/index.cjs +1 -1
- package/components/TableCanvas/feature-filtering/filter-list-block/index.mjs +1 -1
- 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/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 +4 -4
- package/components/TableCanvas/feature-key-text/index.cjs +1 -1
- package/components/TableCanvas/feature-key-text/index.mjs +6 -6
- package/components/TableCanvas/feature-notifications/index.cjs +1 -1
- package/components/TableCanvas/feature-notifications/index.mjs +2 -2
- package/components/TableCanvas/feature-pagination/TablePagination.d.ts +2 -0
- package/components/TableCanvas/feature-pagination/index.cjs +1 -1
- package/components/TableCanvas/feature-pagination/index.mjs +3 -3
- package/components/TableCanvas/feature-popover-table/components/styled.d.ts +1 -23
- 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 +3 -3
- 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/compatibility.d.ts +8 -0
- package/components/TableCanvas/feature-right-sidebar/index.cjs +1 -1
- package/components/TableCanvas/feature-right-sidebar/index.d.ts +2 -3
- package/components/TableCanvas/feature-right-sidebar/index.mjs +3 -3
- 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 +7 -7
- 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 +4 -4
- package/components/TableCanvas/feature-rows-grouping/index.cjs +1 -1
- package/components/TableCanvas/feature-rows-grouping/index.mjs +10 -10
- 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 +128 -128
- package/components/TableCanvas/feature-select-row/index.cjs +1 -1
- package/components/TableCanvas/feature-select-row/index.mjs +1 -1
- package/components/TableCanvas/feature-sidebar/constants.d.ts +7 -0
- package/components/TableCanvas/feature-sidebar/getCustomSidebarTabs.d.ts +4 -0
- package/components/TableCanvas/feature-sidebar/index.cjs +1 -0
- package/components/TableCanvas/feature-sidebar/index.d.ts +1 -0
- package/components/TableCanvas/feature-sidebar/index.mjs +4 -0
- package/components/TableCanvas/feature-sidebar/ui/BottomSheet.d.ts +6 -0
- package/components/TableCanvas/feature-sidebar/ui/BottomSheet.styled.d.ts +6 -0
- package/components/TableCanvas/{feature-right-sidebar → feature-sidebar}/ui/SidebarContentLayout.d.ts +1 -0
- package/components/TableCanvas/{feature-right-sidebar → feature-sidebar}/ui/SidebarTabs.d.ts +2 -1
- package/components/TableCanvas/feature-sidebar/ui/TableSidebar.d.ts +16 -0
- package/components/TableCanvas/{feature-right-sidebar → feature-sidebar}/ui/styled.d.ts +5 -2
- package/components/TableCanvas/feature-sidebar/useSidebarTabsState.d.ts +14 -0
- package/components/TableCanvas/feature-sorting/index.cjs +1 -1
- package/components/TableCanvas/feature-sorting/index.mjs +1 -1
- package/components/TableCanvas/feature-sticky/index.cjs +1 -0
- package/components/TableCanvas/feature-sticky/index.d.ts +3 -0
- package/components/TableCanvas/feature-sticky/index.mjs +5 -0
- package/components/TableCanvas/feature-sticky/types.d.ts +2 -0
- package/components/TableCanvas/feature-sticky/useStickyColumnIndexes.d.ts +8 -0
- package/components/TableCanvas/feature-sticky/useStickyRowIndexes.d.ts +3 -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/index.cjs +1 -1
- package/components/TableCanvas/feature-tooltip/index.mjs +2 -2
- 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/index.cjs +1 -1
- package/components/TableCanvas/index.d.ts +2 -1
- package/components/TableCanvas/index.mjs +43 -41
- package/components/TableCanvas/renders/formatCell/index.cjs +1 -1
- package/components/TableCanvas/renders/formatCell/index.mjs +1 -1
- package/components/TableCanvas/styles/classNames.d.ts +1 -0
- package/components/TableCanvas/styles/getReservedTableHeight.d.ts +18 -0
- package/components/TableCanvas/styles/index.cjs +1 -1
- package/components/TableCanvas/styles/index.mjs +10 -10
- package/components/TableCanvas/styles/styles.constants.d.ts +1 -1
- package/components/TableCanvas/styles/styles.d.ts +2 -5
- package/components/TableCanvas/table-hooks/index.cjs +1 -1
- package/components/TableCanvas/table-hooks/index.mjs +4 -4
- package/components/TableCanvas/table-hooks/useInlineStyle.d.ts +2 -1
- package/components/TableCanvas/table-hooks/useLeftSidebarValues.d.ts +7 -0
- package/components/TableCanvas/table-hooks/useSidebarOpenState.d.ts +11 -0
- package/components/TableCanvas/table-hooks/useSidebarValues.d.ts +1 -0
- package/components/TableCanvas/types/index.cjs +1 -1
- package/components/TableCanvas/types/index.mjs +2 -2
- package/components/TableCanvas/types/table-config.type.d.ts +19 -1
- package/components/TableCanvas/utils/index.cjs +1 -1
- package/components/TableCanvas/utils/index.mjs +2 -2
- 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.constants.d.ts +6 -0
- package/components/TableCanvas/widgets/control-block/index.cjs +1 -1
- package/components/TableCanvas/widgets/control-block/index.mjs +5 -5
- 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/control-block/types.d.ts +1 -0
- package/components/TableCanvas/widgets/index.cjs +1 -1
- package/components/TableCanvas/widgets/index.mjs +5 -5
- package/components/TableCanvas/widgets/mass-actions/MassActions.d.ts +2 -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/hooks/useMassActionsCanvasWidth.d.ts +1 -0
- package/components/TableCanvas/widgets/mass-actions/hooks/useMassActionsCompression.d.ts +1 -1
- package/components/TableCanvas/widgets/mass-actions/hooks/useMassActionsSidebar.d.ts +4 -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/table-or-card-UI.d.ts +6 -3
- package/components/TableContract/index.cjs +1 -1
- package/components/TableContract/index.mjs +2 -2
- package/components/TableGlide/TableGlide.d.ts +1 -1
- package/components/TableGlide/constants.d.ts +3 -3
- package/components/TableGlide/content-tokens.generated.d.ts +612 -0
- package/components/TableGlide/hooks/selection/index.cjs +1 -1
- package/components/TableGlide/hooks/selection/index.mjs +1 -1
- package/components/TableGlide/hooks/selection/useBaseHighlightRegions.d.ts +2 -1
- package/components/TableGlide/hooks/selection/useColoringLayers.d.ts +2 -3
- package/components/TableGlide/hooks/selection/useColumnRowHighlightRegions.d.ts +1 -4
- package/components/TableGlide/hooks/selection/useSelectionGeometry.d.ts +3 -1
- package/components/TableGlide/hooks/useErrorCellRanges.d.ts +1 -2
- package/components/TableGlide/index.cjs +1 -1
- package/components/TableGlide/index.mjs +31 -31
- package/components/TableGlide/lib/canvas/cells/buttons/index.cjs +1 -1
- package/components/TableGlide/lib/canvas/cells/buttons/index.mjs +4 -4
- 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 +13 -13
- package/components/TableGlide/lib/canvas/cells/renderer/index.cjs +1 -1
- package/components/TableGlide/lib/canvas/cells/renderer/index.mjs +4 -4
- 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 +34 -34
- 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/CanvasLink.d.ts +2 -2
- package/components/TableGlide/lib/canvas/primitives/CanvasText.d.ts +3 -1
- package/components/TableGlide/lib/canvas/primitives/index.cjs +1 -1
- package/components/TableGlide/lib/canvas/primitives/index.mjs +5 -5
- package/components/TableGlide/lib/canvas/utils/index.cjs +1 -1
- package/components/TableGlide/lib/canvas/utils/index.mjs +2 -2
- package/components/TableGlide/theming/activeTheme.type.d.ts +3 -1
- package/components/TableGlide/theming/cell-fill-override.d.ts +31 -0
- package/components/TableGlide/theming/custom-colors.d.ts +46 -11
- package/components/TableGlide/theming/fill-states.d.ts +19 -0
- package/components/TableGlide/theming/glide-colors.d.ts +14 -14
- 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/table-colors.generated.d.ts +529 -0
- package/components/TableGlide/tokens.d.ts +1 -104
- package/components/TableGlide/types.d.ts +3 -5
- package/components/TableTabs/index.cjs +1 -1
- package/components/TableTabs/index.mjs +1 -1
- package/components/Tooltip/index.cjs +1 -1
- package/components/Tooltip/index.mjs +1 -1
- package/components/TourWidget/index.cjs +3 -3
- package/components/TourWidget/index.mjs +14 -14
- package/components/Typography/index.cjs +1 -1
- package/components/Typography/index.mjs +1 -1
- package/components/Widget/index.cjs +1 -1
- package/components/Widget/index.mjs +2 -2
- package/formComponents/FormCombobox/index.cjs +1 -1
- package/formComponents/FormCombobox/index.mjs +1 -1
- package/formComponents/FormRadioGroupBox/index.cjs +1 -1
- package/formComponents/FormRadioGroupBox/index.mjs +1 -1
- package/formComponents/FormSegments/index.cjs +1 -1
- package/formComponents/FormSegments/index.mjs +1 -1
- package/formComponents/FormSwitch/index.cjs +1 -1
- package/formComponents/FormSwitch/index.mjs +1 -1
- package/index.cjs +1 -1
- package/index.d.ts +3 -1
- package/index.mjs +1864 -1859
- package/layouts/Container/index.cjs +1 -1
- package/layouts/Container/index.mjs +1 -1
- package/layouts/Container/lib/utils/index.cjs +1 -1
- package/layouts/Container/lib/utils/index.mjs +1 -1
- package/layouts/ErrorPage/index.cjs +1 -1
- package/layouts/ErrorPage/index.mjs +1 -1
- 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/layouts/Layout/index.cjs +1 -1
- package/layouts/Layout/index.mjs +1 -1
- package/layouts/PageLayout/index.cjs +1 -1
- package/layouts/PageLayout/index.mjs +1 -1
- package/mcp-data/component-index.json +1158 -206
- package/mixins/index.cjs +4 -4
- package/mixins/index.mjs +61 -54
- package/package.json +6 -6
- package/shared/utils/resizable/index.cjs +1 -0
- package/shared/utils/resizable/index.d.ts +2 -0
- package/shared/utils/resizable/index.mjs +39 -0
- package/shared/utils/resizable/resizableConfig.d.ts +16 -0
- package/styles/index.cjs +1 -1
- package/styles/index.mjs +1 -1
- package/types/index.d.ts +1 -0
- package/types/utility.d.ts +1 -0
- package/utils/breakpoint/index.cjs +1 -1
- package/utils/breakpoint/index.mjs +2 -2
- package/utils/clickStream/index.cjs +1 -1
- package/utils/clickStream/index.mjs +1 -1
- package/utils/eventBus/index.cjs +1 -1
- package/utils/eventBus/index.mjs +1 -1
- package/utils/getActiveTheme.d.ts +1 -1
- package/utils/hooks/index.cjs +1 -1
- package/utils/hooks/index.mjs +1 -1
- package/utils/index.cjs +1 -1
- package/utils/index.mjs +8 -8
- package/utils/react/index.cjs +1 -1
- package/utils/react/index.mjs +1 -1
- package/utils/styles/index.cjs +1 -1
- package/utils/styles/index.mjs +1 -1
- package/chunks/AnalyticalWidget-BtyWKJuu.mjs +0 -537
- package/chunks/AnalyticalWidget-YytE3Rlw.cjs +0 -43
- package/chunks/ApprovalCenter-DdsLEipZ.cjs +0 -1
- package/chunks/BlockTitle-DC1McGof.cjs +0 -1
- package/chunks/FiltersActions-Bg5wvHFG.cjs +0 -1
- package/chunks/MassActions-BTrj9l-R.cjs +0 -1
- package/chunks/PageTitle-CrBeieoq.cjs +0 -9
- package/chunks/Stories-UYVANawW.cjs +0 -1
- package/chunks/TableCanvas-qnwh4c5g.cjs +0 -30
- package/chunks/TableGlide-BLbbkn4C.mjs +0 -8154
- package/chunks/TableGlide-CZ2mkokV.cjs +0 -1
- package/components/TableCanvas/feature-right-sidebar/constants.d.ts +0 -1
- package/components/TableCanvas/feature-right-sidebar/ui/TableSidebar.d.ts +0 -16
- /package/components/TableCanvas/{feature-right-sidebar → feature-sidebar}/ui/TableSidebar.classnames.d.ts +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generatedAt": "2026-10-
|
|
3
|
-
"libVersion": "1.
|
|
2
|
+
"generatedAt": "2026-10-12T12:07:03.768Z",
|
|
3
|
+
"libVersion": "1.23.0",
|
|
4
4
|
"components": {
|
|
5
5
|
"Accordion": {
|
|
6
6
|
"name": "Accordion",
|
|
@@ -512,6 +512,464 @@
|
|
|
512
512
|
}
|
|
513
513
|
]
|
|
514
514
|
},
|
|
515
|
+
"AiAgentInput": {
|
|
516
|
+
"name": "AiAgentInput",
|
|
517
|
+
"group": "components",
|
|
518
|
+
"folderName": "AiAgentPopup",
|
|
519
|
+
"role": "primary",
|
|
520
|
+
"description": "Поле ввода AI-помощника: атомарный TextArea с овальным свечением позади\nи правым слотом под кнопки. Компонент намеренно простой: никакой логики\nотправки, очистки или смены кнопок в нём нет, всё это на стороне\nпотребителя.\n\n- свечение включается пропом glow и переключается в реальном времени;\n овал фиксированной высоты держится у верхней границы поля,\n при авторосте поднимается вместе с ней и лежит поверх контента\n чата (решение дизайнера), кликам не мешает;\n- rightSlot — произвольное содержимое правой части поля: кнопка\n отправки, кнопка остановки, с тултипами и любой логикой потребителя;\n- поле авторастёт до пиксельного предела maxHeight (по умолчанию 160),\n дальше внутренний скролл;\n- внешних отступов у компонента нет: место в лэйауте чата задаёт\n потребитель. Остальные пропсы уходят в TextArea, стили можно\n переопределить через className и style.",
|
|
521
|
+
"props": [
|
|
522
|
+
{
|
|
523
|
+
"name": "glow",
|
|
524
|
+
"type": "boolean | undefined",
|
|
525
|
+
"required": false,
|
|
526
|
+
"description": "Включить овальное свечение позади поля. Переключается в реальном\nвремени с плавным переходом: например, включать, пока AI-агент\nобдумывает ответ, и выключать, когда пользователь печатает.\nОвал фиксированной высоты держится у верхней границы поля,\nпри авторосте поднимается вместе с ней и лежит поверх контента\nчата, кликам не мешая.",
|
|
527
|
+
"default": "false"
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
"name": "maxHeight",
|
|
531
|
+
"type": "number | undefined",
|
|
532
|
+
"required": false,
|
|
533
|
+
"description": "Пиксельный предел высоты поля при авторосте (высота текстовой рамки\nцеликом, с её внутренними отступами), дальше внутренний скролл.\nПредел в px, а не в строках: при ресайзе окна количество\nпомещающихся строк меняется.",
|
|
534
|
+
"default": "DEFAULT_INPUT_MAX_HEIGHT"
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
"name": "rightSlot",
|
|
538
|
+
"type": "React.ReactElement<any, string | React.JSXElementConstructor<any>> | undefined",
|
|
539
|
+
"required": false,
|
|
540
|
+
"description": "Содержимое правой части поля: кнопка отправки, кнопка остановки\nи любые другие элементы с логикой и тултипами потребителя.\nАтомарный TextArea ждёт в этом месте один элемент; несколько кнопок\nоборачивайте в общий контейнер."
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
"name": "onChange",
|
|
544
|
+
"type": "React.ChangeEventHandler<HTMLTextAreaElement> | undefined",
|
|
545
|
+
"required": false,
|
|
546
|
+
"description": "Обработчик изменения элемента формы"
|
|
547
|
+
},
|
|
548
|
+
{
|
|
549
|
+
"name": "onClear",
|
|
550
|
+
"type": "(() => void) | undefined",
|
|
551
|
+
"required": false,
|
|
552
|
+
"description": "Callback при нажатии на кнопку очистки поля ввода."
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
"name": "appearance",
|
|
556
|
+
"type": "\"default\" | \"viewMode\" | undefined",
|
|
557
|
+
"required": false,
|
|
558
|
+
"description": ""
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
"name": "autoResize",
|
|
562
|
+
"type": "boolean | undefined",
|
|
563
|
+
"required": false,
|
|
564
|
+
"description": ""
|
|
565
|
+
},
|
|
566
|
+
{
|
|
567
|
+
"name": "clear",
|
|
568
|
+
"type": "true | undefined",
|
|
569
|
+
"required": false,
|
|
570
|
+
"description": ""
|
|
571
|
+
},
|
|
572
|
+
{
|
|
573
|
+
"name": "dirName",
|
|
574
|
+
"type": "string | undefined",
|
|
575
|
+
"required": false,
|
|
576
|
+
"description": ""
|
|
577
|
+
},
|
|
578
|
+
{
|
|
579
|
+
"name": "hasDivider",
|
|
580
|
+
"type": "boolean | undefined",
|
|
581
|
+
"required": false,
|
|
582
|
+
"description": ""
|
|
583
|
+
},
|
|
584
|
+
{
|
|
585
|
+
"name": "hasRequiredIndicator",
|
|
586
|
+
"type": "boolean | undefined",
|
|
587
|
+
"required": false,
|
|
588
|
+
"description": ""
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
"name": "headerSlot",
|
|
592
|
+
"type": "React.ReactNode",
|
|
593
|
+
"required": false,
|
|
594
|
+
"description": ""
|
|
595
|
+
},
|
|
596
|
+
{
|
|
597
|
+
"name": "helperText",
|
|
598
|
+
"type": "string | undefined",
|
|
599
|
+
"required": false,
|
|
600
|
+
"description": ""
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
"name": "hintContentLeft",
|
|
604
|
+
"type": "React.ReactNode",
|
|
605
|
+
"required": false,
|
|
606
|
+
"description": ""
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
"name": "hintHasArrow",
|
|
610
|
+
"type": "boolean | undefined",
|
|
611
|
+
"required": false,
|
|
612
|
+
"description": ""
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
"name": "hintOffset",
|
|
616
|
+
"type": "[number, number] | undefined",
|
|
617
|
+
"required": false,
|
|
618
|
+
"description": ""
|
|
619
|
+
},
|
|
620
|
+
{
|
|
621
|
+
"name": "hintOpened",
|
|
622
|
+
"type": "boolean | undefined",
|
|
623
|
+
"required": false,
|
|
624
|
+
"description": ""
|
|
625
|
+
},
|
|
626
|
+
{
|
|
627
|
+
"name": "hintPlacement",
|
|
628
|
+
"type": "Placement | ComputedPlacement[] | undefined",
|
|
629
|
+
"required": false,
|
|
630
|
+
"description": ""
|
|
631
|
+
},
|
|
632
|
+
{
|
|
633
|
+
"name": "hintSize",
|
|
634
|
+
"type": "\"s\" | \"m\" | undefined",
|
|
635
|
+
"required": false,
|
|
636
|
+
"description": ""
|
|
637
|
+
},
|
|
638
|
+
{
|
|
639
|
+
"name": "hintTargetIcon",
|
|
640
|
+
"type": "React.ReactNode",
|
|
641
|
+
"required": false,
|
|
642
|
+
"description": ""
|
|
643
|
+
},
|
|
644
|
+
{
|
|
645
|
+
"name": "hintText",
|
|
646
|
+
"type": "string | undefined",
|
|
647
|
+
"required": false,
|
|
648
|
+
"description": ""
|
|
649
|
+
},
|
|
650
|
+
{
|
|
651
|
+
"name": "hintTrigger",
|
|
652
|
+
"type": "\"hover\" | \"click\" | undefined",
|
|
653
|
+
"required": false,
|
|
654
|
+
"description": ""
|
|
655
|
+
},
|
|
656
|
+
{
|
|
657
|
+
"name": "hintView",
|
|
658
|
+
"type": "\"default\" | undefined",
|
|
659
|
+
"required": false,
|
|
660
|
+
"description": ""
|
|
661
|
+
},
|
|
662
|
+
{
|
|
663
|
+
"name": "hintWidth",
|
|
664
|
+
"type": "string | undefined",
|
|
665
|
+
"required": false,
|
|
666
|
+
"description": ""
|
|
667
|
+
},
|
|
668
|
+
{
|
|
669
|
+
"name": "labelAriaHidden",
|
|
670
|
+
"type": "boolean | undefined",
|
|
671
|
+
"required": false,
|
|
672
|
+
"description": ""
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
"name": "labelPlacement",
|
|
676
|
+
"type": "\"inner\" | \"outer\" | undefined",
|
|
677
|
+
"required": false,
|
|
678
|
+
"description": ""
|
|
679
|
+
},
|
|
680
|
+
{
|
|
681
|
+
"name": "leftHelper",
|
|
682
|
+
"type": "React.ReactNode",
|
|
683
|
+
"required": false,
|
|
684
|
+
"description": ""
|
|
685
|
+
},
|
|
686
|
+
{
|
|
687
|
+
"name": "leftHelperPlacement",
|
|
688
|
+
"type": "\"inner\" | \"outer\" | undefined",
|
|
689
|
+
"required": false,
|
|
690
|
+
"description": ""
|
|
691
|
+
},
|
|
692
|
+
{
|
|
693
|
+
"name": "maxAuto",
|
|
694
|
+
"type": "number | undefined",
|
|
695
|
+
"required": false,
|
|
696
|
+
"description": ""
|
|
697
|
+
},
|
|
698
|
+
{
|
|
699
|
+
"name": "minAuto",
|
|
700
|
+
"type": "number | undefined",
|
|
701
|
+
"required": false,
|
|
702
|
+
"description": ""
|
|
703
|
+
},
|
|
704
|
+
{
|
|
705
|
+
"name": "optional",
|
|
706
|
+
"type": "boolean | undefined",
|
|
707
|
+
"required": false,
|
|
708
|
+
"description": ""
|
|
709
|
+
},
|
|
710
|
+
{
|
|
711
|
+
"name": "optionalText",
|
|
712
|
+
"type": "string | undefined",
|
|
713
|
+
"required": false,
|
|
714
|
+
"description": ""
|
|
715
|
+
},
|
|
716
|
+
{
|
|
717
|
+
"name": "requiredPlacement",
|
|
718
|
+
"type": "\"left\" | \"right\" | undefined",
|
|
719
|
+
"required": false,
|
|
720
|
+
"description": ""
|
|
721
|
+
},
|
|
722
|
+
{
|
|
723
|
+
"name": "resize",
|
|
724
|
+
"type": "\"none\" | \"both\" | \"horizontal\" | \"vertical\" | undefined",
|
|
725
|
+
"required": false,
|
|
726
|
+
"description": ""
|
|
727
|
+
},
|
|
728
|
+
{
|
|
729
|
+
"name": "rightHelper",
|
|
730
|
+
"type": "React.ReactNode",
|
|
731
|
+
"required": false,
|
|
732
|
+
"description": ""
|
|
733
|
+
},
|
|
734
|
+
{
|
|
735
|
+
"name": "rightHelperPlacement",
|
|
736
|
+
"type": "\"inner\" | \"outer\" | undefined",
|
|
737
|
+
"required": false,
|
|
738
|
+
"description": ""
|
|
739
|
+
},
|
|
740
|
+
{
|
|
741
|
+
"name": "size",
|
|
742
|
+
"type": "\"s\" | undefined",
|
|
743
|
+
"required": false,
|
|
744
|
+
"description": ""
|
|
745
|
+
},
|
|
746
|
+
{
|
|
747
|
+
"name": "status",
|
|
748
|
+
"type": "\"\" | \"warning\" | \"success\" | \"error\" | undefined",
|
|
749
|
+
"required": false,
|
|
750
|
+
"description": ""
|
|
751
|
+
},
|
|
752
|
+
{
|
|
753
|
+
"name": "titleCaption",
|
|
754
|
+
"type": "React.ReactNode",
|
|
755
|
+
"required": false,
|
|
756
|
+
"description": ""
|
|
757
|
+
},
|
|
758
|
+
{
|
|
759
|
+
"name": "view",
|
|
760
|
+
"type": "\"default\" | \"positive\" | \"warning\" | \"negative\" | \"edited\" | undefined",
|
|
761
|
+
"required": false,
|
|
762
|
+
"description": ""
|
|
763
|
+
}
|
|
764
|
+
],
|
|
765
|
+
"propsTypeName": "AiAgentInputProps",
|
|
766
|
+
"sourceFile": "packages/ui-kit/src/components/AiAgentPopup/AiAgentInput.tsx",
|
|
767
|
+
"type": "composition",
|
|
768
|
+
"atomicMcpVersion": "0.360.0",
|
|
769
|
+
"importPath": "@daisforge/ui",
|
|
770
|
+
"importStatement": "import { AiAgentInput } from '@daisforge/ui';",
|
|
771
|
+
"minimalUsage": "<AiAgentInput />",
|
|
772
|
+
"examples": [
|
|
773
|
+
{
|
|
774
|
+
"exportName": "Usage",
|
|
775
|
+
"displayName": "Использование в AiAgentPopup.stories.tsx",
|
|
776
|
+
"type": "usage",
|
|
777
|
+
"code": "<AiAgentInput\n glow={glow}\n placeholder=\"Спросите что-нибудь\"\n value={draft}\n onChange={(e) => onDraftChange(e.target.value)}\n rightSlot={\n <IconButton size=\"xs\" view=\"clear\" onClick={onSend}>\n {/* плазма-иконки умеют градиент в color: рисуют её маской */}\n <IconSendOutline size=\"s\" color={textAccentGradient} />\n </IconButton>\n }\n />",
|
|
778
|
+
"sourceFile": "packages/storybook/src/stories/AiAgentPopup/AiAgentPopup.stories.tsx"
|
|
779
|
+
}
|
|
780
|
+
]
|
|
781
|
+
},
|
|
782
|
+
"AiAgentPopup": {
|
|
783
|
+
"name": "AiAgentPopup",
|
|
784
|
+
"group": "components",
|
|
785
|
+
"folderName": "AiAgentPopup",
|
|
786
|
+
"role": "primary",
|
|
787
|
+
"description": "Окно AI-помощника с градиентной рамкой: перетаскивание, ресайз с адаптивным углом, сохранение позиции и размера в localStorage, опциональная левая панель с иконками-разделами. В комплекте AiAgentInput (поле ввода чата со свечением)",
|
|
788
|
+
"props": [
|
|
789
|
+
{
|
|
790
|
+
"name": "defaultPosition",
|
|
791
|
+
"type": "AiAgentPopupPosition | undefined",
|
|
792
|
+
"required": false,
|
|
793
|
+
"description": "Начальная позиция окна. Приоритетнее targetRef, но уступает сохранённой\nпозиции из useStorage."
|
|
794
|
+
},
|
|
795
|
+
{
|
|
796
|
+
"name": "defaultSize",
|
|
797
|
+
"type": "AiAgentPopupSize | undefined",
|
|
798
|
+
"required": false,
|
|
799
|
+
"description": "Начальный размер окна в px. Сохранённый размер из useStorage\nприоритетнее.",
|
|
800
|
+
"default": "{ width: 400, height: 540 }"
|
|
801
|
+
},
|
|
802
|
+
{
|
|
803
|
+
"name": "dragBoundary",
|
|
804
|
+
"type": "AiAgentPopupDragBoundary | undefined",
|
|
805
|
+
"required": false,
|
|
806
|
+
"description": "Ограничение области перетаскивания: отступы от границ вьюпорта.\nУчитывается и при ресайзе: окно нельзя растянуть за границы области."
|
|
807
|
+
},
|
|
808
|
+
{
|
|
809
|
+
"name": "draggable",
|
|
810
|
+
"type": "boolean | undefined",
|
|
811
|
+
"required": false,
|
|
812
|
+
"description": "Включить / выключить перетаскивание. Окно тянется за любое место\nконтейнера, кроме интерактивных элементов и зон из dragIgnoreSelector.",
|
|
813
|
+
"default": "true"
|
|
814
|
+
},
|
|
815
|
+
{
|
|
816
|
+
"name": "dragIgnoreSelector",
|
|
817
|
+
"type": "string | undefined",
|
|
818
|
+
"required": false,
|
|
819
|
+
"description": "Дополнительный CSS-селектор элементов, с которых перетаскивание не\nначинается (например, область сообщений чата, чтобы работало выделение\nтекста). То же самое можно сделать атрибутом data-no-drag на элементе."
|
|
820
|
+
},
|
|
821
|
+
{
|
|
822
|
+
"name": "frame",
|
|
823
|
+
"type": "string | React.RefObject<HTMLElement | null> | undefined",
|
|
824
|
+
"required": false,
|
|
825
|
+
"description": "В каком контейнере позиционируется (по умолчанию document), можно также указать id элемента или ref для него.\nКонтейнер, в котором живёт окно. По умолчанию document: окно поверх\nвсей страницы, это целевой сценарий использования. Если передать\nэлемент, окно рендерится, перетаскивается и ресайзится в его рамках;\nв продуктовом коде это обычно не нужно, вариант используется в стори\nдля изоляции примеров друг от друга."
|
|
826
|
+
},
|
|
827
|
+
{
|
|
828
|
+
"name": "leftPanel",
|
|
829
|
+
"type": "AiAgentLeftPanelProps | undefined",
|
|
830
|
+
"required": false,
|
|
831
|
+
"description": "Левая панель с иконками-разделами внутри окна. Открытие раздела\nрасширяет окно (в пределах максимума), закрытие возвращает прежнюю\nширину. Если не задана, окно только с контентом."
|
|
832
|
+
},
|
|
833
|
+
{
|
|
834
|
+
"name": "onPositionChange",
|
|
835
|
+
"type": "((position: AiAgentPopupPosition) => void) | undefined",
|
|
836
|
+
"required": false,
|
|
837
|
+
"description": "Callback смены позиции при перетаскивании."
|
|
838
|
+
},
|
|
839
|
+
{
|
|
840
|
+
"name": "onSizeChange",
|
|
841
|
+
"type": "((size: AiAgentPopupSize) => void) | undefined",
|
|
842
|
+
"required": false,
|
|
843
|
+
"description": "Callback смены размера по окончании ресайза."
|
|
844
|
+
},
|
|
845
|
+
{
|
|
846
|
+
"name": "positionState",
|
|
847
|
+
"type": "AiAgentPopupPositionState | undefined",
|
|
848
|
+
"required": false,
|
|
849
|
+
"description": "Внешний стейт позиции [position, setPosition] для полного управления\nснаружи. Если передан, useStorage позицию не сохраняет."
|
|
850
|
+
},
|
|
851
|
+
{
|
|
852
|
+
"name": "resizable",
|
|
853
|
+
"type": "boolean | Partial<{ disabled?: boolean | undefined; directions?: ResizeDirections | undefined; defaultSize?: { width?: number | undefined; height?: number | undefined; } | undefined; minWidth?: number | undefined; minHeight?: number | undefined; maxWidth?: number | undefined; maxHeight?: number | undefined; icons?: { topRight?: React.ReactNode; bottomRight?: React.ReactNode; bottomLeft?: React.Rea…",
|
|
854
|
+
"required": false,
|
|
855
|
+
"description": "Включить / настроить resizable-режим.\n- `true`: ресайз за правый нижний угол с дефолтной иконкой.\n- объект: частичная конфигурация, мержится с дефолтной.",
|
|
856
|
+
"default": "true"
|
|
857
|
+
},
|
|
858
|
+
{
|
|
859
|
+
"name": "targetGap",
|
|
860
|
+
"type": "AiAgentPopupTargetGap | undefined",
|
|
861
|
+
"required": false,
|
|
862
|
+
"description": "Отступ окна от targetRef в px. Число: только по горизонтали.\nОбъект { x, y }: смещение по обеим осям от правого верхнего угла\nтаргета, y больше нуля опускает окно вниз, меньше нуля поднимает.",
|
|
863
|
+
"default": "12"
|
|
864
|
+
},
|
|
865
|
+
{
|
|
866
|
+
"name": "targetRef",
|
|
867
|
+
"type": "React.RefObject<HTMLElement | null> | undefined",
|
|
868
|
+
"required": false,
|
|
869
|
+
"description": "Ref на элемент, рядом с которым откроется окно (справа от него).\nИспользуется, только если позиция ещё не известна: не передан\ndefaultPosition и нет сохранённой позиции из useStorage."
|
|
870
|
+
},
|
|
871
|
+
{
|
|
872
|
+
"name": "useStorage",
|
|
873
|
+
"type": "string | boolean | undefined",
|
|
874
|
+
"required": false,
|
|
875
|
+
"description": "Сохранять ли позицию и размер окна в localStorage.\n- `true`: автосохранение с ключом `ai-agent-popup-state`.\n- `string`: кастомный ключ.\n- `false`: отключено.",
|
|
876
|
+
"default": "false"
|
|
877
|
+
},
|
|
878
|
+
{
|
|
879
|
+
"name": "opened",
|
|
880
|
+
"type": "boolean | undefined",
|
|
881
|
+
"required": false,
|
|
882
|
+
"description": "Отображение Popup."
|
|
883
|
+
},
|
|
884
|
+
{
|
|
885
|
+
"name": "overlay",
|
|
886
|
+
"type": "React.ReactNode",
|
|
887
|
+
"required": false,
|
|
888
|
+
"description": "Соседний элемент для окна в портале."
|
|
889
|
+
},
|
|
890
|
+
{
|
|
891
|
+
"name": "popupInfo",
|
|
892
|
+
"type": "PopupInfo | undefined",
|
|
893
|
+
"required": false,
|
|
894
|
+
"description": "Дополнительная информация для программного взаимодействия с окном через контекст."
|
|
895
|
+
},
|
|
896
|
+
{
|
|
897
|
+
"name": "positionFixed",
|
|
898
|
+
"type": "boolean | undefined",
|
|
899
|
+
"required": false,
|
|
900
|
+
"description": "Если `frame` отличается от `document` применяет `position='fixed'`",
|
|
901
|
+
"default": "false"
|
|
902
|
+
},
|
|
903
|
+
{
|
|
904
|
+
"name": "withAnimation",
|
|
905
|
+
"type": "boolean | undefined",
|
|
906
|
+
"required": false,
|
|
907
|
+
"description": "Использовать ли анимацию."
|
|
908
|
+
},
|
|
909
|
+
{
|
|
910
|
+
"name": "zIndex",
|
|
911
|
+
"type": "string | undefined",
|
|
912
|
+
"required": false,
|
|
913
|
+
"description": "Значение z-index для Popup."
|
|
914
|
+
}
|
|
915
|
+
],
|
|
916
|
+
"propsTypeName": "AiAgentPopupProps",
|
|
917
|
+
"sourceFile": "packages/ui-kit/src/components/AiAgentPopup/AiAgentPopup.tsx",
|
|
918
|
+
"type": "wrapper",
|
|
919
|
+
"category": "Локальные компоненты",
|
|
920
|
+
"hint": "Не путать с AiAgentPopover (старая плавающая кнопка с поповером) — AiAgentPopup отдельное окно под новый дизайн. Наполнение окна на стороне потребителя.",
|
|
921
|
+
"keywords": [
|
|
922
|
+
"ai-помощник",
|
|
923
|
+
"окно чата",
|
|
924
|
+
"draggable popup",
|
|
925
|
+
"перетаскиваемое окно",
|
|
926
|
+
"свечение поля ввода",
|
|
927
|
+
"левая панель с разделами"
|
|
928
|
+
],
|
|
929
|
+
"scope": "internal",
|
|
930
|
+
"docs": "# AiAgentPopup\n\n`AiAgentPopup` — окно AI-помощника, локальная DF-обёртка над\n[Popup](https://plasma.sberdevices.ru/sdds-finai/components/popup/).\nКомпонент даёт готовый контейнер с перетаскиванием, ресайзом и сохранением\nположения; всё наполнение окна (шапка, чат, поле ввода) — на стороне\nпотребителя.\n\n## Ключевые особенности\n\n- окно можно перетаскивать за любое свободное место контейнера;\n область перетаскивания ограничена экраном с учётом `dragBoundary`\n- ресайз с адаптивным углом: иконка сама встаёт в тот угол окна,\n где есть место расти\n- позиция при открытии, по убыванию приоритета: сохранённая в localStorage\n (`useStorage`), затем `defaultPosition`, затем справа от `targetRef`\n с отступом `targetGap`, иначе отступ от левого верхнего угла экрана\n- `targetGap` числом задаёт отступ только по горизонтали (верх окна\n и верх таргета на одном уровне), а объектом `{ x, y }` — смещение\n по обеим осям от правого верхнего угла таргета: `y` больше нуля\n опускает окно, меньше нуля поднимает\n- `useStorage` сохраняет позицию и размер окна: после закрытия и даже\n перезагрузки страницы окно открывается там же и того же размера\n- поле ввода чата с овальным свечением позади даёт компонент\n `AiAgentInput`: свечение включается его пропом `glow` и переключается\n в реальном времени (например, пока AI-агент обдумывает ответ)\n- слева в окне можно показать полосу иконок-разделов (проп `leftPanel`)\n- тема подхватывается автоматически, настраивать её снаружи не нужно\n- существующий `AiAgentPopover` (плавающая кнопка с поповером) остаётся\n как есть, `AiAgentPopup` — отдельный компонент под новый дизайн\n\n## Особенности\n\n- перетаскивание не начинается с интерактивных элементов (кнопки, ссылки,\n поля ввода), с зон с атрибутом `data-no-drag` и с зон под селектором\n `dragIgnoreSelector`; пометьте `data-no-drag` область сообщений чата,\n чтобы в ней работало выделение текста\n- смещения меньше 5px считаются кликом, а не перетаскиванием\n- активный угол ресайза вычисляется по положению окна: экран делится\n на шесть секторов, окно в верхней половине растёт вниз, в нижней вверх,\n в левой части вправо, в правой влево; при ресайзе за верхние и левые\n углы противоположный угол окна стоит на месте\n- окно нельзя растянуть за края экрана, пределы учитывают `dragBoundary`;\n минимальный размер по умолчанию 360x360, максимальный 800x800\n- при первом открытии окно 400x540, другой стартовый размер задаётся\n через `defaultSize`\n- конфигурация ресайза настраивается через `resizable` частично:\n не заданные поля компонент заполняет своими значениями;\n `resizable={false}` выключает ресайз\n- для полного управления позицией снаружи есть `positionState` — пара\n `[position, setPosition]`, как у `useState`; в этом режиме позиция\n в localStorage не сохраняется\n- сохранённая позиция при чтении зажимается в границы текущего экрана,\n при изменении размеров окна браузера окно возвращается в видимую область\n- проп `frame` (унаследован от атомарного `Popup`) ограничивает окно\n рамками переданного контейнера: позиция, перетаскивание и ресайз\n считаются внутри него. В продуктовом коде обычно не нужен, окно живёт\n поверх всей страницы; используется в наших стори для изоляции примеров\n друг от друга\n\n## Поле ввода AiAgentInput\n\nПоле ввода чата с овальным свечением позади — отдельный простой компонент.\nЛогики отправки, очистки и смены кнопок в нём нет, всё это на стороне\nпотребителя.\n\n- свечение включается пропом `glow` и переключается в реальном времени\n с плавным переходом; рисуется линейным градиентом и размытием\n из макета, у тёмных тем свой градиент\n- свечение — овал высотой 79px (по макету), он выступает над верхним\n краем поля на 25px, остальная часть лежит за полем; когда поле растёт\n (Shift+Enter), овал поднимается вместе с верхним краем поля, а при\n ресайзе окна у овала меняется только ширина\n- свечение лежит поверх контента чата, включая сообщения с фоном\n (решение дизайнера); кликам и выделению текста оно не мешает\n- `rightSlot` — произвольная правая часть поля: кнопка отправки, кнопка\n остановки, с тултипами и любой логикой потребителя\n- поле авторастёт до пиксельного предела `maxHeight` (по умолчанию 220),\n дальше внутренний скролл; предел в px, а не в строках, потому что\n при ресайзе окна количество помещающихся строк меняется\n- лимита на число символов у компонента нет; если он нужен (по гайду\n дизайна 324 символа), передайте `maxLength`, он уйдёт в поле как есть\n- внешних отступов у компонента нет: место в лэйауте чата задаёт\n потребитель; стили переопределяются через `className` и `style`\n\n## Левая панель\n\nПроп `leftPanel` добавляет внутри окна слева узкую полосу иконок-разделов.\nКлик по иконке раскрывает раздел фиксированной ширины: он показывается\nвместо полосы (полоса и раздел сменяют друг друга плавно), а вернуться\nк другим иконкам можно только крестиком в шапке раздела.\n\n- разделы задаются массивом `items`: у каждого `key`, `icon` (в полосе),\n `title` и `content` (в раскрытом разделе); иконку шапки раздела можно\n задать отдельно через `titleIcon`\n- шапку раздела (иконка, заголовок, крестик) и её высоту компонент рисует\n сам; отступы, скролл и наполнение раздела под шапкой — на потребителе\n- открытый раздел задаётся `activeKey` (управляемо) или `defaultActiveKey`\n (начальное значение); смена приходит в `onActiveKeyChange` — ключ\n раздела при клике по иконке, `null` при закрытии крестиком\n- пока раздел открыт, минимальная ширина окна при ресайзе больше, чтобы\n чат не схлопнулся; максимальный размер окна 800x800\n- окно пока не расширяется автоматически при открытии раздела (для этого\n нужен управляемый размер окна от атомарного `Popup`, его ещё нет),\n поэтому задавайте `defaultSize` с запасом под ширину раздела\n\n## Внутреннее состояние контента\n\n- перетаскивание, ресайз, смена активного угла и смена темы контент\n не перемонтируют, внутреннее состояние живёт\n- закрытие окна (`opened={false}`) полностью убирает содержимое из DOM,\n это поведение атомарного `Popup`; локальный стейт контента при этом\n теряется\n- поэтому состояние чата (переписку, черновик ввода) держите снаружи\n окна: в сторе или поднятым стейтом, который живёт независимо от\n `opened`\n\nОписание типов — в разделе\n[API](?path=/docs/локальные-компоненты-aiagentpopup-api--docs).",
|
|
931
|
+
"apiDocs": "# AiAgentPopup API\n\n## AiAgentPopupProps\n\n```typescript\ntype AiAgentPopupProps = Omit<\n PopupProps,\n 'children' | 'isOpen' | 'placement' | 'offset' | 'draggable' | 'resizable'\n> & {\n /**\n * Контейнер, в котором живёт окно. По умолчанию document: окно поверх\n * всей страницы, это целевой сценарий использования. Если передать\n * элемент, окно рендерится, перетаскивается и ресайзится в его рамках;\n * в продуктовом коде это обычно не нужно, вариант используется в стори\n * для изоляции примеров друг от друга.\n */\n frame?: AiAgentPopupFrame;\n /**\n * Содержимое окна. Компонент задаёт только контейнер (обводка, тень,\n * скругление, внутренние отступы), всё наполнение на стороне потребителя.\n */\n children?: ReactNode;\n /**\n * Левая панель с иконками-разделами внутри окна. Открытие раздела\n * расширяет окно (в пределах максимума), закрытие возвращает прежнюю\n * ширину. Если не задана, окно только с контентом.\n */\n leftPanel?: AiAgentLeftPanelProps;\n /**\n * Ref на элемент, рядом с которым откроется окно (справа от него).\n * Используется, только если позиция ещё не известна: не передан\n * defaultPosition и нет сохранённой позиции из useStorage.\n */\n targetRef?: RefObject<HTMLElement | null>;\n /**\n * Отступ окна от targetRef в px. Число: только по горизонтали.\n * Объект { x, y }: смещение по обеим осям от правого верхнего угла\n * таргета, y больше нуля опускает окно вниз, меньше нуля поднимает.\n * @default 12\n */\n targetGap?: AiAgentPopupTargetGap;\n /**\n * Начальная позиция окна. Приоритетнее targetRef, но уступает сохранённой\n * позиции из useStorage.\n */\n defaultPosition?: AiAgentPopupPosition;\n /**\n * Внешний стейт позиции [position, setPosition] для полного управления\n * снаружи. Если передан, useStorage позицию не сохраняет.\n */\n positionState?: AiAgentPopupPositionState;\n /**\n * Callback смены позиции при перетаскивании.\n */\n onPositionChange?: (position: AiAgentPopupPosition) => void;\n /**\n * Включить / выключить перетаскивание. Окно тянется за любое место\n * контейнера, кроме интерактивных элементов и зон из dragIgnoreSelector.\n * @default true\n */\n draggable?: boolean;\n /**\n * Ограничение области перетаскивания: отступы от границ вьюпорта.\n * Учитывается и при ресайзе: окно нельзя растянуть за границы области.\n */\n dragBoundary?: AiAgentPopupDragBoundary;\n /**\n * Дополнительный CSS-селектор элементов, с которых перетаскивание не\n * начинается (например, область сообщений чата, чтобы работало выделение\n * текста). То же самое можно сделать атрибутом data-no-drag на элементе.\n */\n dragIgnoreSelector?: string;\n /**\n * Сохранять ли позицию и размер окна в localStorage.\n * - `true`: автосохранение с ключом `ai-agent-popup-state`.\n * - `string`: кастомный ключ.\n * - `false`: отключено.\n * @default false\n */\n useStorage?: boolean | string;\n /**\n * Включить / настроить resizable-режим.\n * - `true`: ресайз за правый нижний угол с дефолтной иконкой.\n * - объект: частичная конфигурация, мержится с дефолтной.\n * @default true\n */\n resizable?: boolean | Partial<AiAgentPopupResizableConfig>;\n /**\n * Начальный размер окна в px. Сохранённый размер из useStorage\n * приоритетнее.\n * @default { width: 400, height: 540 }\n */\n defaultSize?: AiAgentPopupSize;\n /**\n * Callback смены размера по окончании ресайза.\n */\n onSizeChange?: (size: AiAgentPopupSize) => void;\n};\n```\n\n> `AiAgentPopup` наследует базовые пропсы `Popup` из `sdds-finai`, кроме `placement`,\n`offset`, `draggable` и `resizable`: позицией и ресайзом компонент управляет сам\nчерез собственные пропсы.\n\n## AiAgentPopupPosition\n\n```typescript\ntype AiAgentPopupPosition = { x: number; y: number };\n```\n\n> Координаты левого верхнего угла окна относительно экрана, в px.\n\n## AiAgentPopupPositionState\n\n```typescript\ntype AiAgentPopupPositionState = [\n AiAgentPopupPosition,\n Dispatch<SetStateAction<AiAgentPopupPosition>>,\n];\n```\n\n> Пара для полного внешнего управления позицией, как у `useState`. Если передана\nв `positionState`, компонент не хранит позицию сам и не сохраняет её в localStorage.\n\n## AiAgentPopupTargetGap\n\n```typescript\ntype AiAgentPopupTargetGap = number | { x?: number; y?: number };\n```\n\n> Отступ окна от `targetRef`. Число задаёт отступ только по горизонтали, объект с\nполями `x` и `y` — смещение по обеим осям от правого верхнего угла таргета: `y` больше\nнуля опускает окно, меньше нуля поднимает.\n\n## AiAgentPopupSize\n\n```typescript\ntype AiAgentPopupSize = { width: number; height: number };\n```\n\n## AiAgentPopupDragBoundary\n\n```typescript\ntype AiAgentPopupDragBoundary = {\n top?: number;\n right?: number;\n bottom?: number;\n left?: number;\n};\n```\n\n> Отступы от краёв экрана. Учитываются при перетаскивании, при ресайзе и при вычислении\nначальной позиции.\n\n## AiAgentPopupResizableConfig\n\n```typescript\ntype AiAgentPopupResizableConfig = Exclude<\n PopupProps['resizable'],\n boolean | undefined\n>;\n```\n\n> Конфигурация ресайза атомарного `Popup`. В `resizable` можно передать её частично:\nне заданные поля компонент заполняет своими значениями (активный угол по положению\nокна, DF-иконка, минимум 360x360, пределы по краям экрана).\n\n## AiAgentInputProps\n\n```typescript\ntype AiAgentInputProps = Omit<TextAreaProps, 'contentRight'> & {\n /**\n * Включить овальное свечение позади поля. Переключается в реальном\n * времени с плавным переходом: например, включать, пока AI-агент\n * обдумывает ответ, и выключать, когда пользователь печатает.\n * Овал фиксированной высоты держится у верхней границы поля,\n * при авторосте поднимается вместе с ней и лежит поверх контента\n * чата, кликам не мешая.\n * @default false\n */\n glow?: boolean;\n /**\n * Содержимое правой части поля: кнопка отправки, кнопка остановки\n * и любые другие элементы с логикой и тултипами потребителя.\n * Атомарный TextArea ждёт в этом месте один элемент; несколько кнопок\n * оборачивайте в общий контейнер.\n */\n rightSlot?: ReactElement;\n /**\n * Пиксельный предел высоты поля при авторосте (высота текстовой рамки\n * целиком, с её внутренними отступами), дальше внутренний скролл.\n * Предел в px, а не в строках: при ресайзе окна количество\n * помещающихся строк меняется.\n * @default 220\n */\n maxHeight?: number;\n};\n```\n\n> Поле ввода чата с овальным свечением позади. Наследует пропсы `TextArea`, кроме\n`contentRight`: правая часть поля задаётся через `rightSlot`.\n\n## AiAgentLeftPanelProps\n\n```typescript\ntype AiAgentLeftPanelProps = {\n /**\n * Разделы панели: иконки в полосе и их контент.\n */\n items: AiAgentLeftPanelItem[];\n /**\n * Ключ открытого раздела. null или undefined — открыта полоса иконок,\n * раздел закрыт. Управляемый режим: значение задаёт потребитель.\n */\n activeKey?: string | null;\n /**\n * Начальный открытый раздел в неуправляемом режиме (когда activeKey\n * не передан).\n */\n defaultActiveKey?: string | null;\n /**\n * Смена открытого раздела: ключ раздела при клике по иконке, null\n * при закрытии крестиком.\n */\n onActiveKeyChange?: (key: string | null) => void;\n};\n```\n\n> Левая панель окна: полоса иконок-разделов. Открытый раздел задаётся `activeKey`\n(управляемо) или `defaultActiveKey`; смена приходит в `onActiveKeyChange` (ключ раздела\nили `null` при закрытии).\n\n## AiAgentLeftPanelItem\n\n```typescript\ntype AiAgentLeftPanelItem = {\n /**\n * Уникальный ключ раздела: по нему определяется открытый раздел\n * (activeKey) и приходит смена в onActiveKeyChange.\n */\n key: string;\n /**\n * Иконка в полосе (свёрнутое состояние левой панели).\n */\n icon: ReactNode;\n /**\n * Иконка слева в шапке открытого раздела, компонент ставит её по центру\n * квадрата 40x40. Если не задана, берётся icon.\n */\n titleIcon?: ReactNode;\n /**\n * Заголовок открытого раздела (в шапке, рядом с иконкой и крестиком).\n */\n title: ReactNode;\n /**\n * Контент открытого раздела под шапкой. Отступы, скролл и наполнение\n * полностью на стороне потребителя.\n */\n content: ReactNode;\n};\n```\n\n> Один раздел левой панели: `icon` в полосе, `title` и `content` в раскрытом разделе.\nШапку с иконкой, заголовком и крестиком компонент рисует сам; наполнение раздела\nпод шапкой задаёт потребитель.",
|
|
932
|
+
"curatedStories": [
|
|
933
|
+
{
|
|
934
|
+
"exportName": "Simple",
|
|
935
|
+
"displayName": "Simple",
|
|
936
|
+
"type": "full-code",
|
|
937
|
+
"code": "import { useLayoutEffect, useRef, useState } from 'react';\nimport {\n AiAgentInput,\n AiAgentPopup,\n IconButton,\n PopupProvider,\n SSRProvider,\n surfaceAccentMinor,\n surfaceTransparentSecondary,\n textAccentGradient,\n textInfo,\n textPrimary,\n Typography,\n} from '@daisforge/ui';\nimport {\n IconCalendarEventOutline,\n IconCatalogOutline,\n IconClose,\n IconDoneCircleOutline,\n IconHistory,\n IconMessageAddOutline,\n IconSearchAIOutline,\n IconSendOutline,\n} from '@daisforge/ui/icons';\n\n// Весь контент окна на стороне потребителя, ниже один из вариантов сборки.\n// Состояние чата и открытый раздел левой панели держим снаружи окна:\n// закрытие окна размонтирует контент, а состояние снаружи это переживает.\n\n// Левый сайдбар страницы с кнопкой AI-помощника: окно откроется справа\n// от неё, targetRef висит на обёртке кнопки\nconst sidebarStyle = {\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '8px',\n background: surfaceTransparentSecondary,\n};\n\nfunction Sidebar({ sidebarRef, targetRef, onToggle }) {\n return (\n <div ref={sidebarRef} style={sidebarStyle}>\n <span ref={targetRef}>\n <IconButton size=\"s\" view=\"clear\" onClick={onToggle}>\n <IconCatalogOutline size=\"s\" />\n </IconButton>\n </span>\n </div>\n );\n}\n\n// Левая граница перетаскивания равна ширине сайдбара: окно не заезжает\n// на него. Ширину следим наблюдателем, а не одним замером\nfunction useSidebarWidth(ref) {\n const [width, setWidth] = useState(0);\n useLayoutEffect(() => {\n const node = ref.current;\n if (!node) return undefined;\n const update = () => setWidth(node.offsetWidth);\n update();\n const observer = new ResizeObserver(update);\n observer.observe(node);\n return () => observer.disconnect();\n }, [ref]);\n return width;\n}\n\nconst chatHeaderStyle = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n};\n\n// Иконка у заголовка не кликается, но стоит в том же квадрате 40x40,\n// что и кнопки шапки\nconst chatTitleIconStyle = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '40px',\n height: '40px',\n};\n\nconst chatMessagesStyle = {\n flex: '1 1 auto',\n minHeight: 0,\n overflow: 'auto',\n display: 'flex',\n flexDirection: 'column',\n gap: '8px',\n marginTop: '12px',\n};\n\nconst chatBubbleStyle = {\n background: surfaceAccentMinor,\n borderRadius: '8px',\n padding: '10px 12px',\n color: textPrimary,\n};\n\n// Сообщение от системы: без фона, свечение ложится прямо под текст\nconst systemMessageStyle = {\n padding: '0 12px',\n color: textInfo,\n};\n\n// Кнопки не начинают перетаскивание, по ним работают обычные клики\nfunction ChatHeader({ onClose }) {\n return (\n <div style={chatHeaderStyle}>\n <div style={{ display: 'flex', alignItems: 'center' }}>\n <span style={chatTitleIconStyle}>\n <IconSearchAIOutline size=\"s\" color={textAccentGradient} />\n </span>\n <Typography variant=\"BodyM\" bold>\n AI-Chat\n </Typography>\n </div>\n <div style={{ display: 'flex', alignItems: 'center' }}>\n <IconButton size=\"s\" view=\"clear\">\n <IconMessageAddOutline size=\"s\" />\n </IconButton>\n <IconButton size=\"s\" view=\"clear\" onClick={onClose}>\n <IconClose size=\"s\" />\n </IconButton>\n </div>\n </div>\n );\n}\n\nfunction ChatContent({\n messages,\n draft,\n onDraftChange,\n onSend,\n onClose,\n}) {\n return (\n <>\n <ChatHeader onClose={onClose} />\n <div style={chatMessagesStyle}>\n {messages.map((message, index) => (\n <Typography\n key={index}\n variant=\"BodyS\"\n style={message.system ? systemMessageStyle : chatBubbleStyle}\n data-no-drag\n >\n {message.text}\n </Typography>\n ))}\n </div>\n {/* Отступов вокруг AiAgentInput нет: по дизайну поле прижато\n к ленте сообщений */}\n <AiAgentInput\n glow\n placeholder=\"Спросите что-нибудь\"\n value={draft}\n onChange={(e) => onDraftChange(e.target.value)}\n rightSlot={\n <IconButton size=\"xs\" view=\"clear\" onClick={onSend}>\n {/* плазма-иконки умеют градиент в color: рисуют её маской */}\n <IconSendOutline size=\"s\" color={textAccentGradient} />\n </IconButton>\n }\n />\n </>\n );\n}\n\nconst sectionBodyStyle = {\n display: 'flex',\n flexDirection: 'column',\n gap: '8px',\n padding: '12px',\n height: '100%',\n overflow: 'auto',\n};\n\n\n// Разделы левой панели окна: иконка в полосе, заголовок и контент раздела\nconst leftPanelItems = [\n {\n key: 'history',\n icon: <IconHistory size=\"s\" />,\n title: 'История',\n content: (\n <div style={sectionBodyStyle}>\n <Typography variant=\"BodyS\">Вчера: вопросы по таблицам</Typography>\n <Typography variant=\"BodyS\">2 дня назад: настройка форм</Typography>\n </div>\n ),\n },\n {\n key: 'tasks',\n icon: <IconDoneCircleOutline size=\"s\" />,\n title: 'Задачи',\n content: (\n <div style={sectionBodyStyle}>\n <Typography variant=\"BodyS\">Проверить отчёт</Typography>\n </div>\n ),\n },\n {\n key: 'calendar',\n icon: <IconCalendarEventOutline size=\"s\" />,\n title: 'Календарь',\n content: (\n <div style={sectionBodyStyle}>\n <Typography variant=\"BodyS\">Сегодня: созвон в 15:00</Typography>\n </div>\n ),\n },\n];${exampleBody("
|
|
938
|
+
},
|
|
939
|
+
{
|
|
940
|
+
"exportName": "Playground",
|
|
941
|
+
"displayName": "Playground",
|
|
942
|
+
"type": "full-code",
|
|
943
|
+
"code": "import { useLayoutEffect, useRef, useState } from 'react';\nimport {\n AiAgentInput,\n AiAgentPopup,\n IconButton,\n PopupProvider,\n SSRProvider,\n surfaceAccentMinor,\n surfaceTransparentSecondary,\n textAccentGradient,\n textInfo,\n textPrimary,\n Typography,\n} from '@daisforge/ui';\nimport {\n IconCalendarEventOutline,\n IconCatalogOutline,\n IconClose,\n IconDoneCircleOutline,\n IconHistory,\n IconMessageAddOutline,\n IconSearchAIOutline,\n IconSendOutline,\n} from '@daisforge/ui/icons';\n\n// Весь контент окна на стороне потребителя, ниже один из вариантов сборки.\n// Состояние чата и открытый раздел левой панели держим снаружи окна:\n// закрытие окна размонтирует контент, а состояние снаружи это переживает.\n\n// Левый сайдбар страницы с кнопкой AI-помощника: окно откроется справа\n// от неё, targetRef висит на обёртке кнопки\nconst sidebarStyle = {\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '8px',\n background: surfaceTransparentSecondary,\n};\n\nfunction Sidebar({ sidebarRef, targetRef, onToggle }) {\n return (\n <div ref={sidebarRef} style={sidebarStyle}>\n <span ref={targetRef}>\n <IconButton size=\"s\" view=\"clear\" onClick={onToggle}>\n <IconCatalogOutline size=\"s\" />\n </IconButton>\n </span>\n </div>\n );\n}\n\n// Левая граница перетаскивания равна ширине сайдбара: окно не заезжает\n// на него. Ширину следим наблюдателем, а не одним замером\nfunction useSidebarWidth(ref) {\n const [width, setWidth] = useState(0);\n useLayoutEffect(() => {\n const node = ref.current;\n if (!node) return undefined;\n const update = () => setWidth(node.offsetWidth);\n update();\n const observer = new ResizeObserver(update);\n observer.observe(node);\n return () => observer.disconnect();\n }, [ref]);\n return width;\n}\n\nconst chatHeaderStyle = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n};\n\n// Иконка у заголовка не кликается, но стоит в том же квадрате 40x40,\n// что и кнопки шапки\nconst chatTitleIconStyle = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '40px',\n height: '40px',\n};\n\nconst chatMessagesStyle = {\n flex: '1 1 auto',\n minHeight: 0,\n overflow: 'auto',\n display: 'flex',\n flexDirection: 'column',\n gap: '8px',\n marginTop: '12px',\n};\n\nconst chatBubbleStyle = {\n background: surfaceAccentMinor,\n borderRadius: '8px',\n padding: '10px 12px',\n color: textPrimary,\n};\n\n// Сообщение от системы: без фона, свечение ложится прямо под текст\nconst systemMessageStyle = {\n padding: '0 12px',\n color: textInfo,\n};\n\n// Кнопки не начинают перетаскивание, по ним работают обычные клики\nfunction ChatHeader({ onClose }) {\n return (\n <div style={chatHeaderStyle}>\n <div style={{ display: 'flex', alignItems: 'center' }}>\n <span style={chatTitleIconStyle}>\n <IconSearchAIOutline size=\"s\" color={textAccentGradient} />\n </span>\n <Typography variant=\"BodyM\" bold>\n AI-Chat\n </Typography>\n </div>\n <div style={{ display: 'flex', alignItems: 'center' }}>\n <IconButton size=\"s\" view=\"clear\">\n <IconMessageAddOutline size=\"s\" />\n </IconButton>\n <IconButton size=\"s\" view=\"clear\" onClick={onClose}>\n <IconClose size=\"s\" />\n </IconButton>\n </div>\n </div>\n );\n}\n\nfunction ChatContent({\n messages,\n draft,\n onDraftChange,\n onSend,\n onClose,\n}) {\n return (\n <>\n <ChatHeader onClose={onClose} />\n <div style={chatMessagesStyle}>\n {messages.map((message, index) => (\n <Typography\n key={index}\n variant=\"BodyS\"\n style={message.system ? systemMessageStyle : chatBubbleStyle}\n data-no-drag\n >\n {message.text}\n </Typography>\n ))}\n </div>\n {/* Отступов вокруг AiAgentInput нет: по дизайну поле прижато\n к ленте сообщений */}\n <AiAgentInput\n glow\n placeholder=\"Спросите что-нибудь\"\n value={draft}\n onChange={(e) => onDraftChange(e.target.value)}\n rightSlot={\n <IconButton size=\"xs\" view=\"clear\" onClick={onSend}>\n {/* плазма-иконки умеют градиент в color: рисуют её маской */}\n <IconSendOutline size=\"s\" color={textAccentGradient} />\n </IconButton>\n }\n />\n </>\n );\n}\n\nconst sectionBodyStyle = {\n display: 'flex',\n flexDirection: 'column',\n gap: '8px',\n padding: '12px',\n height: '100%',\n overflow: 'auto',\n};\n\n\n// Разделы левой панели окна: иконка в полосе, заголовок и контент раздела\nconst leftPanelItems = [\n {\n key: 'history',\n icon: <IconHistory size=\"s\" />,\n title: 'История',\n content: (\n <div style={sectionBodyStyle}>\n <Typography variant=\"BodyS\">Вчера: вопросы по таблицам</Typography>\n <Typography variant=\"BodyS\">2 дня назад: настройка форм</Typography>\n </div>\n ),\n },\n {\n key: 'tasks',\n icon: <IconDoneCircleOutline size=\"s\" />,\n title: 'Задачи',\n content: (\n <div style={sectionBodyStyle}>\n <Typography variant=\"BodyS\">Проверить отчёт</Typography>\n </div>\n ),\n },\n {\n key: 'calendar',\n icon: <IconCalendarEventOutline size=\"s\" />,\n title: 'Календарь',\n content: (\n <div style={sectionBodyStyle}>\n <Typography variant=\"BodyS\">Сегодня: созвон в 15:00</Typography>\n </div>\n ),\n },\n];${exampleBody("
|
|
944
|
+
}
|
|
945
|
+
],
|
|
946
|
+
"hasCuratedMeta": true,
|
|
947
|
+
"atomicMcpVersion": "0.360.0",
|
|
948
|
+
"importPath": "@daisforge/ui",
|
|
949
|
+
"importStatement": "import { AiAgentPopup } from '@daisforge/ui';",
|
|
950
|
+
"minimalUsage": "<AiAgentPopup />",
|
|
951
|
+
"examples": [
|
|
952
|
+
{
|
|
953
|
+
"exportName": "Simple",
|
|
954
|
+
"displayName": "Simple",
|
|
955
|
+
"type": "full-code",
|
|
956
|
+
"code": "import { useLayoutEffect, useRef, useState } from 'react';\nimport {\n AiAgentInput,\n AiAgentPopup,\n IconButton,\n PopupProvider,\n SSRProvider,\n surfaceAccentMinor,\n surfaceTransparentSecondary,\n textAccentGradient,\n textInfo,\n textPrimary,\n Typography,\n} from '@daisforge/ui';\nimport {\n IconCalendarEventOutline,\n IconCatalogOutline,\n IconClose,\n IconDoneCircleOutline,\n IconHistory,\n IconMessageAddOutline,\n IconSearchAIOutline,\n IconSendOutline,\n} from '@daisforge/ui/icons';\n\n// Весь контент окна на стороне потребителя, ниже один из вариантов сборки.\n// Состояние чата и открытый раздел левой панели держим снаружи окна:\n// закрытие окна размонтирует контент, а состояние снаружи это переживает.\n\n// Левый сайдбар страницы с кнопкой AI-помощника: окно откроется справа\n// от неё, targetRef висит на обёртке кнопки\nconst sidebarStyle = {\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '8px',\n background: surfaceTransparentSecondary,\n};\n\nfunction Sidebar({ sidebarRef, targetRef, onToggle }) {\n return (\n <div ref={sidebarRef} style={sidebarStyle}>\n <span ref={targetRef}>\n <IconButton size=\"s\" view=\"clear\" onClick={onToggle}>\n <IconCatalogOutline size=\"s\" />\n </IconButton>\n </span>\n </div>\n );\n}\n\n// Левая граница перетаскивания равна ширине сайдбара: окно не заезжает\n// на него. Ширину следим наблюдателем, а не одним замером\nfunction useSidebarWidth(ref) {\n const [width, setWidth] = useState(0);\n useLayoutEffect(() => {\n const node = ref.current;\n if (!node) return undefined;\n const update = () => setWidth(node.offsetWidth);\n update();\n const observer = new ResizeObserver(update);\n observer.observe(node);\n return () => observer.disconnect();\n }, [ref]);\n return width;\n}\n\nconst chatHeaderStyle = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n};\n\n// Иконка у заголовка не кликается, но стоит в том же квадрате 40x40,\n// что и кнопки шапки\nconst chatTitleIconStyle = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '40px',\n height: '40px',\n};\n\nconst chatMessagesStyle = {\n flex: '1 1 auto',\n minHeight: 0,\n overflow: 'auto',\n display: 'flex',\n flexDirection: 'column',\n gap: '8px',\n marginTop: '12px',\n};\n\nconst chatBubbleStyle = {\n background: surfaceAccentMinor,\n borderRadius: '8px',\n padding: '10px 12px',\n color: textPrimary,\n};\n\n// Сообщение от системы: без фона, свечение ложится прямо под текст\nconst systemMessageStyle = {\n padding: '0 12px',\n color: textInfo,\n};\n\n// Кнопки не начинают перетаскивание, по ним работают обычные клики\nfunction ChatHeader({ onClose }) {\n return (\n <div style={chatHeaderStyle}>\n <div style={{ display: 'flex', alignItems: 'center' }}>\n <span style={chatTitleIconStyle}>\n <IconSearchAIOutline size=\"s\" color={textAccentGradient} />\n </span>\n <Typography variant=\"BodyM\" bold>\n AI-Chat\n </Typography>\n </div>\n <div style={{ display: 'flex', alignItems: 'center' }}>\n <IconButton size=\"s\" view=\"clear\">\n <IconMessageAddOutline size=\"s\" />\n </IconButton>\n <IconButton size=\"s\" view=\"clear\" onClick={onClose}>\n <IconClose size=\"s\" />\n </IconButton>\n </div>\n </div>\n );\n}\n\nfunction ChatContent({\n messages,\n draft,\n onDraftChange,\n onSend,\n onClose,\n}) {\n return (\n <>\n <ChatHeader onClose={onClose} />\n <div style={chatMessagesStyle}>\n {messages.map((message, index) => (\n <Typography\n key={index}\n variant=\"BodyS\"\n style={message.system ? systemMessageStyle : chatBubbleStyle}\n data-no-drag\n >\n {message.text}\n </Typography>\n ))}\n </div>\n {/* Отступов вокруг AiAgentInput нет: по дизайну поле прижато\n к ленте сообщений */}\n <AiAgentInput\n glow\n placeholder=\"Спросите что-нибудь\"\n value={draft}\n onChange={(e) => onDraftChange(e.target.value)}\n rightSlot={\n <IconButton size=\"xs\" view=\"clear\" onClick={onSend}>\n {/* плазма-иконки умеют градиент в color: рисуют её маской */}\n <IconSendOutline size=\"s\" color={textAccentGradient} />\n </IconButton>\n }\n />\n </>\n );\n}\n\nconst sectionBodyStyle = {\n display: 'flex',\n flexDirection: 'column',\n gap: '8px',\n padding: '12px',\n height: '100%',\n overflow: 'auto',\n};\n\n\n// Разделы левой панели окна: иконка в полосе, заголовок и контент раздела\nconst leftPanelItems = [\n {\n key: 'history',\n icon: <IconHistory size=\"s\" />,\n title: 'История',\n content: (\n <div style={sectionBodyStyle}>\n <Typography variant=\"BodyS\">Вчера: вопросы по таблицам</Typography>\n <Typography variant=\"BodyS\">2 дня назад: настройка форм</Typography>\n </div>\n ),\n },\n {\n key: 'tasks',\n icon: <IconDoneCircleOutline size=\"s\" />,\n title: 'Задачи',\n content: (\n <div style={sectionBodyStyle}>\n <Typography variant=\"BodyS\">Проверить отчёт</Typography>\n </div>\n ),\n },\n {\n key: 'calendar',\n icon: <IconCalendarEventOutline size=\"s\" />,\n title: 'Календарь',\n content: (\n <div style={sectionBodyStyle}>\n <Typography variant=\"BodyS\">Сегодня: созвон в 15:00</Typography>\n </div>\n ),\n },\n];${exampleBody("
|
|
957
|
+
},
|
|
958
|
+
{
|
|
959
|
+
"exportName": "Playground",
|
|
960
|
+
"displayName": "Playground",
|
|
961
|
+
"type": "full-code",
|
|
962
|
+
"code": "import { useLayoutEffect, useRef, useState } from 'react';\nimport {\n AiAgentInput,\n AiAgentPopup,\n IconButton,\n PopupProvider,\n SSRProvider,\n surfaceAccentMinor,\n surfaceTransparentSecondary,\n textAccentGradient,\n textInfo,\n textPrimary,\n Typography,\n} from '@daisforge/ui';\nimport {\n IconCalendarEventOutline,\n IconCatalogOutline,\n IconClose,\n IconDoneCircleOutline,\n IconHistory,\n IconMessageAddOutline,\n IconSearchAIOutline,\n IconSendOutline,\n} from '@daisforge/ui/icons';\n\n// Весь контент окна на стороне потребителя, ниже один из вариантов сборки.\n// Состояние чата и открытый раздел левой панели держим снаружи окна:\n// закрытие окна размонтирует контент, а состояние снаружи это переживает.\n\n// Левый сайдбар страницы с кнопкой AI-помощника: окно откроется справа\n// от неё, targetRef висит на обёртке кнопки\nconst sidebarStyle = {\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '8px',\n background: surfaceTransparentSecondary,\n};\n\nfunction Sidebar({ sidebarRef, targetRef, onToggle }) {\n return (\n <div ref={sidebarRef} style={sidebarStyle}>\n <span ref={targetRef}>\n <IconButton size=\"s\" view=\"clear\" onClick={onToggle}>\n <IconCatalogOutline size=\"s\" />\n </IconButton>\n </span>\n </div>\n );\n}\n\n// Левая граница перетаскивания равна ширине сайдбара: окно не заезжает\n// на него. Ширину следим наблюдателем, а не одним замером\nfunction useSidebarWidth(ref) {\n const [width, setWidth] = useState(0);\n useLayoutEffect(() => {\n const node = ref.current;\n if (!node) return undefined;\n const update = () => setWidth(node.offsetWidth);\n update();\n const observer = new ResizeObserver(update);\n observer.observe(node);\n return () => observer.disconnect();\n }, [ref]);\n return width;\n}\n\nconst chatHeaderStyle = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n};\n\n// Иконка у заголовка не кликается, но стоит в том же квадрате 40x40,\n// что и кнопки шапки\nconst chatTitleIconStyle = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '40px',\n height: '40px',\n};\n\nconst chatMessagesStyle = {\n flex: '1 1 auto',\n minHeight: 0,\n overflow: 'auto',\n display: 'flex',\n flexDirection: 'column',\n gap: '8px',\n marginTop: '12px',\n};\n\nconst chatBubbleStyle = {\n background: surfaceAccentMinor,\n borderRadius: '8px',\n padding: '10px 12px',\n color: textPrimary,\n};\n\n// Сообщение от системы: без фона, свечение ложится прямо под текст\nconst systemMessageStyle = {\n padding: '0 12px',\n color: textInfo,\n};\n\n// Кнопки не начинают перетаскивание, по ним работают обычные клики\nfunction ChatHeader({ onClose }) {\n return (\n <div style={chatHeaderStyle}>\n <div style={{ display: 'flex', alignItems: 'center' }}>\n <span style={chatTitleIconStyle}>\n <IconSearchAIOutline size=\"s\" color={textAccentGradient} />\n </span>\n <Typography variant=\"BodyM\" bold>\n AI-Chat\n </Typography>\n </div>\n <div style={{ display: 'flex', alignItems: 'center' }}>\n <IconButton size=\"s\" view=\"clear\">\n <IconMessageAddOutline size=\"s\" />\n </IconButton>\n <IconButton size=\"s\" view=\"clear\" onClick={onClose}>\n <IconClose size=\"s\" />\n </IconButton>\n </div>\n </div>\n );\n}\n\nfunction ChatContent({\n messages,\n draft,\n onDraftChange,\n onSend,\n onClose,\n}) {\n return (\n <>\n <ChatHeader onClose={onClose} />\n <div style={chatMessagesStyle}>\n {messages.map((message, index) => (\n <Typography\n key={index}\n variant=\"BodyS\"\n style={message.system ? systemMessageStyle : chatBubbleStyle}\n data-no-drag\n >\n {message.text}\n </Typography>\n ))}\n </div>\n {/* Отступов вокруг AiAgentInput нет: по дизайну поле прижато\n к ленте сообщений */}\n <AiAgentInput\n glow\n placeholder=\"Спросите что-нибудь\"\n value={draft}\n onChange={(e) => onDraftChange(e.target.value)}\n rightSlot={\n <IconButton size=\"xs\" view=\"clear\" onClick={onSend}>\n {/* плазма-иконки умеют градиент в color: рисуют её маской */}\n <IconSendOutline size=\"s\" color={textAccentGradient} />\n </IconButton>\n }\n />\n </>\n );\n}\n\nconst sectionBodyStyle = {\n display: 'flex',\n flexDirection: 'column',\n gap: '8px',\n padding: '12px',\n height: '100%',\n overflow: 'auto',\n};\n\n\n// Разделы левой панели окна: иконка в полосе, заголовок и контент раздела\nconst leftPanelItems = [\n {\n key: 'history',\n icon: <IconHistory size=\"s\" />,\n title: 'История',\n content: (\n <div style={sectionBodyStyle}>\n <Typography variant=\"BodyS\">Вчера: вопросы по таблицам</Typography>\n <Typography variant=\"BodyS\">2 дня назад: настройка форм</Typography>\n </div>\n ),\n },\n {\n key: 'tasks',\n icon: <IconDoneCircleOutline size=\"s\" />,\n title: 'Задачи',\n content: (\n <div style={sectionBodyStyle}>\n <Typography variant=\"BodyS\">Проверить отчёт</Typography>\n </div>\n ),\n },\n {\n key: 'calendar',\n icon: <IconCalendarEventOutline size=\"s\" />,\n title: 'Календарь',\n content: (\n <div style={sectionBodyStyle}>\n <Typography variant=\"BodyS\">Сегодня: созвон в 15:00</Typography>\n </div>\n ),\n },\n];${exampleBody("
|
|
963
|
+
},
|
|
964
|
+
{
|
|
965
|
+
"exportName": "Usage",
|
|
966
|
+
"displayName": "Использование в AiAgentPopup.stories.tsx",
|
|
967
|
+
"type": "usage",
|
|
968
|
+
"code": "<AiAgentPopup\n // Пока окно не умеет само расширяться при открытии раздела,\n // стартуем шире размера по умолчанию\n defaultSize={{ width: 680, height: 540 }}\n {...popupArgs}\n opened={opened}\n targetRef={targetRef}\n frame={frameRef}\n leftPanel={{\n items: leftPanelItems,\n activeKey: activeSection,\n onActiveKeyChange: setActiveSection,\n }}\n dragBoundary={{\n top: 8,\n right: 8,\n bottom: 8,\n ...dragBoundary,\n left: sidebarWidth + (dragBoundary?.left ?? 0),\n }}\n >\n <ChatContent\n messages={messages}\n draft={draft}\n glow={glow}\n onDraftChange={setDraft}\n onSend={sendDraft}\n onClose={() => setOpened(false)}\n />\n </AiAgentPopup>",
|
|
969
|
+
"sourceFile": "packages/storybook/src/stories/AiAgentPopup/AiAgentPopup.stories.tsx"
|
|
970
|
+
}
|
|
971
|
+
]
|
|
972
|
+
},
|
|
515
973
|
"AnalyticalWidget": {
|
|
516
974
|
"name": "AnalyticalWidget",
|
|
517
975
|
"group": "components",
|
|
@@ -796,7 +1254,7 @@
|
|
|
796
1254
|
},
|
|
797
1255
|
{
|
|
798
1256
|
"name": "view",
|
|
799
|
-
"type": "\"clear\" | \"default\" | \"
|
|
1257
|
+
"type": "\"clear\" | \"default\" | \"positive\" | \"warning\" | \"negative\" | \"secondary\" | \"accent\" | \"dark\" | \"black\" | \"white\" | \"gradient\" | undefined",
|
|
800
1258
|
"required": false,
|
|
801
1259
|
"description": ""
|
|
802
1260
|
}
|
|
@@ -820,12 +1278,6 @@
|
|
|
820
1278
|
"description": "Отступ (top/right) при `absolute`.",
|
|
821
1279
|
"default": "12"
|
|
822
1280
|
},
|
|
823
|
-
{
|
|
824
|
-
"name": "as",
|
|
825
|
-
"type": "keyof JSX.IntrinsicElements | React.ComponentType<any> | undefined",
|
|
826
|
-
"required": false,
|
|
827
|
-
"description": "Сменить рендер на другой тип компонента."
|
|
828
|
-
},
|
|
829
1281
|
{
|
|
830
1282
|
"name": "dropdownProps",
|
|
831
1283
|
"type": "(Omit<DropdownProps<ItemOption>, \"view\" | \"size\"> & Pick<PropsType<{ size: { m: PolymorphicClassName; s: PolymorphicClassName; xs: PolymorphicClassName; }; view: { default: PolymorphicClassName; }; }> & { items: ItemOption[]; trigger?: DropdownTrigger | undefined; placement?: DropdownPlacement | undefined; children?: React.ReactNode; variant?: \"normal\" | \"tight\" | undefined; zIndex?: Property.ZInd…",
|
|
@@ -845,6 +1297,12 @@
|
|
|
845
1297
|
"required": false,
|
|
846
1298
|
"description": ""
|
|
847
1299
|
},
|
|
1300
|
+
{
|
|
1301
|
+
"name": "as",
|
|
1302
|
+
"type": "keyof JSX.IntrinsicElements | React.ComponentType<unknown> | undefined",
|
|
1303
|
+
"required": false,
|
|
1304
|
+
"description": ""
|
|
1305
|
+
},
|
|
848
1306
|
{
|
|
849
1307
|
"name": "isLoading",
|
|
850
1308
|
"type": "boolean | undefined",
|
|
@@ -859,13 +1317,13 @@
|
|
|
859
1317
|
},
|
|
860
1318
|
{
|
|
861
1319
|
"name": "position",
|
|
862
|
-
"type": "
|
|
1320
|
+
"type": "\"top\" | \"bottom\" | \"top-right\" | \"top-left\" | \"bottom-right\" | \"bottom-left\" | \"center\" | \"center-left\" | \"center-right\" | undefined",
|
|
863
1321
|
"required": false,
|
|
864
1322
|
"description": ""
|
|
865
1323
|
},
|
|
866
1324
|
{
|
|
867
1325
|
"name": "size",
|
|
868
|
-
"type": "
|
|
1326
|
+
"type": "EmbeddedButtonSize | undefined",
|
|
869
1327
|
"required": false,
|
|
870
1328
|
"description": "",
|
|
871
1329
|
"default": "'m'"
|
|
@@ -878,7 +1336,7 @@
|
|
|
878
1336
|
},
|
|
879
1337
|
{
|
|
880
1338
|
"name": "view",
|
|
881
|
-
"type": "
|
|
1339
|
+
"type": "EmbeddedButtonView | undefined",
|
|
882
1340
|
"required": false,
|
|
883
1341
|
"description": "",
|
|
884
1342
|
"default": "'default'"
|
|
@@ -2488,6 +2946,15 @@
|
|
|
2488
2946
|
"inheritedFrom": "Avatar",
|
|
2489
2947
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
2490
2948
|
},
|
|
2949
|
+
{
|
|
2950
|
+
"name": "thousandSeparator",
|
|
2951
|
+
"type": "string | boolean",
|
|
2952
|
+
"required": false,
|
|
2953
|
+
"description": "Разделитель тысяч.\nМожет быть строкой (например, \",\") или булевым значением.",
|
|
2954
|
+
"default": "' ' (пробел)",
|
|
2955
|
+
"inheritedFrom": "Avatar",
|
|
2956
|
+
"inheritedPackage": "@salutejs/sdds-finai"
|
|
2957
|
+
},
|
|
2491
2958
|
{
|
|
2492
2959
|
"name": "type",
|
|
2493
2960
|
"type": "\"badge\" | \"counter\"",
|
|
@@ -2525,13 +2992,6 @@
|
|
|
2525
2992
|
"inheritedFrom": "Avatar",
|
|
2526
2993
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
2527
2994
|
},
|
|
2528
|
-
{
|
|
2529
|
-
"name": "thousandSeparator",
|
|
2530
|
-
"type": "string | boolean",
|
|
2531
|
-
"required": false,
|
|
2532
|
-
"inheritedFrom": "Avatar",
|
|
2533
|
-
"inheritedPackage": "@salutejs/sdds-finai"
|
|
2534
|
-
},
|
|
2535
2995
|
{
|
|
2536
2996
|
"name": "transparent",
|
|
2537
2997
|
"type": "boolean",
|
|
@@ -3811,7 +4271,15 @@
|
|
|
3811
4271
|
"folderName": "Calendar",
|
|
3812
4272
|
"role": "primary",
|
|
3813
4273
|
"description": "Календарь для выбора одной даты или диапазона дат с отметкой событий",
|
|
3814
|
-
"props": [
|
|
4274
|
+
"props": [
|
|
4275
|
+
{
|
|
4276
|
+
"name": "quarterNames",
|
|
4277
|
+
"type": "string[] | undefined",
|
|
4278
|
+
"required": false,
|
|
4279
|
+
"description": "Названия кварталов.",
|
|
4280
|
+
"default": "['Q1', 'Q2', 'Q3', 'Q4']"
|
|
4281
|
+
}
|
|
4282
|
+
],
|
|
3815
4283
|
"propsTypeName": "CalendarProps",
|
|
3816
4284
|
"sourceFile": "node_modules/@salutejs/sdds-finai/types/components/Calendar/Calendar.d.ts",
|
|
3817
4285
|
"type": "wrapper",
|
|
@@ -4180,6 +4648,13 @@
|
|
|
4180
4648
|
"required": false,
|
|
4181
4649
|
"description": "Обработчик изменения отображаемых месяца или года при навигации по календарю."
|
|
4182
4650
|
},
|
|
4651
|
+
{
|
|
4652
|
+
"name": "quarterNames",
|
|
4653
|
+
"type": "string[] | undefined",
|
|
4654
|
+
"required": false,
|
|
4655
|
+
"description": "Названия кварталов.",
|
|
4656
|
+
"default": "['Q1', 'Q2', 'Q3', 'Q4']"
|
|
4657
|
+
},
|
|
4183
4658
|
{
|
|
4184
4659
|
"name": "renderFromDate",
|
|
4185
4660
|
"type": "Date | undefined",
|
|
@@ -4368,6 +4843,13 @@
|
|
|
4368
4843
|
"required": false,
|
|
4369
4844
|
"description": "Обработчик изменения отображаемых месяца или года при навигации по календарю."
|
|
4370
4845
|
},
|
|
4846
|
+
{
|
|
4847
|
+
"name": "quarterNames",
|
|
4848
|
+
"type": "string[] | undefined",
|
|
4849
|
+
"required": false,
|
|
4850
|
+
"description": "Названия кварталов.",
|
|
4851
|
+
"default": "['Q1', 'Q2', 'Q3', 'Q4']"
|
|
4852
|
+
},
|
|
4371
4853
|
{
|
|
4372
4854
|
"name": "renderFromDate",
|
|
4373
4855
|
"type": "Date | undefined",
|
|
@@ -4538,6 +5020,13 @@
|
|
|
4538
5020
|
"required": false,
|
|
4539
5021
|
"description": "Обработчик изменения отображаемых месяца или года при навигации по календарю."
|
|
4540
5022
|
},
|
|
5023
|
+
{
|
|
5024
|
+
"name": "quarterNames",
|
|
5025
|
+
"type": "string[] | undefined",
|
|
5026
|
+
"required": false,
|
|
5027
|
+
"description": "Названия кварталов.",
|
|
5028
|
+
"default": "['Q1', 'Q2', 'Q3', 'Q4']"
|
|
5029
|
+
},
|
|
4541
5030
|
{
|
|
4542
5031
|
"name": "renderFromDate",
|
|
4543
5032
|
"type": "Date | undefined",
|
|
@@ -4720,6 +5209,13 @@
|
|
|
4720
5209
|
"required": false,
|
|
4721
5210
|
"description": "Обработчик изменения отображаемых месяца или года при навигации по календарю."
|
|
4722
5211
|
},
|
|
5212
|
+
{
|
|
5213
|
+
"name": "quarterNames",
|
|
5214
|
+
"type": "string[] | undefined",
|
|
5215
|
+
"required": false,
|
|
5216
|
+
"description": "Названия кварталов.",
|
|
5217
|
+
"default": "['Q1', 'Q2', 'Q3', 'Q4']"
|
|
5218
|
+
},
|
|
4723
5219
|
{
|
|
4724
5220
|
"name": "renderFromDate",
|
|
4725
5221
|
"type": "Date | undefined",
|
|
@@ -5580,17 +6076,17 @@
|
|
|
5580
6076
|
"examples": [
|
|
5581
6077
|
{
|
|
5582
6078
|
"exportName": "Usage1",
|
|
5583
|
-
"displayName": "Использование в
|
|
6079
|
+
"displayName": "Использование в TableCanvas.stickyRowsCols.stories.tsx",
|
|
5584
6080
|
"type": "usage",
|
|
5585
|
-
"code": "<Checkbox\n
|
|
5586
|
-
"sourceFile": "packages/storybook/src/stories/
|
|
6081
|
+
"code": "<Checkbox\n key={key}\n size=\"s\"\n label={typeof name === 'string' ? name : key}\n checked={stickyColumns.includes(key)}\n onChange={(event) => toggleColumn(key, event.target.checked)}\n />",
|
|
6082
|
+
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.StickyRowsCols/TableCanvas.stickyRowsCols.stories.tsx"
|
|
5587
6083
|
},
|
|
5588
6084
|
{
|
|
5589
6085
|
"exportName": "Usage2",
|
|
5590
|
-
"displayName": "Использование в
|
|
6086
|
+
"displayName": "Использование в Table.customRenderWithContext.stories.tsx",
|
|
5591
6087
|
"type": "usage",
|
|
5592
|
-
"code": "<Checkbox\n
|
|
5593
|
-
"sourceFile": "packages/storybook/src/stories/
|
|
6088
|
+
"code": "<Checkbox\n tabIndex={tabIndex}\n checked={checked}\n label={`${checked ? 'Выключить' : 'Включить'} чекбокс`}\n onChange={(e) => setChecked(e.target.checked)}\n />",
|
|
6089
|
+
"sourceFile": "packages/storybook/src/stories/Table/Table.customRender/Table.customRenderWithContext.stories.tsx"
|
|
5594
6090
|
},
|
|
5595
6091
|
{
|
|
5596
6092
|
"exportName": "Vendor1",
|
|
@@ -6392,6 +6888,12 @@
|
|
|
6392
6888
|
"role": "primary",
|
|
6393
6889
|
"description": "Выпадающий список с поиском и мультивыбором значений в виде чипов",
|
|
6394
6890
|
"props": [
|
|
6891
|
+
{
|
|
6892
|
+
"name": "sortItems",
|
|
6893
|
+
"type": "((a: T, b: T) => number) | undefined",
|
|
6894
|
+
"required": false,
|
|
6895
|
+
"description": "Компаратор сортировки элементов первого уровня.\nВложенные списки и исходный массив items не изменяются."
|
|
6896
|
+
},
|
|
6395
6897
|
{
|
|
6396
6898
|
"name": "autoComplete",
|
|
6397
6899
|
"type": "React.HTMLInputAutoCompleteAttribute | undefined",
|
|
@@ -6452,6 +6954,14 @@
|
|
|
6452
6954
|
"inheritedFrom": "Combobox",
|
|
6453
6955
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
6454
6956
|
},
|
|
6957
|
+
{
|
|
6958
|
+
"name": "appearance",
|
|
6959
|
+
"type": "\"default\" | \"viewMode\"",
|
|
6960
|
+
"required": false,
|
|
6961
|
+
"description": "Стиль для UI конфигурации\nВлияет на выбор предустановленного набора токенов",
|
|
6962
|
+
"inheritedFrom": "Combobox",
|
|
6963
|
+
"inheritedPackage": "@salutejs/sdds-finai"
|
|
6964
|
+
},
|
|
6455
6965
|
{
|
|
6456
6966
|
"name": "arrowPlacement",
|
|
6457
6967
|
"type": "\"right\" | \"left\"",
|
|
@@ -6527,6 +7037,14 @@
|
|
|
6527
7037
|
"inheritedFrom": "Combobox",
|
|
6528
7038
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
6529
7039
|
},
|
|
7040
|
+
{
|
|
7041
|
+
"name": "hasDivider",
|
|
7042
|
+
"type": "boolean",
|
|
7043
|
+
"required": false,
|
|
7044
|
+
"description": "отобразить ли divider",
|
|
7045
|
+
"inheritedFrom": "Combobox",
|
|
7046
|
+
"inheritedPackage": "@salutejs/sdds-finai"
|
|
7047
|
+
},
|
|
6530
7048
|
{
|
|
6531
7049
|
"name": "hasRequiredIndicator",
|
|
6532
7050
|
"type": "boolean",
|
|
@@ -6825,13 +7343,6 @@
|
|
|
6825
7343
|
"inheritedFrom": "Combobox",
|
|
6826
7344
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
6827
7345
|
},
|
|
6828
|
-
{
|
|
6829
|
-
"name": "appearance",
|
|
6830
|
-
"type": "\"default\" | \"viewMode\"",
|
|
6831
|
-
"required": false,
|
|
6832
|
-
"inheritedFrom": "Combobox",
|
|
6833
|
-
"inheritedPackage": "@salutejs/sdds-finai"
|
|
6834
|
-
},
|
|
6835
7346
|
{
|
|
6836
7347
|
"name": "chipClickArea",
|
|
6837
7348
|
"type": "\"full\" | \"close-icon\"",
|
|
@@ -6860,13 +7371,6 @@
|
|
|
6860
7371
|
"inheritedFrom": "Combobox",
|
|
6861
7372
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
6862
7373
|
},
|
|
6863
|
-
{
|
|
6864
|
-
"name": "hasDivider",
|
|
6865
|
-
"type": "boolean",
|
|
6866
|
-
"required": false,
|
|
6867
|
-
"inheritedFrom": "Combobox",
|
|
6868
|
-
"inheritedPackage": "@salutejs/sdds-finai"
|
|
6869
|
-
},
|
|
6870
7374
|
{
|
|
6871
7375
|
"name": "hintSize",
|
|
6872
7376
|
"type": "\"s\" | \"m\"",
|
|
@@ -7051,18 +7555,20 @@
|
|
|
7051
7555
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
7052
7556
|
},
|
|
7053
7557
|
{
|
|
7054
|
-
"name": "
|
|
7055
|
-
"type": "
|
|
7558
|
+
"name": "thousandSeparator",
|
|
7559
|
+
"type": "string | boolean",
|
|
7056
7560
|
"required": false,
|
|
7057
|
-
"description": "
|
|
7058
|
-
"default": "
|
|
7561
|
+
"description": "Разделитель тысяч.\nМожет быть строкой (например, \",\") или булевым значением.",
|
|
7562
|
+
"default": "' ' (пробел)",
|
|
7059
7563
|
"inheritedFrom": "Counter",
|
|
7060
7564
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
7061
7565
|
},
|
|
7062
7566
|
{
|
|
7063
|
-
"name": "
|
|
7064
|
-
"type": "
|
|
7567
|
+
"name": "view",
|
|
7568
|
+
"type": "\"default\" | \"accent\" | \"positive\" | \"warning\" | \"negative\" | \"dark\" | \"light\" | \"secondary\"",
|
|
7065
7569
|
"required": false,
|
|
7570
|
+
"description": "Вид Counter",
|
|
7571
|
+
"default": "default",
|
|
7066
7572
|
"inheritedFrom": "Counter",
|
|
7067
7573
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
7068
7574
|
}
|
|
@@ -7099,7 +7605,15 @@
|
|
|
7099
7605
|
"folderName": "DatePicker",
|
|
7100
7606
|
"role": "primary",
|
|
7101
7607
|
"description": "Поле выбора одной даты со встроенным календарём и иконкой",
|
|
7102
|
-
"props": [
|
|
7608
|
+
"props": [
|
|
7609
|
+
{
|
|
7610
|
+
"name": "quarterNames",
|
|
7611
|
+
"type": "string[] | undefined",
|
|
7612
|
+
"required": false,
|
|
7613
|
+
"description": "Названия кварталов.",
|
|
7614
|
+
"default": "['Q1', 'Q2', 'Q3', 'Q4']"
|
|
7615
|
+
}
|
|
7616
|
+
],
|
|
7103
7617
|
"propsTypeName": "DatePickerProps",
|
|
7104
7618
|
"sourceFile": "packages/ui-kit/src/components/DatePicker/DatePicker.tsx",
|
|
7105
7619
|
"type": "wrapper",
|
|
@@ -8216,6 +8730,13 @@
|
|
|
8216
8730
|
"required": false,
|
|
8217
8731
|
"description": "Видимость календаря."
|
|
8218
8732
|
},
|
|
8733
|
+
{
|
|
8734
|
+
"name": "quarterNames",
|
|
8735
|
+
"type": "string[] | undefined",
|
|
8736
|
+
"required": false,
|
|
8737
|
+
"description": "Названия кварталов.",
|
|
8738
|
+
"default": "['Q1', 'Q2', 'Q3', 'Q4']"
|
|
8739
|
+
},
|
|
8219
8740
|
{
|
|
8220
8741
|
"name": "renderFromDate",
|
|
8221
8742
|
"type": "Date | undefined",
|
|
@@ -8392,6 +8913,13 @@
|
|
|
8392
8913
|
"role": "primary",
|
|
8393
8914
|
"description": "Поле для ввода даты и времени одновременно в одном контроле",
|
|
8394
8915
|
"props": [
|
|
8916
|
+
{
|
|
8917
|
+
"name": "quarterNames",
|
|
8918
|
+
"type": "string[] | undefined",
|
|
8919
|
+
"required": false,
|
|
8920
|
+
"description": "Названия кварталов.",
|
|
8921
|
+
"default": "['Q1', 'Q2', 'Q3', 'Q4']"
|
|
8922
|
+
},
|
|
8395
8923
|
{
|
|
8396
8924
|
"name": "enterKeyHint",
|
|
8397
8925
|
"type": "\"search\" | \"enter\" | \"done\" | \"go\" | \"next\" | \"previous\" | \"send\" | undefined",
|
|
@@ -12522,9 +13050,9 @@
|
|
|
12522
13050
|
"props": [
|
|
12523
13051
|
{
|
|
12524
13052
|
"name": "as",
|
|
12525
|
-
"type": "keyof JSX.IntrinsicElements | React.ComponentType<
|
|
13053
|
+
"type": "keyof JSX.IntrinsicElements | React.ComponentType<unknown> | undefined",
|
|
12526
13054
|
"required": false,
|
|
12527
|
-
"description": "
|
|
13055
|
+
"description": ""
|
|
12528
13056
|
},
|
|
12529
13057
|
{
|
|
12530
13058
|
"name": "isLoading",
|
|
@@ -12540,13 +13068,13 @@
|
|
|
12540
13068
|
},
|
|
12541
13069
|
{
|
|
12542
13070
|
"name": "position",
|
|
12543
|
-
"type": "
|
|
13071
|
+
"type": "\"center\" | \"center-left\" | \"center-right\" | \"top\" | \"top-left\" | \"top-right\" | \"bottom\" | \"bottom-left\" | \"bottom-right\" | undefined",
|
|
12544
13072
|
"required": false,
|
|
12545
13073
|
"description": ""
|
|
12546
13074
|
},
|
|
12547
13075
|
{
|
|
12548
13076
|
"name": "size",
|
|
12549
|
-
"type": "
|
|
13077
|
+
"type": "EmbeddedButtonSize | undefined",
|
|
12550
13078
|
"required": false,
|
|
12551
13079
|
"description": ""
|
|
12552
13080
|
},
|
|
@@ -12558,7 +13086,7 @@
|
|
|
12558
13086
|
},
|
|
12559
13087
|
{
|
|
12560
13088
|
"name": "view",
|
|
12561
|
-
"type": "
|
|
13089
|
+
"type": "EmbeddedButtonView | undefined",
|
|
12562
13090
|
"required": false,
|
|
12563
13091
|
"description": ""
|
|
12564
13092
|
}
|
|
@@ -13673,17 +14201,17 @@
|
|
|
13673
14201
|
"examples": [
|
|
13674
14202
|
{
|
|
13675
14203
|
"exportName": "Usage1",
|
|
13676
|
-
"displayName": "Использование в
|
|
14204
|
+
"displayName": "Использование в TableCanvas.bottomSheet.basic.tsx",
|
|
13677
14205
|
"type": "usage",
|
|
13678
|
-
"code": "<IconButton\n
|
|
13679
|
-
"sourceFile": "packages/storybook/src/stories/
|
|
14206
|
+
"code": "<IconButton\n size=\"xxs\"\n view=\"clear\"\n aria-label={expanded ? 'Закрыть лог' : 'Открыть лог'}\n aria-expanded={expanded}\n aria-controls={contentId}\n style={{ flexShrink: 0 }}\n onClick={() => setHeight(expanded ? 32 : 220)}\n >\n {expanded ? (\n <IconChevronDown size=\"xs\" />\n ) : (\n <IconChevronUp size=\"xs\" />\n )}\n </IconButton>",
|
|
14207
|
+
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.BottomSheet/TableCanvas.bottomSheet.basic.tsx"
|
|
13680
14208
|
},
|
|
13681
14209
|
{
|
|
13682
14210
|
"exportName": "Usage2",
|
|
13683
|
-
"displayName": "Использование в
|
|
14211
|
+
"displayName": "Использование в TableCanvas.bottomSheet.auto.tsx",
|
|
13684
14212
|
"type": "usage",
|
|
13685
|
-
"code": "<IconButton\n
|
|
13686
|
-
"sourceFile": "packages/storybook/src/stories/
|
|
14213
|
+
"code": "<IconButton\n size=\"xxs\"\n view=\"clear\"\n aria-label={\n expanded ? 'Закрыть авто-панель' : 'Открыть авто-панель'\n }\n aria-expanded={expanded}\n aria-controls={contentId}\n style={{ flexShrink: 0 }}\n onClick={() => setExpanded((value) => !value)}\n >\n {expanded ? (\n <IconChevronDown size=\"xs\" />\n ) : (\n <IconChevronUp size=\"xs\" />\n )}\n </IconButton>",
|
|
14214
|
+
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.BottomSheet/TableCanvas.bottomSheet.auto.tsx"
|
|
13687
14215
|
},
|
|
13688
14216
|
{
|
|
13689
14217
|
"exportName": "Vendor1",
|
|
@@ -16608,6 +17136,14 @@
|
|
|
16608
17136
|
"inheritedFrom": "Modal",
|
|
16609
17137
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
16610
17138
|
},
|
|
17139
|
+
{
|
|
17140
|
+
"name": "size",
|
|
17141
|
+
"type": "string",
|
|
17142
|
+
"required": false,
|
|
17143
|
+
"description": "Размер модального окна.",
|
|
17144
|
+
"inheritedFrom": "Modal",
|
|
17145
|
+
"inheritedPackage": "@salutejs/sdds-finai"
|
|
17146
|
+
},
|
|
16611
17147
|
{
|
|
16612
17148
|
"name": "withAnimation",
|
|
16613
17149
|
"type": "boolean",
|
|
@@ -16646,13 +17182,6 @@
|
|
|
16646
17182
|
"inheritedFrom": "Modal",
|
|
16647
17183
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
16648
17184
|
},
|
|
16649
|
-
{
|
|
16650
|
-
"name": "size",
|
|
16651
|
-
"type": "string",
|
|
16652
|
-
"required": false,
|
|
16653
|
-
"inheritedFrom": "Modal",
|
|
16654
|
-
"inheritedPackage": "@salutejs/sdds-finai"
|
|
16655
|
-
},
|
|
16656
17185
|
{
|
|
16657
17186
|
"name": "view",
|
|
16658
17187
|
"type": "string",
|
|
@@ -18324,6 +18853,14 @@
|
|
|
18324
18853
|
"inheritedFrom": "Modal",
|
|
18325
18854
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
18326
18855
|
},
|
|
18856
|
+
{
|
|
18857
|
+
"name": "size",
|
|
18858
|
+
"type": "string",
|
|
18859
|
+
"required": false,
|
|
18860
|
+
"description": "Размер модального окна.",
|
|
18861
|
+
"inheritedFrom": "Modal",
|
|
18862
|
+
"inheritedPackage": "@salutejs/sdds-finai"
|
|
18863
|
+
},
|
|
18327
18864
|
{
|
|
18328
18865
|
"name": "withAnimation",
|
|
18329
18866
|
"type": "boolean",
|
|
@@ -18369,13 +18906,6 @@
|
|
|
18369
18906
|
"inheritedFrom": "Modal",
|
|
18370
18907
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
18371
18908
|
},
|
|
18372
|
-
{
|
|
18373
|
-
"name": "size",
|
|
18374
|
-
"type": "string",
|
|
18375
|
-
"required": false,
|
|
18376
|
-
"inheritedFrom": "Modal",
|
|
18377
|
-
"inheritedPackage": "@salutejs/sdds-finai"
|
|
18378
|
-
},
|
|
18379
18909
|
{
|
|
18380
18910
|
"name": "view",
|
|
18381
18911
|
"type": "string",
|
|
@@ -18815,6 +19345,14 @@
|
|
|
18815
19345
|
"inheritedFrom": "Modal",
|
|
18816
19346
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
18817
19347
|
},
|
|
19348
|
+
{
|
|
19349
|
+
"name": "size",
|
|
19350
|
+
"type": "string",
|
|
19351
|
+
"required": false,
|
|
19352
|
+
"description": "Размер модального окна.",
|
|
19353
|
+
"inheritedFrom": "Modal",
|
|
19354
|
+
"inheritedPackage": "@salutejs/sdds-finai"
|
|
19355
|
+
},
|
|
18818
19356
|
{
|
|
18819
19357
|
"name": "view",
|
|
18820
19358
|
"type": "string",
|
|
@@ -18867,13 +19405,6 @@
|
|
|
18867
19405
|
"required": false,
|
|
18868
19406
|
"inheritedFrom": "Modal",
|
|
18869
19407
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
18870
|
-
},
|
|
18871
|
-
{
|
|
18872
|
-
"name": "size",
|
|
18873
|
-
"type": "string",
|
|
18874
|
-
"required": false,
|
|
18875
|
-
"inheritedFrom": "Modal",
|
|
18876
|
-
"inheritedPackage": "@salutejs/sdds-finai"
|
|
18877
19408
|
}
|
|
18878
19409
|
],
|
|
18879
19410
|
"atomicMcpVersion": "0.360.0",
|
|
@@ -19168,7 +19699,14 @@
|
|
|
19168
19699
|
"folderName": "Note",
|
|
19169
19700
|
"role": "primary",
|
|
19170
19701
|
"description": "Блок с информационным, предупреждающим или обычным текстовым примечанием",
|
|
19171
|
-
"props": [
|
|
19702
|
+
"props": [
|
|
19703
|
+
{
|
|
19704
|
+
"name": "contentAfter",
|
|
19705
|
+
"type": "React.ReactNode",
|
|
19706
|
+
"required": false,
|
|
19707
|
+
"description": ""
|
|
19708
|
+
}
|
|
19709
|
+
],
|
|
19172
19710
|
"propsTypeName": "ComponentProps<typeof Note>",
|
|
19173
19711
|
"sourceFile": "node_modules/@salutejs/sdds-finai/types/components/Note/Note.d.ts",
|
|
19174
19712
|
"type": "wrapper",
|
|
@@ -19519,6 +20057,12 @@
|
|
|
19519
20057
|
"role": "primary",
|
|
19520
20058
|
"description": "Провайдер контейнера для показа toast-уведомлений на странице",
|
|
19521
20059
|
"props": [
|
|
20060
|
+
{
|
|
20061
|
+
"name": "defaultNotificationArgs",
|
|
20062
|
+
"type": "NotificationDefaultArgs<NotificationProps> | undefined",
|
|
20063
|
+
"required": false,
|
|
20064
|
+
"description": ""
|
|
20065
|
+
},
|
|
19522
20066
|
{
|
|
19523
20067
|
"name": "frame",
|
|
19524
20068
|
"type": "string | undefined",
|
|
@@ -21495,7 +22039,7 @@
|
|
|
21495
22039
|
},
|
|
21496
22040
|
{
|
|
21497
22041
|
"name": "resizable",
|
|
21498
|
-
"type": "boolean |
|
|
22042
|
+
"type": "boolean | ResizableOptions | undefined",
|
|
21499
22043
|
"required": false,
|
|
21500
22044
|
"description": "Настройка resizable-режима.",
|
|
21501
22045
|
"default": "false"
|
|
@@ -21507,12 +22051,6 @@
|
|
|
21507
22051
|
"description": "Смещение всплывающего окна при соприкосновении с границами экрана.",
|
|
21508
22052
|
"default": "false"
|
|
21509
22053
|
},
|
|
21510
|
-
{
|
|
21511
|
-
"name": "size",
|
|
21512
|
-
"type": "\"s\" | \"m\" | undefined",
|
|
21513
|
-
"required": false,
|
|
21514
|
-
"description": "Размер компонента."
|
|
21515
|
-
},
|
|
21516
22054
|
{
|
|
21517
22055
|
"name": "trigger",
|
|
21518
22056
|
"type": "\"hover\" | \"click\" | \"focus\" | undefined",
|
|
@@ -21520,12 +22058,6 @@
|
|
|
21520
22058
|
"description": "Способ скрытия/раскрытия всплывающего окна.",
|
|
21521
22059
|
"default": "click"
|
|
21522
22060
|
},
|
|
21523
|
-
{
|
|
21524
|
-
"name": "view",
|
|
21525
|
-
"type": "\"action\" | \"info\" | undefined",
|
|
21526
|
-
"required": false,
|
|
21527
|
-
"description": "Вид компонента."
|
|
21528
|
-
},
|
|
21529
22061
|
{
|
|
21530
22062
|
"name": "zIndex",
|
|
21531
22063
|
"type": "number | undefined",
|
|
@@ -21538,6 +22070,18 @@
|
|
|
21538
22070
|
"type": "\"default\" | \"closeInner\" | undefined",
|
|
21539
22071
|
"required": false,
|
|
21540
22072
|
"description": ""
|
|
22073
|
+
},
|
|
22074
|
+
{
|
|
22075
|
+
"name": "size",
|
|
22076
|
+
"type": "\"s\" | \"m\" | undefined",
|
|
22077
|
+
"required": false,
|
|
22078
|
+
"description": ""
|
|
22079
|
+
},
|
|
22080
|
+
{
|
|
22081
|
+
"name": "view",
|
|
22082
|
+
"type": "\"action\" | \"info\" | undefined",
|
|
22083
|
+
"required": false,
|
|
22084
|
+
"description": ""
|
|
21541
22085
|
}
|
|
21542
22086
|
],
|
|
21543
22087
|
"propsTypeName": "PopoverBetaCompProps",
|
|
@@ -22368,7 +22912,7 @@
|
|
|
22368
22912
|
},
|
|
22369
22913
|
{
|
|
22370
22914
|
"name": "resizable",
|
|
22371
|
-
"type": "boolean |
|
|
22915
|
+
"type": "boolean | ResizableOptions | undefined",
|
|
22372
22916
|
"required": false,
|
|
22373
22917
|
"description": "Настройка resizable-режима.",
|
|
22374
22918
|
"default": "false"
|
|
@@ -22387,18 +22931,18 @@
|
|
|
22387
22931
|
"description": "Способ скрытия/раскрытия всплывающего окна.",
|
|
22388
22932
|
"default": "click"
|
|
22389
22933
|
},
|
|
22390
|
-
{
|
|
22391
|
-
"name": "view",
|
|
22392
|
-
"type": "\"action\" | \"info\" | undefined",
|
|
22393
|
-
"required": false,
|
|
22394
|
-
"description": "Вид компонента."
|
|
22395
|
-
},
|
|
22396
22934
|
{
|
|
22397
22935
|
"name": "zIndex",
|
|
22398
22936
|
"type": "number | undefined",
|
|
22399
22937
|
"required": false,
|
|
22400
22938
|
"description": "CSS-свойство z-index всплывающего окна.",
|
|
22401
22939
|
"default": "1000"
|
|
22940
|
+
},
|
|
22941
|
+
{
|
|
22942
|
+
"name": "view",
|
|
22943
|
+
"type": "\"action\" | \"info\" | undefined",
|
|
22944
|
+
"required": false,
|
|
22945
|
+
"description": ""
|
|
22402
22946
|
}
|
|
22403
22947
|
],
|
|
22404
22948
|
"propsTypeName": "PopoverDFProps",
|
|
@@ -23094,10 +23638,10 @@
|
|
|
23094
23638
|
},
|
|
23095
23639
|
{
|
|
23096
23640
|
"exportName": "Usage2",
|
|
23097
|
-
"displayName": "Использование в
|
|
23641
|
+
"displayName": "Использование в AiAgentPopup.stories.tsx",
|
|
23098
23642
|
"type": "usage",
|
|
23099
|
-
"code": "<PopupProvider>\n <
|
|
23100
|
-
"sourceFile": "packages/storybook/src/stories/
|
|
23643
|
+
"code": "<PopupProvider>\n <div\n ref={frameRef}\n style={fullHeight ? fullHeightStageStyle : stageStyle}\n >\n <Sidebar\n sidebarRef={sidebarRef}\n targetRef={targetRef}\n onToggle={() => setOpened(!opened)}\n />\n <AiAgentPopup\n // Пока окно не умеет само расширяться при открытии раздела,\n // стартуем шире размера по умолчанию\n defaultSize={{ width: 680, height: 540 }}\n {...popupArgs}\n opened={opened}\n targetRef={targetRef}\n frame={frameRef}\n leftPanel={{\n items: leftPanelItems,\n activeKey: activeSection,\n onActiveKeyChange: setActiveSection,\n }}\n dragBoundary={{\n top: 8,\n right: 8,\n bottom: 8,\n ...dragBoundary,\n left: sidebarWidth + (dragBoundary?.left ?? 0),\n }}\n >\n <ChatContent\n messages={messages}\n draft={draft}\n glow={glow}\n onDraftChange={setDraft}\n onSend={sendDraft}\n onClose={() => setOpened(false)}\n />\n </AiAgentPopup>\n </div>\n </PopupProvider>",
|
|
23644
|
+
"sourceFile": "packages/storybook/src/stories/AiAgentPopup/AiAgentPopup.stories.tsx"
|
|
23101
23645
|
},
|
|
23102
23646
|
{
|
|
23103
23647
|
"exportName": "Vendor1",
|
|
@@ -25993,10 +26537,10 @@
|
|
|
25993
26537
|
},
|
|
25994
26538
|
{
|
|
25995
26539
|
"exportName": "Usage2",
|
|
25996
|
-
"displayName": "Использование в
|
|
26540
|
+
"displayName": "Использование в AiAgentPopup.stories.tsx",
|
|
25997
26541
|
"type": "usage",
|
|
25998
|
-
"code": "<SSRProvider>\n <PopupProvider>\n <
|
|
25999
|
-
"sourceFile": "packages/storybook/src/stories/
|
|
26542
|
+
"code": "<SSRProvider>\n <PopupProvider>\n <div\n ref={frameRef}\n style={fullHeight ? fullHeightStageStyle : stageStyle}\n >\n <Sidebar\n sidebarRef={sidebarRef}\n targetRef={targetRef}\n onToggle={() => setOpened(!opened)}\n />\n <AiAgentPopup\n // Пока окно не умеет само расширяться при открытии раздела,\n // стартуем шире размера по умолчанию\n defaultSize={{ width: 680, height: 540 }}\n {...popupArgs}\n opened={opened}\n targetRef={targetRef}\n frame={frameRef}\n leftPanel={{\n items: leftPanelItems,\n activeKey: activeSection,\n onActiveKeyChange: setActiveSection,\n }}\n dragBoundary={{\n top: 8,\n right: 8,\n bottom: 8,\n ...dragBoundary,\n left: sidebarWidth + (dragBoundary?.left ?? 0),\n }}\n >\n <ChatContent\n messages={messages}\n draft={draft}\n glow={glow}\n onDraftChange={setDraft}\n onSend={sendDraft}\n onClose={() => setOpened(false)}\n />\n </AiAgentPopup>\n </div>\n </PopupProvider>\n </SSRProvider>",
|
|
26543
|
+
"sourceFile": "packages/storybook/src/stories/AiAgentPopup/AiAgentPopup.stories.tsx"
|
|
26000
26544
|
}
|
|
26001
26545
|
]
|
|
26002
26546
|
},
|
|
@@ -26413,6 +26957,12 @@
|
|
|
26413
26957
|
"role": "primary",
|
|
26414
26958
|
"description": "Выпадающий список для выбора одного или нескольких значений из перечня",
|
|
26415
26959
|
"props": [
|
|
26960
|
+
{
|
|
26961
|
+
"name": "sortItems",
|
|
26962
|
+
"type": "((a: SelectItemOption, b: SelectItemOption) => number) | undefined",
|
|
26963
|
+
"required": false,
|
|
26964
|
+
"description": "Компаратор сортировки элементов первого уровня.\nВложенные списки и исходный массив items не изменяются."
|
|
26965
|
+
},
|
|
26416
26966
|
{
|
|
26417
26967
|
"name": "type",
|
|
26418
26968
|
"type": "\"submit\" | \"reset\" | \"button\" | undefined",
|
|
@@ -29469,6 +30019,12 @@
|
|
|
29469
30019
|
"required": true,
|
|
29470
30020
|
"description": ""
|
|
29471
30021
|
},
|
|
30022
|
+
{
|
|
30023
|
+
"name": "sortItems",
|
|
30024
|
+
"type": "((a: T, b: T) => number) | undefined",
|
|
30025
|
+
"required": false,
|
|
30026
|
+
"description": "Компаратор сортировки элементов первого уровня.\nВложенные списки и исходный массив items не изменяются."
|
|
30027
|
+
},
|
|
29472
30028
|
{
|
|
29473
30029
|
"name": "disableLeftOffset",
|
|
29474
30030
|
"type": "boolean | undefined",
|
|
@@ -29535,6 +30091,14 @@
|
|
|
29535
30091
|
"inheritedFrom": "Combobox",
|
|
29536
30092
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
29537
30093
|
},
|
|
30094
|
+
{
|
|
30095
|
+
"name": "appearance",
|
|
30096
|
+
"type": "\"default\" | \"viewMode\"",
|
|
30097
|
+
"required": false,
|
|
30098
|
+
"description": "Стиль для UI конфигурации\nВлияет на выбор предустановленного набора токенов",
|
|
30099
|
+
"inheritedFrom": "Combobox",
|
|
30100
|
+
"inheritedPackage": "@salutejs/sdds-finai"
|
|
30101
|
+
},
|
|
29538
30102
|
{
|
|
29539
30103
|
"name": "arrowPlacement",
|
|
29540
30104
|
"type": "\"right\" | \"left\"",
|
|
@@ -29610,6 +30174,14 @@
|
|
|
29610
30174
|
"inheritedFrom": "Combobox",
|
|
29611
30175
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
29612
30176
|
},
|
|
30177
|
+
{
|
|
30178
|
+
"name": "hasDivider",
|
|
30179
|
+
"type": "boolean",
|
|
30180
|
+
"required": false,
|
|
30181
|
+
"description": "отобразить ли divider",
|
|
30182
|
+
"inheritedFrom": "Combobox",
|
|
30183
|
+
"inheritedPackage": "@salutejs/sdds-finai"
|
|
30184
|
+
},
|
|
29613
30185
|
{
|
|
29614
30186
|
"name": "hasRequiredIndicator",
|
|
29615
30187
|
"type": "boolean",
|
|
@@ -29908,13 +30480,6 @@
|
|
|
29908
30480
|
"inheritedFrom": "Combobox",
|
|
29909
30481
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
29910
30482
|
},
|
|
29911
|
-
{
|
|
29912
|
-
"name": "appearance",
|
|
29913
|
-
"type": "\"default\" | \"viewMode\"",
|
|
29914
|
-
"required": false,
|
|
29915
|
-
"inheritedFrom": "Combobox",
|
|
29916
|
-
"inheritedPackage": "@salutejs/sdds-finai"
|
|
29917
|
-
},
|
|
29918
30483
|
{
|
|
29919
30484
|
"name": "chipClickArea",
|
|
29920
30485
|
"type": "\"full\" | \"close-icon\"",
|
|
@@ -29943,13 +30508,6 @@
|
|
|
29943
30508
|
"inheritedFrom": "Combobox",
|
|
29944
30509
|
"inheritedPackage": "@salutejs/sdds-finai"
|
|
29945
30510
|
},
|
|
29946
|
-
{
|
|
29947
|
-
"name": "hasDivider",
|
|
29948
|
-
"type": "boolean",
|
|
29949
|
-
"required": false,
|
|
29950
|
-
"inheritedFrom": "Combobox",
|
|
29951
|
-
"inheritedPackage": "@salutejs/sdds-finai"
|
|
29952
|
-
},
|
|
29953
30511
|
{
|
|
29954
30512
|
"name": "hintSize",
|
|
29955
30513
|
"type": "\"s\" | \"m\"",
|
|
@@ -30731,17 +31289,17 @@
|
|
|
30731
31289
|
"examples": [
|
|
30732
31290
|
{
|
|
30733
31291
|
"exportName": "Usage1",
|
|
30734
|
-
"displayName": "Использование в TableCanvas.
|
|
31292
|
+
"displayName": "Использование в TableCanvas.bottomSheet.example.tsx",
|
|
30735
31293
|
"type": "usage",
|
|
30736
|
-
"code": "<TableCanvas\n
|
|
30737
|
-
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.
|
|
31294
|
+
"code": "<TableCanvas\n refTable={options.refTable}\n rows={rowsForTable}\n columnConfig={columns}\n tableConfig={tableConfig}\n bottomSummaryRows={summaryRows}\n headerContextValue={{\n issueTypeOptions: ['Bug', 'Improvement', 'Epic', 'Story'].map(\n (value) => ({ value, text: value }),\n ),\n }}\n />",
|
|
31295
|
+
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.BottomSheet/TableCanvas.bottomSheet.example.tsx"
|
|
30738
31296
|
},
|
|
30739
31297
|
{
|
|
30740
31298
|
"exportName": "Usage2",
|
|
30741
|
-
"displayName": "Использование в TableCanvas.
|
|
31299
|
+
"displayName": "Использование в TableCanvas.summaryRows.stories.tsx",
|
|
30742
31300
|
"type": "usage",
|
|
30743
|
-
"code": "<TableCanvas\n
|
|
30744
|
-
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.
|
|
31301
|
+
"code": "<TableCanvas\n key={tableKey}\n tableConfig={{\n containerStyle: { height: '600px' },\n summaryRows: {\n showDefault,\n showInControl: true,\n onChange: handleSummaryRowsChange,\n domMetadata: {\n dataAttributes: { 'data-testid': TEST_ID.switch },\n },\n },\n sidebarConfig: {\n defaultTabs: [\n {\n id: 'tableSettings',\n domMetadata: {\n dataAttributes: { 'data-testid': TEST_ID.settingsTab },\n },\n },\n ],\n },\n }}\n columnConfig={columnConfig}\n bottomSummaryRows={bottomSummaryRowsData}\n rows={rows}\n />",
|
|
31302
|
+
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.SummaryRows/TableCanvas.summaryRows.stories.tsx"
|
|
30745
31303
|
}
|
|
30746
31304
|
]
|
|
30747
31305
|
},
|
|
@@ -30806,12 +31364,6 @@
|
|
|
30806
31364
|
"required": false,
|
|
30807
31365
|
"description": "Индексы строк, выбранных через checkbox selection."
|
|
30808
31366
|
},
|
|
30809
|
-
{
|
|
30810
|
-
"name": "checkboxVisibleRowIndexes",
|
|
30811
|
-
"type": "ReadonlySet<number> | undefined",
|
|
30812
|
-
"required": false,
|
|
30813
|
-
"description": "Индексы строк, у которых ЕСТЬ (виден) чекбокс — для тёмной подсветки highlightActiveType='row'."
|
|
30814
|
-
},
|
|
30815
31367
|
{
|
|
30816
31368
|
"name": "coercePasteValue",
|
|
30817
31369
|
"type": "((val: string, cell: GridCell) => GridCell | undefined) | undefined",
|
|
@@ -30848,6 +31400,12 @@
|
|
|
30848
31400
|
"required": false,
|
|
30849
31401
|
"description": "Внешний ref на wrapper-div (для TableCanvas - refTableContainer)"
|
|
30850
31402
|
},
|
|
31403
|
+
{
|
|
31404
|
+
"name": "containerSlot",
|
|
31405
|
+
"type": "React.ReactNode",
|
|
31406
|
+
"required": false,
|
|
31407
|
+
"description": "Дополнительный контент wrapper-div, не зависящий от готовности canvas-grid."
|
|
31408
|
+
},
|
|
30851
31409
|
{
|
|
30852
31410
|
"name": "containerStyle",
|
|
30853
31411
|
"type": "React.CSSProperties | undefined",
|
|
@@ -31051,7 +31609,7 @@
|
|
|
31051
31609
|
"name": "hoverEffects",
|
|
31052
31610
|
"type": "HoverEffectsConfig | undefined",
|
|
31053
31611
|
"required": false,
|
|
31054
|
-
"description": "Эффекты при наведении. `hoverEffects.row` — подсветка строки под курсором:\nрисуется через bgCell (getRowThemeOverride), т.е. лежит ПОД селектингом и\nhighlightActiveType — они рисуются поверх (highlightRegions) и визуально\nперекрывают hover. По умолчанию
|
|
31612
|
+
"description": "Эффекты при наведении. `hoverEffects.row` — подсветка строки под курсором:\nрисуется через bgCell (getRowThemeOverride), т.е. лежит ПОД селектингом и\nhighlightActiveType — они рисуются поверх (highlightRegions) и визуально\nперекрывают hover. По умолчанию row-подсветка ВКЛЮЧЕНА; выключение —\nявное `{ row: false }`."
|
|
31055
31613
|
},
|
|
31056
31614
|
{
|
|
31057
31615
|
"name": "imageEditorOverride",
|
|
@@ -31521,6 +32079,18 @@
|
|
|
31521
32079
|
"required": false,
|
|
31522
32080
|
"description": "Объединяет (rowspan) пустые нижние ряды у «мелких» групп — тех, что заканчиваются\nвыше самого глубокого уровня групп, — в одну высокую ячейку вместо пустой полосы\nпод заголовком. Точечно на группе можно переопределить через `getGroupDetails().span`\n(поставить `false`, чтобы отключить для конкретной группы). Не задано → как раньше."
|
|
31523
32081
|
},
|
|
32082
|
+
{
|
|
32083
|
+
"name": "stickyColumns",
|
|
32084
|
+
"type": "readonly number[] | undefined",
|
|
32085
|
+
"required": false,
|
|
32086
|
+
"description": "Липкие колонки, например `[0, 3, 10]`. Колонка стоит на своём месте, пока при прокрутке не дойдёт\nдо закреплённой зоны слева, и дальше остаётся в ней, как `position: sticky`. Сочетается с\n`freezeColumns`. Индексы считаются без колонки маркеров строк."
|
|
32087
|
+
},
|
|
32088
|
+
{
|
|
32089
|
+
"name": "stickyRows",
|
|
32090
|
+
"type": "readonly number[] | undefined",
|
|
32091
|
+
"required": false,
|
|
32092
|
+
"description": "Липкие строки, например `[0, 5, 40]`. Строка прилипает под шапкой (и под уже прилипшими строками),\nкогда при прокрутке доходит до них, как `position: sticky`."
|
|
32093
|
+
},
|
|
31524
32094
|
{
|
|
31525
32095
|
"name": "trailingRowOptions",
|
|
31526
32096
|
"type": "{ readonly tint?: boolean | undefined; readonly hint?: string | undefined; readonly sticky?: boolean | undefined; readonly addIcon?: string | undefined; readonly targetColumn?: number | GridColumn | undefined; } | undefined",
|
|
@@ -31593,6 +32163,18 @@
|
|
|
31593
32163
|
"required": false,
|
|
31594
32164
|
"description": ""
|
|
31595
32165
|
},
|
|
32166
|
+
{
|
|
32167
|
+
"name": "stickyColumnsConfig",
|
|
32168
|
+
"type": "StickyColumnsConfig<ColumnGlideInstance<R, SR, CustomCtxs>> | undefined",
|
|
32169
|
+
"required": false,
|
|
32170
|
+
"description": ""
|
|
32171
|
+
},
|
|
32172
|
+
{
|
|
32173
|
+
"name": "stickyRowsConfig",
|
|
32174
|
+
"type": "StickyRowsConfig<R> | undefined",
|
|
32175
|
+
"required": false,
|
|
32176
|
+
"description": ""
|
|
32177
|
+
},
|
|
31596
32178
|
{
|
|
31597
32179
|
"name": "bottomSummaryRows",
|
|
31598
32180
|
"type": "readonly SR[] | undefined",
|
|
@@ -31695,6 +32277,13 @@
|
|
|
31695
32277
|
"required": false,
|
|
31696
32278
|
"description": ""
|
|
31697
32279
|
},
|
|
32280
|
+
{
|
|
32281
|
+
"name": "checkboxVisibleRowIndexes",
|
|
32282
|
+
"type": "ReadonlySet<number> | undefined",
|
|
32283
|
+
"required": false,
|
|
32284
|
+
"description": "Индексы строк, у которых ЕСТЬ (виден) чекбокс.",
|
|
32285
|
+
"deprecated": true
|
|
32286
|
+
},
|
|
31698
32287
|
{
|
|
31699
32288
|
"name": "rowMarkerStartIndex",
|
|
31700
32289
|
"type": "number | undefined",
|
|
@@ -31718,7 +32307,7 @@
|
|
|
31718
32307
|
}
|
|
31719
32308
|
],
|
|
31720
32309
|
"propsTypeName": "TableGlideInstanceProps",
|
|
31721
|
-
"rawType": "export type TableGlideInstanceProps<\n R extends ObjectForExtending,\n SR = unknown,\n CustomCtxs extends ObjectForExtending = {},\n> = Omit<\n TableGlideProps<R, SR>,\n 'columns' | 'onHeaderContextMenu' | 'onCellContextMenu'\n> & {\n columns: readonly ColumnGlideInstance<R, SR, CustomCtxs>[];\n onHeaderContextMenuDropdown?: HeaderContextMenuDropdownProps<\n R,\n SR,\n CustomCtxs\n >;\n onCellContextMenuDropdown?: CellContextMenuDropdownProps<R, SR>;\n containerProps?: {\n className?: string;\n style?: React.CSSProperties;\n ref?: React.Ref<HTMLDivElement>;\n };\n contentStateOverlay?: TableContentStateOverlay;\n renderOverlayFeatures?: (ctx: {\n containerElement: HTMLDivElement;\n renderInContainer: (children: React.ReactNode) => React.ReactPortal | null;\n }) => React.ReactNode;\n CellReadOnlyEditor: (\n props: CellReadOnlyEditorGlideInstanceProps<R, SR>,\n ) => ReactNode;\n onRowsChange?: (\n rows: R[],\n data: RowsChangeDataGlideInstance<R, SR, CustomCtxs>,\n ) => void;\n onCellClicked?: (\n cell: readonly [number, number],\n info: TableInfoWithRow<R, SR, CustomCtxs>,\n ) => void;\n} & TableGlideInstanceContextMenu<R, SR, CustomCtxs>;",
|
|
32310
|
+
"rawType": "export type TableGlideInstanceProps<\n R extends ObjectForExtending,\n SR = unknown,\n CustomCtxs extends ObjectForExtending = {},\n> = Omit<\n TableGlideProps<R, SR>,\n 'columns' | 'onHeaderContextMenu' | 'onCellContextMenu'\n> & {\n columns: readonly ColumnGlideInstance<R, SR, CustomCtxs>[];\n onHeaderContextMenuDropdown?: HeaderContextMenuDropdownProps<\n R,\n SR,\n CustomCtxs\n >;\n onCellContextMenuDropdown?: CellContextMenuDropdownProps<R, SR>;\n containerProps?: {\n className?: string;\n style?: React.CSSProperties;\n ref?: React.Ref<HTMLDivElement>;\n };\n contentStateOverlay?: TableContentStateOverlay;\n renderOverlayFeatures?: (ctx: {\n containerElement: HTMLDivElement;\n renderInContainer: (children: React.ReactNode) => React.ReactPortal | null;\n }) => React.ReactNode;\n CellReadOnlyEditor: (\n props: CellReadOnlyEditorGlideInstanceProps<R, SR>,\n ) => ReactNode;\n onRowsChange?: (\n rows: R[],\n data: RowsChangeDataGlideInstance<R, SR, CustomCtxs>,\n ) => void;\n onCellClicked?: (\n cell: readonly [number, number],\n info: TableInfoWithRow<R, SR, CustomCtxs>,\n ) => void;\n stickyColumnsConfig?: StickyColumnsConfig<\n ColumnGlideInstance<R, SR, CustomCtxs>\n >;\n stickyRowsConfig?: StickyRowsConfig<R>;\n} & TableGlideInstanceContextMenu<R, SR, CustomCtxs>;",
|
|
31722
32311
|
"isGeneric": true,
|
|
31723
32312
|
"sourceFile": "packages/ui-kit/src/components/TableCanvas/TableGlideInstance/TableGlideInstance.tsx",
|
|
31724
32313
|
"type": "composition",
|
|
@@ -32119,12 +32708,6 @@
|
|
|
32119
32708
|
"required": false,
|
|
32120
32709
|
"description": "Индексы строк, выбранных через checkbox selection."
|
|
32121
32710
|
},
|
|
32122
|
-
{
|
|
32123
|
-
"name": "checkboxVisibleRowIndexes",
|
|
32124
|
-
"type": "ReadonlySet<number> | undefined",
|
|
32125
|
-
"required": false,
|
|
32126
|
-
"description": "Индексы строк, у которых ЕСТЬ (виден) чекбокс — для тёмной подсветки highlightActiveType='row'."
|
|
32127
|
-
},
|
|
32128
32711
|
{
|
|
32129
32712
|
"name": "containerClassName",
|
|
32130
32713
|
"type": "string | undefined",
|
|
@@ -32137,6 +32720,12 @@
|
|
|
32137
32720
|
"required": false,
|
|
32138
32721
|
"description": "Внешний ref на wrapper-div (для TableCanvas - refTableContainer)"
|
|
32139
32722
|
},
|
|
32723
|
+
{
|
|
32724
|
+
"name": "containerSlot",
|
|
32725
|
+
"type": "React.ReactNode",
|
|
32726
|
+
"required": false,
|
|
32727
|
+
"description": "Дополнительный контент wrapper-div, не зависящий от готовности canvas-grid."
|
|
32728
|
+
},
|
|
32140
32729
|
{
|
|
32141
32730
|
"name": "containerStyle",
|
|
32142
32731
|
"type": "React.CSSProperties | undefined",
|
|
@@ -32223,7 +32812,7 @@
|
|
|
32223
32812
|
"name": "hoverEffects",
|
|
32224
32813
|
"type": "HoverEffectsConfig | undefined",
|
|
32225
32814
|
"required": false,
|
|
32226
|
-
"description": "Эффекты при наведении. `hoverEffects.row` — подсветка строки под курсором:\nрисуется через bgCell (getRowThemeOverride), т.е. лежит ПОД селектингом и\nhighlightActiveType — они рисуются поверх (highlightRegions) и визуально\nперекрывают hover. По умолчанию
|
|
32815
|
+
"description": "Эффекты при наведении. `hoverEffects.row` — подсветка строки под курсором:\nрисуется через bgCell (getRowThemeOverride), т.е. лежит ПОД селектингом и\nhighlightActiveType — они рисуются поверх (highlightRegions) и визуально\nперекрывают hover. По умолчанию row-подсветка ВКЛЮЧЕНА; выключение —\nявное `{ row: false }`."
|
|
32227
32816
|
},
|
|
32228
32817
|
{
|
|
32229
32818
|
"name": "onColumnSelectionApplied",
|
|
@@ -32880,6 +33469,18 @@
|
|
|
32880
33469
|
"required": false,
|
|
32881
33470
|
"description": "Объединяет (rowspan) пустые нижние ряды у «мелких» групп — тех, что заканчиваются\nвыше самого глубокого уровня групп, — в одну высокую ячейку вместо пустой полосы\nпод заголовком. Точечно на группе можно переопределить через `getGroupDetails().span`\n(поставить `false`, чтобы отключить для конкретной группы). Не задано → как раньше."
|
|
32882
33471
|
},
|
|
33472
|
+
{
|
|
33473
|
+
"name": "stickyColumns",
|
|
33474
|
+
"type": "readonly number[] | undefined",
|
|
33475
|
+
"required": false,
|
|
33476
|
+
"description": "Липкие колонки, например `[0, 3, 10]`. Колонка стоит на своём месте, пока при прокрутке не дойдёт\nдо закреплённой зоны слева, и дальше остаётся в ней, как `position: sticky`. Сочетается с\n`freezeColumns`. Индексы считаются без колонки маркеров строк."
|
|
33477
|
+
},
|
|
33478
|
+
{
|
|
33479
|
+
"name": "stickyRows",
|
|
33480
|
+
"type": "readonly number[] | undefined",
|
|
33481
|
+
"required": false,
|
|
33482
|
+
"description": "Липкие строки, например `[0, 5, 40]`. Строка прилипает под шапкой (и под уже прилипшими строками),\nкогда при прокрутке доходит до них, как `position: sticky`."
|
|
33483
|
+
},
|
|
32883
33484
|
{
|
|
32884
33485
|
"name": "trailingRowOptions",
|
|
32885
33486
|
"type": "{ readonly tint?: boolean | undefined; readonly hint?: string | undefined; readonly sticky?: boolean | undefined; readonly addIcon?: string | undefined; readonly targetColumn?: number | GridColumn | undefined; } | undefined",
|
|
@@ -33009,6 +33610,13 @@
|
|
|
33009
33610
|
"required": false,
|
|
33010
33611
|
"description": ""
|
|
33011
33612
|
},
|
|
33613
|
+
{
|
|
33614
|
+
"name": "checkboxVisibleRowIndexes",
|
|
33615
|
+
"type": "ReadonlySet<number> | undefined",
|
|
33616
|
+
"required": false,
|
|
33617
|
+
"description": "Индексы строк, у которых ЕСТЬ (виден) чекбокс.",
|
|
33618
|
+
"deprecated": true
|
|
33619
|
+
},
|
|
33012
33620
|
{
|
|
33013
33621
|
"name": "rowMarkerStartIndex",
|
|
33014
33622
|
"type": "number | undefined",
|
|
@@ -33746,10 +34354,10 @@
|
|
|
33746
34354
|
},
|
|
33747
34355
|
{
|
|
33748
34356
|
"exportName": "Usage2",
|
|
33749
|
-
"displayName": "Использование в TableCanvas.
|
|
34357
|
+
"displayName": "Использование в TableCanvas.stickyRowsCols.stories.tsx",
|
|
33750
34358
|
"type": "usage",
|
|
33751
|
-
"code": "<Canvas.Badge
|
|
33752
|
-
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.
|
|
34359
|
+
"code": "<Canvas.Badge text=\"Итог\" view=\"accent\" size=\"xs\" transparent />",
|
|
34360
|
+
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.StickyRowsCols/TableCanvas.stickyRowsCols.stories.tsx"
|
|
33753
34361
|
}
|
|
33754
34362
|
]
|
|
33755
34363
|
},
|
|
@@ -34315,7 +34923,14 @@
|
|
|
34315
34923
|
"minimalUsage": "<CanvasIconButton icon={{}} />",
|
|
34316
34924
|
"examples": [
|
|
34317
34925
|
{
|
|
34318
|
-
"exportName": "
|
|
34926
|
+
"exportName": "Usage1",
|
|
34927
|
+
"displayName": "Использование в TableCanvas.stickyRowsCols.stories.tsx",
|
|
34928
|
+
"type": "usage",
|
|
34929
|
+
"code": "<Canvas.IconButton\n icon={<IconEye color=\"#1d1d1f\" size=\"xs\" />}\n view=\"clear\"\n buttonSize=\"xs\"\n tooltip=\"Просмотр\"\n />",
|
|
34930
|
+
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.StickyRowsCols/TableCanvas.stickyRowsCols.stories.tsx"
|
|
34931
|
+
},
|
|
34932
|
+
{
|
|
34933
|
+
"exportName": "Usage2",
|
|
34319
34934
|
"displayName": "Использование в CanvasIconButton.stories.tsx",
|
|
34320
34935
|
"type": "usage",
|
|
34321
34936
|
"code": "<Canvas.IconButton\n icon={<IconSearch />}\n view={row.view}\n buttonSize={size}\n disabled={disabled}\n />",
|
|
@@ -34613,15 +35228,15 @@
|
|
|
34613
35228
|
"exportName": "Usage1",
|
|
34614
35229
|
"displayName": "Использование в CanvasLink.stories.tsx",
|
|
34615
35230
|
"type": "usage",
|
|
34616
|
-
"code": "<Canvas.Link\n view={row.view}\n href
|
|
35231
|
+
"code": "<Canvas.Link\n view={row.view}\n href=\"https://example.com\"\n target=\"_blank\"\n disabled={disabled}\n wordWrap\n maxLines={maxLines}\n lineHeight={lineHeight}\n overflow=\"hidden\"\n textOverflow=\"ellipsis\"\n autoTooltip\n style={{ flexGrow: 1 }}\n >\n {text}\n </Canvas.Link>",
|
|
34617
35232
|
"sourceFile": "packages/storybook/src/stories/TableCanvas/CanvasElements/CanvasLink/CanvasLink.stories.tsx"
|
|
34618
35233
|
},
|
|
34619
35234
|
{
|
|
34620
35235
|
"exportName": "Usage2",
|
|
34621
|
-
"displayName": "Использование в
|
|
35236
|
+
"displayName": "Использование в TableCanvas.stickyRowsCols.stories.tsx",
|
|
34622
35237
|
"type": "usage",
|
|
34623
|
-
"code": "<Canvas.Link
|
|
34624
|
-
"sourceFile": "packages/storybook/src/stories/TableCanvas/
|
|
35238
|
+
"code": "<Canvas.Link\n // Для примера\n // eslint-disable-next-line no-console\n onClick={() => console.log('Открыть менеджера', row.manager)}\n >\n {row.manager}\n </Canvas.Link>",
|
|
35239
|
+
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.StickyRowsCols/TableCanvas.stickyRowsCols.stories.tsx"
|
|
34625
35240
|
},
|
|
34626
35241
|
{
|
|
34627
35242
|
"exportName": "Vendor1",
|
|
@@ -34734,11 +35349,18 @@
|
|
|
34734
35349
|
"minimalUsage": "<CanvasRect />",
|
|
34735
35350
|
"examples": [
|
|
34736
35351
|
{
|
|
34737
|
-
"exportName": "
|
|
35352
|
+
"exportName": "Usage1",
|
|
34738
35353
|
"displayName": "Использование в CanvasImage.stories.tsx",
|
|
34739
35354
|
"type": "usage",
|
|
34740
35355
|
"code": "<Canvas.Rect\n position=\"absolute\"\n left={0}\n top={0}\n style={{ width: 88, height: 88 }}\n borderColor={theme.tokens.outlineAccent}\n borderWidth={1}\n zIndex={1}\n />",
|
|
34741
35356
|
"sourceFile": "packages/storybook/src/stories/TableCanvas/CanvasElements/CanvasImage/CanvasImage.stories.tsx"
|
|
35357
|
+
},
|
|
35358
|
+
{
|
|
35359
|
+
"exportName": "Usage2",
|
|
35360
|
+
"displayName": "Использование в TableCanvas.stickyRowsCols.stories.tsx",
|
|
35361
|
+
"type": "usage",
|
|
35362
|
+
"code": "<Canvas.Rect\n color={theme.tokens.textAccent}\n style={{ width: barWidth, height: 6 }}\n />",
|
|
35363
|
+
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.StickyRowsCols/TableCanvas.stickyRowsCols.stories.tsx"
|
|
34742
35364
|
}
|
|
34743
35365
|
]
|
|
34744
35366
|
},
|
|
@@ -35582,6 +36204,18 @@
|
|
|
35582
36204
|
"required": false,
|
|
35583
36205
|
"description": "Объединяет (rowspan) пустые нижние ряды у «мелких» групп — тех, что заканчиваются\nвыше самого глубокого уровня групп, — в одну высокую ячейку вместо пустой полосы\nпод заголовком. Точечно на группе можно переопределить через `getGroupDetails().span`\n(поставить `false`, чтобы отключить для конкретной группы). Не задано → как раньше."
|
|
35584
36206
|
},
|
|
36207
|
+
{
|
|
36208
|
+
"name": "stickyColumns",
|
|
36209
|
+
"type": "readonly number[] | undefined",
|
|
36210
|
+
"required": false,
|
|
36211
|
+
"description": "Липкие колонки, например `[0, 3, 10]`. Колонка стоит на своём месте, пока при прокрутке не дойдёт\nдо закреплённой зоны слева, и дальше остаётся в ней, как `position: sticky`. Сочетается с\n`freezeColumns`. Индексы считаются без колонки маркеров строк."
|
|
36212
|
+
},
|
|
36213
|
+
{
|
|
36214
|
+
"name": "stickyRows",
|
|
36215
|
+
"type": "readonly number[] | undefined",
|
|
36216
|
+
"required": false,
|
|
36217
|
+
"description": "Липкие строки, например `[0, 5, 40]`. Строка прилипает под шапкой (и под уже прилипшими строками),\nкогда при прокрутке доходит до них, как `position: sticky`."
|
|
36218
|
+
},
|
|
35585
36219
|
{
|
|
35586
36220
|
"name": "trailingRowOptions",
|
|
35587
36221
|
"type": "{ readonly tint?: boolean | undefined; readonly hint?: string | undefined; readonly sticky?: boolean | undefined; readonly addIcon?: string | undefined; readonly targetColumn?: number | GridColumn | undefined; } | undefined",
|
|
@@ -39445,12 +40079,6 @@
|
|
|
39445
40079
|
"description": "Смещение всплывающего окна при соприкосновении с границами экрана.",
|
|
39446
40080
|
"default": "false"
|
|
39447
40081
|
},
|
|
39448
|
-
{
|
|
39449
|
-
"name": "size",
|
|
39450
|
-
"type": "\"m\" | \"s\" | undefined",
|
|
39451
|
-
"required": false,
|
|
39452
|
-
"description": "Размер компонента."
|
|
39453
|
-
},
|
|
39454
40082
|
{
|
|
39455
40083
|
"name": "trigger",
|
|
39456
40084
|
"type": "\"click\" | \"hover\" | \"focus\" | undefined",
|
|
@@ -39458,18 +40086,24 @@
|
|
|
39458
40086
|
"description": "Способ скрытия/раскрытия всплывающего окна.",
|
|
39459
40087
|
"default": "click"
|
|
39460
40088
|
},
|
|
39461
|
-
{
|
|
39462
|
-
"name": "view",
|
|
39463
|
-
"type": "\"default\" | undefined",
|
|
39464
|
-
"required": false,
|
|
39465
|
-
"description": "Вид компонента."
|
|
39466
|
-
},
|
|
39467
40089
|
{
|
|
39468
40090
|
"name": "zIndex",
|
|
39469
40091
|
"type": "number | undefined",
|
|
39470
40092
|
"required": false,
|
|
39471
40093
|
"description": "CSS-свойство z-index всплывающего окна.",
|
|
39472
40094
|
"default": "1000"
|
|
40095
|
+
},
|
|
40096
|
+
{
|
|
40097
|
+
"name": "size",
|
|
40098
|
+
"type": "TooltipSize | undefined",
|
|
40099
|
+
"required": false,
|
|
40100
|
+
"description": ""
|
|
40101
|
+
},
|
|
40102
|
+
{
|
|
40103
|
+
"name": "view",
|
|
40104
|
+
"type": "\"default\" | undefined",
|
|
40105
|
+
"required": false,
|
|
40106
|
+
"description": ""
|
|
39473
40107
|
}
|
|
39474
40108
|
],
|
|
39475
40109
|
"propsTypeName": "TooltipBetaCompProps",
|
|
@@ -39895,14 +40529,14 @@
|
|
|
39895
40529
|
"exportName": "Usage1",
|
|
39896
40530
|
"displayName": "Использование в TourWidget.examples.tsx",
|
|
39897
40531
|
"type": "usage",
|
|
39898
|
-
"code": "<TourWidget.Footer>\n <Box\n $css={{\n display: 'flex',\n
|
|
40532
|
+
"code": "<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=\"default\"\n onClick={() =>\n setActiveStepIndex((current) =>\n clampStep(current + 1, tourStepsCount),\n )\n }\n >\n Далее\n </Button>\n </Box>\n </Box>\n </TourWidget.Footer>",
|
|
39899
40533
|
"sourceFile": "packages/storybook/src/stories/TourWidget/TourWidget.examples.tsx"
|
|
39900
40534
|
},
|
|
39901
40535
|
{
|
|
39902
40536
|
"exportName": "Usage2",
|
|
39903
40537
|
"displayName": "Использование в TourWidget.examples.tsx",
|
|
39904
40538
|
"type": "usage",
|
|
39905
|
-
"code": "<TourWidget.Footer>\n <Box\n $css={{\n display: 'flex',\n
|
|
40539
|
+
"code": "<TourWidget.Footer>\n <Box\n $css={{\n display: 'flex',\n flexDirection: 'column',\n }}\n >\n <TourWidget.Bullets\n count={tourStepsCount}\n $css={{ marginInline: 'auto' }}\n />\n <Box\n $css={{\n display: 'flex',\n flexDirection: 'row',\n gap: '4px',\n marginTop: '20px',\n }}\n >\n <Button\n size=\"s\"\n stretching=\"filled\"\n view=\"secondary\"\n onClick={() =>\n setActiveStepIndex((current) =>\n clampStep(current - 1, tourStepsCount),\n )\n }\n >\n Назад\n </Button>\n <Button\n stretching=\"filled\"\n size=\"s\"\n view=\"default\"\n onClick={() =>\n setActiveStepIndex((current) =>\n clampStep(current + 1, tourStepsCount),\n )\n }\n >\n Далее\n </Button>\n </Box>\n <Box\n $css={{\n display: 'flex',\n flexDirection: 'column',\n marginTop: '4px',\n }}\n >\n <LinkButton\n size=\"s\"\n view=\"default\"\n onClick={() => setActiveStepIndex(0)}\n >\n Пропустить всё\n </LinkButton>\n </Box>\n </Box>\n </TourWidget.Footer>",
|
|
39906
40540
|
"sourceFile": "packages/storybook/src/stories/TourWidget/TourWidget.examples.tsx"
|
|
39907
40541
|
}
|
|
39908
40542
|
]
|
|
@@ -40097,14 +40731,14 @@
|
|
|
40097
40731
|
"онбординг",
|
|
40098
40732
|
"степ-виджет"
|
|
40099
40733
|
],
|
|
40100
|
-
"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<TourWidget activeStepIndex={activeStepIndex} $css={{ width: '306px' }}>\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```\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` автоматически использует глобальную тему приложения.\n\n## CSS-переменные\n\nКорневой `$css` можно использовать для точечной настройки внешнего вида.\n\n```tsx\n\n<TourWidget\n $css={{\n [tourWidgetTokens.minWidth]: '0',\n [tourWidgetTokens.borderRadius]: '16px',\n [tourWidgetTokens.gradientFrameHeight]: '34%',\n [tourWidgetTokens.gradientFrameFade]: '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).",
|
|
40734
|
+
"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Рекомендуемая ширина карточки зависит от ориентации:\n\n| Вариант | Минимальная ширина | Максимальная ширина |\n| ----------------------------- | ------------------ | ------------------- |\n| Горизонтальный (`horizontal`) | 480 px | 720 px |\n| Вертикальный (`vertical`) | 270 px | 460 px |\n\nЭти значения — рекомендации по дизайну. Компонент не устанавливает их автоматически; задавайте ширину и ограничения через `$css` (`width`, `minWidth`, `maxWidth`).\n\n## Использование\n\n```tsx\n\n```\n\nБазовая схема работы:\n\n```tsx\nconst [activeStepIndex, setActiveStepIndex] = useState(0);\n\n<TourWidget activeStepIndex={activeStepIndex} $css={{ width: '306px' }}>\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```\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` автоматически использует глобальную тему приложения.\n\n## CSS-переменные\n\nКорневой `$css` можно использовать для точечной настройки внешнего вида.\n\n```tsx\n\n<TourWidget\n $css={{\n [tourWidgetTokens.minWidth]: '0',\n [tourWidgetTokens.borderRadius]: '16px',\n [tourWidgetTokens.gradientFrameHeight]: '34%',\n [tourWidgetTokens.gradientFrameFade]: '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).",
|
|
40101
40735
|
"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```\n\n## tourWidgetTokens\n\n```typescript\nexport const tourWidgetTokens = {\n background: '--tour-widget-background',\n borderRadius: '--tour-widget-border-radius',\n bulletActiveBackground: '--tour-widget-bullet-active-background',\n bulletBackground: '--tour-widget-bullet-background',\n bulletsOffset: '--tour-widget-bullets-offset',\n bulletsWidth: '--tour-widget-bullets-width',\n contentBorderRadius: '--tour-widget-content-border-radius',\n gradientBackground: '--tour-widget-gradient-background',\n gradientBlur: '--tour-widget-gradient-blur',\n gradientFrameBottom: '--tour-widget-gradient-frame-bottom',\n gradientFrameFade: '--tour-widget-gradient-frame-fade',\n gradientFrameHeight: '--tour-widget-gradient-frame-height',\n gradientFrameLeft: '--tour-widget-gradient-frame-left',\n gradientFrameRight: '--tour-widget-gradient-frame-right',\n gradientHeight: '--tour-widget-gradient-height',\n gradientLeft: '--tour-widget-gradient-left',\n gradientOpacity: '--tour-widget-gradient-opacity',\n gradientTop: '--tour-widget-gradient-top',\n gradientWidth: '--tour-widget-gradient-width',\n inlineOvalDisplay: '--tour-widget-inline-oval-display',\n minWidth: '--tour-widget-min-width',\n ovalBackground: '--tour-widget-oval-background',\n ovalBlur: '--tour-widget-oval-blur',\n ovalBorderRadius: '--tour-widget-oval-border-radius',\n ovalFrameDisplay: '--tour-widget-oval-frame-display',\n ovalFrameHeight: '--tour-widget-oval-frame-height',\n ovalHeight: '--tour-widget-oval-height',\n ovalLeft: '--tour-widget-oval-left',\n ovalOpacity: '--tour-widget-oval-opacity',\n ovalTop: '--tour-widget-oval-top',\n ovalWidth: '--tour-widget-oval-width',\n shapeGradientMaskMiddle: '--tour-widget-shape-gradient-mask-middle',\n shapeGradientMaskStart: '--tour-widget-shape-gradient-mask-start',\n shapeGradientOpacity: '--tour-widget-shape-gradient-opacity',\n shapeGradientPathOpacity: '--tour-widget-shape-gradient-path-opacity',\n themeBackground: '--tour-widget-theme-background',\n themeGradientHorizontal: '--tour-widget-theme-gradient-horizontal',\n themeGradientHorizontalBlur: '--tour-widget-theme-gradient-horizontal-blur',\n themeGradientOpacity: '--tour-widget-theme-gradient-opacity',\n themeGradientVertical: '--tour-widget-theme-gradient-vertical',\n themeGradientVerticalBlur: '--tour-widget-theme-gradient-vertical-blur',\n themeOvalBackground: '--tour-widget-theme-oval-background',\n themeOvalHorizontalBlur: '--tour-widget-theme-oval-horizontal-blur',\n themeOvalHorizontalOpacity: '--tour-widget-theme-oval-horizontal-opacity',\n themeOvalVerticalBlur: '--tour-widget-theme-oval-vertical-blur',\n themeOvalVerticalOpacity: '--tour-widget-theme-oval-vertical-opacity',\n themeShapeEnd: '--tour-widget-theme-shape-end',\n themeShapeMiddle: '--tour-widget-theme-shape-middle',\n themeShapeOpacity: '--tour-widget-theme-shape-opacity',\n themeShapeStart: '--tour-widget-theme-shape-start',\n} as const;\n```",
|
|
40102
40736
|
"curatedStories": [
|
|
40103
40737
|
{
|
|
40104
40738
|
"exportName": "Vertical",
|
|
40105
40739
|
"displayName": "Вертикальный тур",
|
|
40106
40740
|
"type": "full-code",
|
|
40107
|
-
"code": "function VerticalExample() {\n const tourStepsCount = 14;\n const [activeStepIndex, setActiveStepIndex] = useState(0);\n\n return (\n <TourWidget activeStepIndex={activeStepIndex} $css={{ width: '298px' }}>\n <TourWidget.Content>\n <MediaPlaceholder width={266} height={266} />\n </TourWidget.Content>\n <TourWidget.Header title=\"Title\" description=\"Description\" />\n <TourWidget.Footer>\n <Box\n $css={{\n display: 'flex',\n flexDirection: 'column',\n }}\n >\n <TourWidget.Bullets\n count={tourStepsCount}\n $css={{ marginInline: 'auto' }}\n />\n <Box\n $css={{\n display: 'flex',\n flexDirection: 'row',\n gap: '4px',\n marginTop: '20px',\n }}\n >\n <Button\n size=\"s\"\n stretching=\"filled\"\n view=\"secondary\"\n onClick={() =>\n setActiveStepIndex((current) =>\n clampStep(current - 1, tourStepsCount),\n )\n }\n >\n Назад\n </Button>\n <Button\n stretching=\"filled\"\n size=\"s\"\n view=\"default\"\n onClick={() =>\n setActiveStepIndex((current) =>\n clampStep(current + 1, tourStepsCount),\n )\n }\n >\n Далее\n </Button>\n </Box>\n <LinkButton\n
|
|
40741
|
+
"code": "function VerticalExample() {\n const tourStepsCount = 14;\n const [activeStepIndex, setActiveStepIndex] = useState(0);\n\n return (\n <TourWidget activeStepIndex={activeStepIndex} $css={{ width: '298px' }}>\n <TourWidget.Content>\n <MediaPlaceholder width={266} height={266} />\n </TourWidget.Content>\n <TourWidget.Header title=\"Title\" description=\"Description\" />\n <TourWidget.Footer>\n <Box\n $css={{\n display: 'flex',\n flexDirection: 'column',\n }}\n >\n <TourWidget.Bullets\n count={tourStepsCount}\n $css={{ marginInline: 'auto' }}\n />\n <Box\n $css={{\n display: 'flex',\n flexDirection: 'row',\n gap: '4px',\n marginTop: '20px',\n }}\n >\n <Button\n size=\"s\"\n stretching=\"filled\"\n view=\"secondary\"\n onClick={() =>\n setActiveStepIndex((current) =>\n clampStep(current - 1, tourStepsCount),\n )\n }\n >\n Назад\n </Button>\n <Button\n stretching=\"filled\"\n size=\"s\"\n view=\"default\"\n onClick={() =>\n setActiveStepIndex((current) =>\n clampStep(current + 1, tourStepsCount),\n )\n }\n >\n Далее\n </Button>\n </Box>\n <Box\n $css={{\n display: 'flex',\n flexDirection: 'column',\n marginTop: '4px',\n }}\n >\n <LinkButton\n size=\"s\"\n view=\"default\"\n onClick={() => setActiveStepIndex(0)}\n >\n Пропустить всё\n </LinkButton>\n </Box>\n </Box>\n </TourWidget.Footer>\n </TourWidget>\n );\n};"
|
|
40108
40742
|
},
|
|
40109
40743
|
{
|
|
40110
40744
|
"exportName": "Horizontal",
|
|
@@ -40154,7 +40788,7 @@
|
|
|
40154
40788
|
"exportName": "Vertical",
|
|
40155
40789
|
"displayName": "Вертикальный тур",
|
|
40156
40790
|
"type": "full-code",
|
|
40157
|
-
"code": "function VerticalExample() {\n const tourStepsCount = 14;\n const [activeStepIndex, setActiveStepIndex] = useState(0);\n\n return (\n <TourWidget activeStepIndex={activeStepIndex} $css={{ width: '298px' }}>\n <TourWidget.Content>\n <MediaPlaceholder width={266} height={266} />\n </TourWidget.Content>\n <TourWidget.Header title=\"Title\" description=\"Description\" />\n <TourWidget.Footer>\n <Box\n $css={{\n display: 'flex',\n flexDirection: 'column',\n }}\n >\n <TourWidget.Bullets\n count={tourStepsCount}\n $css={{ marginInline: 'auto' }}\n />\n <Box\n $css={{\n display: 'flex',\n flexDirection: 'row',\n gap: '4px',\n marginTop: '20px',\n }}\n >\n <Button\n size=\"s\"\n stretching=\"filled\"\n view=\"secondary\"\n onClick={() =>\n setActiveStepIndex((current) =>\n clampStep(current - 1, tourStepsCount),\n )\n }\n >\n Назад\n </Button>\n <Button\n stretching=\"filled\"\n size=\"s\"\n view=\"default\"\n onClick={() =>\n setActiveStepIndex((current) =>\n clampStep(current + 1, tourStepsCount),\n )\n }\n >\n Далее\n </Button>\n </Box>\n <LinkButton\n
|
|
40791
|
+
"code": "function VerticalExample() {\n const tourStepsCount = 14;\n const [activeStepIndex, setActiveStepIndex] = useState(0);\n\n return (\n <TourWidget activeStepIndex={activeStepIndex} $css={{ width: '298px' }}>\n <TourWidget.Content>\n <MediaPlaceholder width={266} height={266} />\n </TourWidget.Content>\n <TourWidget.Header title=\"Title\" description=\"Description\" />\n <TourWidget.Footer>\n <Box\n $css={{\n display: 'flex',\n flexDirection: 'column',\n }}\n >\n <TourWidget.Bullets\n count={tourStepsCount}\n $css={{ marginInline: 'auto' }}\n />\n <Box\n $css={{\n display: 'flex',\n flexDirection: 'row',\n gap: '4px',\n marginTop: '20px',\n }}\n >\n <Button\n size=\"s\"\n stretching=\"filled\"\n view=\"secondary\"\n onClick={() =>\n setActiveStepIndex((current) =>\n clampStep(current - 1, tourStepsCount),\n )\n }\n >\n Назад\n </Button>\n <Button\n stretching=\"filled\"\n size=\"s\"\n view=\"default\"\n onClick={() =>\n setActiveStepIndex((current) =>\n clampStep(current + 1, tourStepsCount),\n )\n }\n >\n Далее\n </Button>\n </Box>\n <Box\n $css={{\n display: 'flex',\n flexDirection: 'column',\n marginTop: '4px',\n }}\n >\n <LinkButton\n size=\"s\"\n view=\"default\"\n onClick={() => setActiveStepIndex(0)}\n >\n Пропустить всё\n </LinkButton>\n </Box>\n </Box>\n </TourWidget.Footer>\n </TourWidget>\n );\n};"
|
|
40158
40792
|
},
|
|
40159
40793
|
{
|
|
40160
40794
|
"exportName": "Horizontal",
|
|
@@ -40753,10 +41387,10 @@
|
|
|
40753
41387
|
},
|
|
40754
41388
|
{
|
|
40755
41389
|
"exportName": "Usage1",
|
|
40756
|
-
"displayName": "Использование в
|
|
41390
|
+
"displayName": "Использование в AiAgentPopup.stories.tsx",
|
|
40757
41391
|
"type": "usage",
|
|
40758
|
-
"code": "<Typography variant=\"
|
|
40759
|
-
"sourceFile": "packages/storybook/src/stories/
|
|
41392
|
+
"code": "<Typography\n // eslint-disable-next-line react/no-array-index-key\n key={index}\n variant=\"BodyS\"\n style={message.system ? systemMessageStyle : chatBubbleStyle}\n data-no-drag\n >\n {message.text}\n </Typography>",
|
|
41393
|
+
"sourceFile": "packages/storybook/src/stories/AiAgentPopup/AiAgentPopup.stories.tsx"
|
|
40760
41394
|
}
|
|
40761
41395
|
]
|
|
40762
41396
|
},
|
|
@@ -41324,17 +41958,17 @@
|
|
|
41324
41958
|
"examples": [
|
|
41325
41959
|
{
|
|
41326
41960
|
"exportName": "Usage1",
|
|
41327
|
-
"displayName": "Использование в TableCanvas.
|
|
41961
|
+
"displayName": "Использование в TableCanvas.bottomSheet.auto.tsx",
|
|
41328
41962
|
"type": "usage",
|
|
41329
|
-
"code": "<BodyS
|
|
41330
|
-
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.
|
|
41963
|
+
"code": "<BodyS\n key={message}\n data-testid=\"bottom-sheet-auto-message\"\n style={{ padding: '8px 12px' }}\n >\n {message}\n </BodyS>",
|
|
41964
|
+
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.BottomSheet/TableCanvas.bottomSheet.auto.tsx"
|
|
41331
41965
|
},
|
|
41332
41966
|
{
|
|
41333
41967
|
"exportName": "Usage2",
|
|
41334
|
-
"displayName": "Использование в
|
|
41968
|
+
"displayName": "Использование в TableCanvas.bottomSheet.basic.tsx",
|
|
41335
41969
|
"type": "usage",
|
|
41336
|
-
"code": "<BodyS
|
|
41337
|
-
"sourceFile": "packages/storybook/src/stories/
|
|
41970
|
+
"code": "<BodyS key={message} style={{ padding: '12px 0' }}>\n {message}\n </BodyS>",
|
|
41971
|
+
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.BottomSheet/TableCanvas.bottomSheet.basic.tsx"
|
|
41338
41972
|
},
|
|
41339
41973
|
{
|
|
41340
41974
|
"exportName": "Vendor1",
|
|
@@ -41521,10 +42155,10 @@
|
|
|
41521
42155
|
},
|
|
41522
42156
|
{
|
|
41523
42157
|
"exportName": "Usage2",
|
|
41524
|
-
"displayName": "Использование в TableCanvas.
|
|
42158
|
+
"displayName": "Использование в TableCanvas.bottomSheet.example.tsx",
|
|
41525
42159
|
"type": "usage",
|
|
41526
|
-
"code": "<BodyXS style={{
|
|
41527
|
-
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.
|
|
42160
|
+
"code": "<BodyXS style={{ color: textSecondary }}>Последние отчёты</BodyXS>",
|
|
42161
|
+
"sourceFile": "packages/storybook/src/stories/TableCanvas/TableCanvas.BottomSheet/TableCanvas.bottomSheet.example.tsx"
|
|
41528
42162
|
},
|
|
41529
42163
|
{
|
|
41530
42164
|
"exportName": "Vendor1",
|
|
@@ -45844,6 +46478,13 @@
|
|
|
45844
46478
|
"description": "Дропдаун открыт всегда.",
|
|
45845
46479
|
"default": "false"
|
|
45846
46480
|
},
|
|
46481
|
+
{
|
|
46482
|
+
"name": "appearance",
|
|
46483
|
+
"type": "\"default\" | \"viewMode\" | undefined",
|
|
46484
|
+
"required": false,
|
|
46485
|
+
"description": "Стиль для UI конфигурации\nВлияет на выбор предустановленного набора токенов",
|
|
46486
|
+
"default": "default"
|
|
46487
|
+
},
|
|
45847
46488
|
{
|
|
45848
46489
|
"name": "arrowPlacement",
|
|
45849
46490
|
"type": "\"left\" | \"right\" | undefined",
|
|
@@ -45901,6 +46542,12 @@
|
|
|
45901
46542
|
"description": "Коррекция placement, если выпадающий список находится за пределами экрана.",
|
|
45902
46543
|
"default": "false"
|
|
45903
46544
|
},
|
|
46545
|
+
{
|
|
46546
|
+
"name": "hasDivider",
|
|
46547
|
+
"type": "boolean | undefined",
|
|
46548
|
+
"required": false,
|
|
46549
|
+
"description": "отобразить ли divider"
|
|
46550
|
+
},
|
|
45904
46551
|
{
|
|
45905
46552
|
"name": "hasRequiredIndicator",
|
|
45906
46553
|
"type": "boolean | undefined",
|
|
@@ -46084,6 +46731,12 @@
|
|
|
46084
46731
|
"description": "Label в элементе выпадающего списка в одну строку или с переносом строк.",
|
|
46085
46732
|
"default": "true"
|
|
46086
46733
|
},
|
|
46734
|
+
{
|
|
46735
|
+
"name": "sortItems",
|
|
46736
|
+
"type": "((a: ItemOption, b: ItemOption) => number) | undefined",
|
|
46737
|
+
"required": false,
|
|
46738
|
+
"description": "Компаратор сортировки элементов первого уровня.\nВложенные списки и исходный массив items не изменяются."
|
|
46739
|
+
},
|
|
46087
46740
|
{
|
|
46088
46741
|
"name": "textAfter",
|
|
46089
46742
|
"type": "string | undefined",
|
|
@@ -46141,12 +46794,6 @@
|
|
|
46141
46794
|
"required": false,
|
|
46142
46795
|
"description": ""
|
|
46143
46796
|
},
|
|
46144
|
-
{
|
|
46145
|
-
"name": "appearance",
|
|
46146
|
-
"type": "\"default\" | \"viewMode\" | undefined",
|
|
46147
|
-
"required": false,
|
|
46148
|
-
"description": ""
|
|
46149
|
-
},
|
|
46150
46797
|
{
|
|
46151
46798
|
"name": "autoComplete",
|
|
46152
46799
|
"type": "React.HTMLInputAutoCompleteAttribute | undefined",
|
|
@@ -46485,6 +47132,13 @@
|
|
|
46485
47132
|
"description": "Сторона открытия календаря относительно поля ввода.",
|
|
46486
47133
|
"default": "[\"bottom\", \"top\"]"
|
|
46487
47134
|
},
|
|
47135
|
+
{
|
|
47136
|
+
"name": "quarterNames",
|
|
47137
|
+
"type": "string[] | undefined",
|
|
47138
|
+
"required": false,
|
|
47139
|
+
"description": "Названия кварталов.",
|
|
47140
|
+
"default": "['Q1', 'Q2', 'Q3', 'Q4']"
|
|
47141
|
+
},
|
|
46488
47142
|
{
|
|
46489
47143
|
"name": "renderFromDate",
|
|
46490
47144
|
"type": "Date | undefined",
|
|
@@ -46971,6 +47625,13 @@
|
|
|
46971
47625
|
"required": false,
|
|
46972
47626
|
"description": "Видимость календаря."
|
|
46973
47627
|
},
|
|
47628
|
+
{
|
|
47629
|
+
"name": "quarterNames",
|
|
47630
|
+
"type": "string[] | undefined",
|
|
47631
|
+
"required": false,
|
|
47632
|
+
"description": "Названия кварталов.",
|
|
47633
|
+
"default": "['Q1', 'Q2', 'Q3', 'Q4']"
|
|
47634
|
+
},
|
|
46974
47635
|
{
|
|
46975
47636
|
"name": "renderFromDate",
|
|
46976
47637
|
"type": "Date | undefined",
|
|
@@ -48828,6 +49489,12 @@
|
|
|
48828
49489
|
"required": false,
|
|
48829
49490
|
"description": "Размер компонента."
|
|
48830
49491
|
},
|
|
49492
|
+
{
|
|
49493
|
+
"name": "sortItems",
|
|
49494
|
+
"type": "((a: ItemOption, b: ItemOption) => number) | undefined",
|
|
49495
|
+
"required": false,
|
|
49496
|
+
"description": "Компаратор сортировки элементов первого уровня.\nВложенные списки и исходный массив items не изменяются."
|
|
49497
|
+
},
|
|
48831
49498
|
{
|
|
48832
49499
|
"name": "target",
|
|
48833
49500
|
"type": "\"textfield-like\" | \"button-like\" | undefined",
|
|
@@ -53426,7 +54093,7 @@
|
|
|
53426
54093
|
"feature": "CanvasElements/CanvasLink",
|
|
53427
54094
|
"legacy": false,
|
|
53428
54095
|
"summary": "Ссылка с навигацией и underline внутри canvas-ячейки `TableCanvas`.",
|
|
53429
|
-
"docs": "# Canvas.Link\n\nСсылка с навигацией и underline внутри canvas-ячейки `TableCanvas`.\n\n## Ключевые особенности\n\n- Несколько вариантов `view`\n- `view=\"clear\"` использует цвета `default` как fallback — canvas не поддерживает `inherit`\n- Поддержка `href`, `target`, `disabled`\n- Наследует текстовые свойства от `Canvas.Text`: `wordWrap`, `overflow`, `textOverflow`, `ellipsis`, `maxLines`\n\n## Перехват навигации\n\nПо умолчанию `Canvas.Link` выполняет навигацию по `href` после вызова `onClick`.\nДля отмены навигации вызовите `event.preventDefault()`:\n\n```tsx\n<Canvas.Link\n view=\"accent\"\n href=\"/some-page\"\n onClick={(event) => {\n event.preventDefault();\n openModal(row.id);\n }}\n>\n Открыть\n</Canvas.Link>\n```\n\n## Многострочный режим\n\n
|
|
54096
|
+
"docs": "# Canvas.Link\n\nСсылка с навигацией и underline внутри canvas-ячейки `TableCanvas`.\n\n## Ключевые особенности\n\n- Несколько вариантов `view`\n- `view=\"clear\"` использует цвета `default` как fallback — canvas не поддерживает `inherit`\n- Поддержка `href`, `target`, `disabled`\n- Наследует текстовые свойства от `Canvas.Text`: `wordWrap`, `overflow`, `textOverflow`, `ellipsis`, `maxLines`, `autoTooltip`\n\n## Перехват навигации\n\nПо умолчанию `Canvas.Link` выполняет навигацию по `href` после вызова `onClick`.\nДля отмены навигации вызовите `event.preventDefault()`:\n\n```tsx\n<Canvas.Link\n view=\"accent\"\n href=\"/some-page\"\n onClick={(event) => {\n event.preventDefault();\n openModal(row.id);\n }}\n>\n Открыть\n</Canvas.Link>\n```\n\n## Многострочный режим\n\nПеренос включается явно через `wordWrap`. Каждая видимая строка подчёркивается по длине её текста.\n\n```tsx\n<Canvas.Container direction=\"row\" alignItems=\"center\" padding={8}>\n <Canvas.Link\n href=\"/details\"\n wordWrap\n maxLines={2}\n overflow=\"hidden\"\n textOverflow=\"ellipsis\"\n autoTooltip\n style={{ flexGrow: 1 }}\n >\n Длинное название документа с переносом на несколько строк\n </Canvas.Link>\n</Canvas.Container>\n```\n\n`maxLines` ограничивает количество строк при `wordWrap` и `overflow=\"hidden\"`. `maxLines={1}` сохраняет однострочное подчёркивание и ellipsis. `autoTooltip` показывает полный текст при обрезке в многоточие.\n\nВысота строки таблицы не увеличивается автоматически: задайте `tableConfig.rowHeight` с запасом под текст и padding, например `72` для двух строк. Область клика остаётся прямоугольником всего блока ссылки.\n\nОписание типов — в разделе [API](?path=/docs/локальные-компоненты-tablecanvas-canvaselements-canvaslink-api--docs).",
|
|
53430
54097
|
"apiDocs": "# Canvas.Link API\n\n## CanvasLinkOptions\n\n```typescript\ninterface CanvasLinkOptions extends CanvasTextOptions {\n href?: string;\n target?: string;\n rel?: string;\n view?: LinkView;\n disabled?: boolean;\n theme?: Theme;\n}\n```\n\n## LinkView\n\n```typescript\ntype LinkView = Extract<LinkAllProps['view'], string>;\n```",
|
|
53431
54098
|
"api": [
|
|
53432
54099
|
{
|
|
@@ -53444,6 +54111,12 @@
|
|
|
53444
54111
|
"displayName": "View",
|
|
53445
54112
|
"type": "full-code",
|
|
53446
54113
|
"code": "(args) => {\n const { text, href, disabled } = args as {\n text: string;\n href: string;\n disabled: boolean;\n };\n\n const columnConfig = useMemo<readonly ColumnConfig<ViewRow>[]>(\n () => [\n {\n key: 'view',\n name: 'View',\n width: 100,\n renderCell: ({ row }) => (\n <Canvas.Container padding={8} alignItems=\"center\">\n <Canvas.Text>{row.view}</Canvas.Text>\n </Canvas.Container>\n ),\n },\n {\n key: 'link',\n name: 'Link',\n width: 200,\n renderCell: ({ row }) => (\n <Canvas.Container direction=\"row\" alignItems=\"center\" padding={8}>\n <Canvas.Link\n view={row.view}\n href={href}\n target=\"_blank\"\n disabled={disabled}\n >\n {text}\n </Canvas.Link>\n </Canvas.Container>\n ),\n },\n ],\n [text, href, disabled],\n );\n\n return (\n <TableCanvas\n tableConfig={{ containerStyle: { height: '600px' } }}\n columnConfig={columnConfig}\n rows={rows}\n />\n );\n }"
|
|
54114
|
+
},
|
|
54115
|
+
{
|
|
54116
|
+
"exportName": "Multiline",
|
|
54117
|
+
"displayName": "View",
|
|
54118
|
+
"type": "full-code",
|
|
54119
|
+
"code": "(args) => {\n const { text, width, maxLines, lineHeight, disabled } = args as {\n text: string;\n width: number;\n maxLines: number;\n lineHeight: number;\n disabled: boolean;\n };\n const columnConfig = useMemo<readonly ColumnConfig<ViewRow>[]>(\n () => [\n {\n key: 'view',\n name: 'View',\n width: 100,\n renderCell: ({ row }) => (\n <Canvas.Container padding={8} alignItems=\"center\">\n <Canvas.Text>{row.view}</Canvas.Text>\n </Canvas.Container>\n ),\n },\n {\n key: 'link',\n name: 'Multiline link',\n width,\n renderCell: ({ row }) => (\n <Canvas.Container direction=\"row\" alignItems=\"center\" padding={8}>\n <Canvas.Link\n view={row.view}\n href=\"https://example.com\"\n target=\"_blank\"\n disabled={disabled}\n wordWrap\n maxLines={maxLines}\n lineHeight={lineHeight}\n overflow=\"hidden\"\n textOverflow=\"ellipsis\"\n autoTooltip\n style={{ flexGrow: 1 }}\n >\n {text}\n </Canvas.Link>\n </Canvas.Container>\n ),\n },\n ],\n [text, width, maxLines, lineHeight, disabled],\n );\n\n return (\n <TableCanvas\n tableConfig={{\n rowHeight: 112,\n containerStyle: { height: '600px' },\n }}\n columnConfig={columnConfig}\n rows={rows}\n />\n );\n }"
|
|
53447
54120
|
}
|
|
53448
54121
|
]
|
|
53449
54122
|
},
|
|
@@ -54026,7 +54699,7 @@
|
|
|
54026
54699
|
"feature": "massPanelAction",
|
|
54027
54700
|
"legacy": false,
|
|
54028
54701
|
"summary": "Панель действий для выбранных строк",
|
|
54029
|
-
"docs": "# TableCanvas MassPanelAction\n\n## Ключевые особенности\n\n- Панель действий для выбранных строк\n- Автоматическое появление при активном selecting\n- Компрессия кнопок и отдельное поведение accent-кнопок\n\n**tableConfig.controlBlock.massActionPanel**\n\nПанель массовых действий (MassPanelAction) - это компонент, который отображается внизу таблицы и позволяет применять действия к выбранным строкам. Панель появляется автоматически, когда в таблице выбраны строки.\n\n## Когда открывается панель\n\nПанель массовых действий появляется автоматически, когда:\n\n- Включена функция выбора строк (`selecting` в `tableConfig`)\n- Выбрана хотя бы одна строка в таблице\n- `selectingRowsIsActive` равен `true`\n\nПанель скрывается автоматически, когда все строки сняты с выбора.\n\n## Управление видимостью\n\nПо умолчанию панель показывается автоматически при активном `selecting` и хотя бы одной выбранной строке. Это поведение переопределяется через `massActionPanel.show`:\n\n- `undefined` (по умолчанию) — штатное поведение (selecting + выбранные строки)\n- `false` — панель не рендерится, действиями вы управляете сами\n- `true` — панель показывается всегда, даже без активного selecting и выбранных строк (см. стори «Панель без selecting»)\n\n## Замена leftSideInner\n\n**Важно:** Панель массовых действий (`massActionPanel`) была создана как **замена** для `leftSideInner` в `controlBlock`.\n\n### ⚠️ Не рекомендуется использовать вместе\n\n**НЕ ЖЕЛАТЕЛЬНО** использовать `leftSideInner` и `massActionPanel` одновременно, так как:\n\n- Это создает дублирование функциональности\n- `massActionPanel` специально разработан для работы с выбранными строками\n- `massActionPanel` имеет адаптивную компрессию и автоматическое позиционирование\n- `massActionPanel` лучше интегрирован с функцией выбора строк\n\n### Рекомендация\n\nИспользуйте `massActionPanel` вместо `leftSideInner` для кнопок, которые должны работать с выбранными строками. Кнопки, которые не зависят от выбора строк, можно оставить в `leftSideInner` или `rightSideInner`.\n\n## Особенности работы\n\n### Accent кнопки всегда видимы\n\nКнопки с `view: 'accent'` **никогда не скрываются** в дропдауне скрытых действий, даже если панель не помещается по ширине. Они всегда остаются видимыми и сохраняют свой оригинальный порядок относительно других кнопок.\n\n### Адаптивная компрессия\n\nПри нехватке места панель автоматически:\n\n- Скрывает обычные кнопки в дропдаун скрытых действий\n- Оставляет accent кнопки всегда видимыми\n- Сохраняет порядок кнопок (accent кнопки остаются на своих позициях)\n- Автоматически центрируется с учетом
|
|
54702
|
+
"docs": "# TableCanvas MassPanelAction\n\n## Ключевые особенности\n\n- Панель действий для выбранных строк\n- Автоматическое появление при активном selecting\n- Компрессия кнопок и отдельное поведение accent-кнопок\n\n**tableConfig.controlBlock.massActionPanel**\n\nПанель массовых действий (MassPanelAction) - это компонент, который отображается внизу таблицы и позволяет применять действия к выбранным строкам. Панель появляется автоматически, когда в таблице выбраны строки.\n\n## Когда открывается панель\n\nПанель массовых действий появляется автоматически, когда:\n\n- Включена функция выбора строк (`selecting` в `tableConfig`)\n- Выбрана хотя бы одна строка в таблице\n- `selectingRowsIsActive` равен `true`\n\nПанель скрывается автоматически, когда все строки сняты с выбора.\n\n## Управление видимостью\n\nПо умолчанию панель показывается автоматически при активном `selecting` и хотя бы одной выбранной строке. Это поведение переопределяется через `massActionPanel.show`:\n\n- `undefined` (по умолчанию) — штатное поведение (selecting + выбранные строки)\n- `false` — панель не рендерится, действиями вы управляете сами\n- `true` — панель показывается всегда, даже без активного selecting и выбранных строк (см. стори «Панель без selecting»)\n\n## Замена leftSideInner\n\n**Важно:** Панель массовых действий (`massActionPanel`) была создана как **замена** для `leftSideInner` в `controlBlock`.\n\n### ⚠️ Не рекомендуется использовать вместе\n\n**НЕ ЖЕЛАТЕЛЬНО** использовать `leftSideInner` и `massActionPanel` одновременно, так как:\n\n- Это создает дублирование функциональности\n- `massActionPanel` специально разработан для работы с выбранными строками\n- `massActionPanel` имеет адаптивную компрессию и автоматическое позиционирование\n- `massActionPanel` лучше интегрирован с функцией выбора строк\n\n### Рекомендация\n\nИспользуйте `massActionPanel` вместо `leftSideInner` для кнопок, которые должны работать с выбранными строками. Кнопки, которые не зависят от выбора строк, можно оставить в `leftSideInner` или `rightSideInner`.\n\n## Особенности работы\n\n### Accent кнопки всегда видимы\n\nКнопки с `view: 'accent'` **никогда не скрываются** в дропдауне скрытых действий, даже если панель не помещается по ширине. Они всегда остаются видимыми и сохраняют свой оригинальный порядок относительно других кнопок.\n\n### Адаптивная компрессия\n\nПри нехватке места панель автоматически:\n\n- Скрывает обычные кнопки в дропдаун скрытых действий\n- Оставляет accent кнопки всегда видимыми\n- Сохраняет порядок кнопок (accent кнопки остаются на своих позициях)\n- Автоматически центрируется по текущей ширине canvas с учетом обеих боковых панелей\n\n### Взаимодействие с боковыми панелями\n\nПри открытии левой или правой Sidebar панель массовых действий автоматически сворачивается, если была развёрнута. Пока открыта хотя бы одна Sidebar, автоматическое состояние остаётся свёрнутым.\n\nПанель автоматически разворачивается только после закрытия всех Sidebar. Если открыты обе, закрытие одной сохраняет автоматическое сворачивание. Позиция и компрессия кнопок пересчитываются по текущей ширине canvas после изменения панелей. Ручное сворачивание и разворачивание остаются доступными.\n\n### Размеры кнопок\n\nРазмеры кнопок и дропдаунов панель подбирает сама — по размеру панели (`massActionPanel.size`: `m`/`s`/`xs`) и компактности. Передавать `size` кнопкам отдельно **не нужно**. Если `size` всё же задан — он используется как есть.\n\n## Конфигурация\n\nПанель массовых действий настраивается через `tableConfig.controlBlock.massActionPanel`:\n\n```tsx\ntableConfig={{\n selecting: {\n state: selectingRowState,\n rowKeyGetter: (row) => row.id,\n },\n controlBlock: {\n massActionPanel: {\n buttons: [\n {\n type: 'button',\n text: 'Действие',\n view: 'secondary', // или 'accent', 'critical', 'primary' и т.д.\n onClick: () => {\n // Обработчик клика\n },\n },\n ],\n },\n },\n}}\n```\n\nПомимо `buttons`, у панели есть необязательные пропсы: `size` (размер панели, см. «Размеры кнопок»), `show` (управление видимостью), `bottom` (отступ панели снизу от контейнера, по умолчанию 24px) и `collapsedDropdownProps` (пропсы дропдауна скрытых действий). Полное описание типов — в разделе API.\n\n## Типы кнопок\n\n### Button\n\nИспользуется компонент `Button` с `type: 'button'`:\n\n- Доступны view: `'accent'`, `'secondary'`, `'critical'`, `'primary'` и т.д.\n- `view: 'accent'` - accent кнопки, которые всегда остаются видимыми\n\n### LinkButton\n\nКнопка-ссылка с `type: 'linkButton'` (компонент `LinkButton`). View задаётся в link-нотации:\n\n```tsx\n{\n type: 'linkButton',\n text: 'Ссылка-действие',\n view: 'linkSecondary', // 'linkAccent' / 'linkDefault' и т.д.\n onClick: () => {},\n}\n```\n\n## Disabled состояние\n\nЕсли кнопка имеет `disabled: true`, можно передать `disabledTooltipProps` для отображения подсказки при наведении на disabled кнопку:\n\n```tsx\n{\n type: 'button',\n text: 'Действие',\n view: 'secondary',\n disabled: true,\n disabledTooltipProps: {\n text: 'Выберите строки для выполнения действия',\n },\n onClick: () => {},\n}\n```\n\n**Важно:** disabled кнопка остаётся неактивной и после перемещения в дропдаун скрытых действий — `disabled` пробрасывается на пункт меню. Подсказка `disabledTooltipProps` при этом показывается только у кнопок на самой панели, в меню её нет.\n\n## Dropdown в кнопках\n\nКнопки могут иметь вложенный dropdown:\n\n```tsx\n{\n type: 'button',\n text: 'Действие с меню',\n view: 'secondary',\n dropdown: {\n items: [\n { label: 'Опция 1', value: '1' },\n { label: 'Опция 2', value: '2' },\n ],\n onItemSelect: (item) => {\n // Обработчик выбора\n },\n },\n}\n```\n\n> Подробнее о типах — [MassPanelAction API](?path=/docs/локальные-компоненты-tablecanvas-controlblock-masspanelaction-api--docs)",
|
|
54030
54703
|
"apiDocs": "# MassPanelAction API\n\n## MassActionsButtonProps\n\n```typescript\ntype MassActionsButtonPropsButton = DataAttributes &\n Partial<ButtonCompProps> & {\n type: 'button';\n view?: ButtonCompProps['view'];\n /**\n * Dropdown для кнопки.\n * Используется универсальный DropdownProps, который работает и с обычным Dropdown, и с TableDropdown\n */\n dropdown?: DropdownProps & { $css?: CSSObject };\n disabledTooltipProps?: TooltipProps;\n };\n```\n\n## MassActionsButtonPropsLinkButton\n\n```typescript\ntype MassActionsButtonPropsLinkButton = DataAttributes &\n Partial<LinkButtonProps> & {\n type?: 'linkButton';\n view?: LinkView<LinkButtonView>;\n /**\n * Dropdown для кнопки.\n * Используется универсальный DropdownProps, который работает и с обычным Dropdown, и с TableDropdown\n */\n dropdown?: DropdownProps & { $css?: CSSObject };\n disabledTooltipProps?: TooltipProps;\n };\n```",
|
|
54031
54704
|
"api": [
|
|
54032
54705
|
{
|
|
@@ -54409,11 +55082,11 @@
|
|
|
54409
55082
|
"legacy": false,
|
|
54410
55083
|
"summary": "*tableConfig.filtering**",
|
|
54411
55084
|
"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)",
|
|
54412
|
-
"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 * callback при переключении тогла «Итоговые строки» в настройках таблицы.\n * Вызывается только по действию пользователя (не при монтировании),\n * поэтому подходит для сохранения выбора, например, в localStorage.\n * Сохранённое значение передавайте обратно в `showDefault`.\n */\n onChange?: (checked: boolean) => void;\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\n/**\n * Видимость сторон рамки ячейки: true рисовать, false не рисовать, не задано -\n * работает уровень ниже (настройка колонки, строки или общая).\n */\nexport type CellBorderVisibility = {\n top?: boolean;\n right?: boolean;\n bottom?: boolean;\n left?: boolean;\n};\n\n/**\n * Управление рамками (линиями) таблицы: включение и выключение. Уровни, от\n * слабого к сильному: общие настройки (vertical, horizontal), затем колонка\n * (getVerticalBorder) и строка (getHorizontalBorder), затем ячейка\n * (getCellBorder).\n */\nexport type BordersConfig<RowType = ObjectForExtending> = {\n /** Рисовать ли вертикальные линии между колонками. @default true */\n vertical?: boolean;\n /** Рисовать ли горизонтальные линии между строками тела. @default true */\n horizontal?: boolean;\n /**\n * Точечное управление вертикальной линией справа от колонки (разделитель\n * после неё). Вернуть true или false, чтобы переопределить общую настройку\n * vertical, или undefined, чтобы оставить её. Зовётся на каждую видимую\n * колонку при перерисовке, поэтому функция должна быть быстрой.\n */\n getVerticalBorder?: (params: {\n /** Ключ колонки, справа от которой рисуется линия. */\n columnKey: string;\n /** Индекс колонки в порядке отрисовки (закреплённые в начале). */\n columnIndex: number;\n }) => boolean | undefined;\n /**\n * Точечное управление горизонтальной линией сверху строки. Вернуть true или\n * false, чтобы переопределить общую настройку horizontal, или undefined,\n * чтобы оставить её. Для summary-строк не вызывается. Зовётся на каждую\n * видимую строку при перерисовке, поэтому функция должна быть быстрой.\n */\n getHorizontalBorder?: (params: {\n /** Строка под линией (линия рисуется сверху этой строки). */\n row: RowType;\n /** Индекс строки среди отображаемых. При раскрытии subRows индексы сдвигаются. */\n rowIndex: number;\n /** Уровень вложенности subRows: 0 корень, 1 и больше дочерние. */\n treeLvl: number;\n }) => boolean | undefined;\n /**\n * Стороны рамки конкретной ячейки, вкл и выкл. Для ячеек без переопределений\n * возвращать undefined. Включает отрисовку линий с разбивкой по ячейкам,\n * поэтому функция должна быть быстрой: без тяжёлых вычислений и с готовыми\n * объектами-константами вместо новых на каждый вызов. Для summary-строк не\n * вызывается.\n */\n getCellBorder?: (params: {\n /** Индекс колонки среди отображаемых (без служебных). */\n col: number;\n /** Ключ колонки. */\n columnKey: string | undefined;\n /** Строка ячейки. */\n row: RowType;\n /** Индекс строки среди отображаемых. */\n rowIndex: number;\n /** Уровень вложенности subRows: 0 корень, 1 и больше дочерние. */\n treeLvl: number;\n }) => CellBorderVisibility | undefined;\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 * Управление рамками (линиями) таблицы: включение и выключение.\n *\n * Уровни, от слабого к сильному: общие настройки (vertical, horizontal),\n * затем колонка (getVerticalBorder) и строка (getHorizontalBorder), затем\n * ячейка (getCellBorder).\n *\n * `vertical: false` и `horizontal: false` убирают все вертикальные или\n * горизонтальные линии тела. `getCellBorder` включает и выключает стороны\n * рамки конкретной ячейки; при его использовании линии рисуются с разбивкой\n * по ячейкам.\n */\n borders?: BordersConfig<RowType>;\n /**\n * rowSize - размеры строк таблицы\n */\n rowSize?: Prettify<RowSize>;\n /**\n * rowHeight - размер высоты строк таблицы\n */\n rowHeight?: Maybe<number | RowHeightFunc<RowType>>;\n /**\n * headerRowHeight - высота одного ряда шапки (в px). По умолчанию 33.\n *\n * Значение применяется к КАЖДОМУ уровню шапки: как к листовому (нижнему) ряду\n * колонок, так и к каждому уровню объединённых (групповых) заголовков. Поэтому\n * при N уровнях группировки итоговая высота шапки = headerRowHeight * (1 + N).\n * Например, headerRowHeight={50} при 2 уровнях групп даст шапку 50 + 50 + 50 = 150px.\n */\n headerRowHeight?: Maybe<number>;\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```",
|
|
55085
|
+
"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 * Общие настройки пользовательских вкладок левой и правой панели TableCanvas.\n */\nexport type TableCanvasSidebarConfig = {\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 /**\n * Ширина контента без полоски вкладок (44px). Число — px, строка — CSS.\n * Проценты считаются от ширины рабочей области TableCanvas.\n * Изменение пропса сразу меняет ширину открытой панели.\n * По умолчанию: 300px слева, 400px справа.\n */\n width?: string | number;\n};\n\n/** Настройки правой панели; встроенные вкладки доступны только справа. */\nexport type SidebarConfig = TableCanvasSidebarConfig & {\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\n/** Конфигурация правой панели. SidebarConfig сохранён для совместимости. */\nexport type RightSidebarConfig = SidebarConfig;\n\n/** Пользовательские вкладки слева; встроенных вкладок настроек нет. */\nexport type LeftSidebarConfig = TableCanvasSidebarConfig;\n\n/** Нижний слот под canvas, над пагинацией, между боковыми панелями. */\nexport type BottomSheetConfig = {\n /** @default true */\n enabled?: boolean;\n /** Число — px, строка — CSS; 'auto' — по содержимому. Проценты — от рабочей области. @default 32 */\n height?: string | number;\n /** Минимальная высота, ограниченная доступным пространством. @default 32 */\n minHeight?: string | number;\n /** Максимальная высота в px или CSS, дополнительно ограниченная доступным пространством. */\n maxHeight?: string | number;\n /** Пользователь управляет содержимым и раскрытием; при height: 'auto' панель прокручивается сама. */\n content: React.ReactNode;\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 * callback при переключении тогла «Итоговые строки» в настройках таблицы.\n * Вызывается только по действию пользователя (не при монтировании),\n * поэтому подходит для сохранения выбора, например, в localStorage.\n * Сохранённое значение передавайте обратно в `showDefault`.\n */\n onChange?: (checked: boolean) => void;\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\n/**\n * Видимость сторон рамки ячейки: true рисовать, false не рисовать, не задано -\n * работает уровень ниже (настройка колонки, строки или общая).\n */\nexport type CellBorderVisibility = {\n top?: boolean;\n right?: boolean;\n bottom?: boolean;\n left?: boolean;\n};\n\n/**\n * Управление рамками (линиями) таблицы: включение и выключение. Уровни, от\n * слабого к сильному: общие настройки (vertical, horizontal), затем колонка\n * (getVerticalBorder) и строка (getHorizontalBorder), затем ячейка\n * (getCellBorder).\n */\nexport type BordersConfig<RowType = ObjectForExtending> = {\n /** Рисовать ли вертикальные линии между колонками. @default true */\n vertical?: boolean;\n /** Рисовать ли горизонтальные линии между строками тела. @default true */\n horizontal?: boolean;\n /**\n * Точечное управление вертикальной линией справа от колонки (разделитель\n * после неё). Вернуть true или false, чтобы переопределить общую настройку\n * vertical, или undefined, чтобы оставить её. Зовётся на каждую видимую\n * колонку при перерисовке, поэтому функция должна быть быстрой.\n */\n getVerticalBorder?: (params: {\n /** Ключ колонки, справа от которой рисуется линия. */\n columnKey: string;\n /** Индекс колонки в порядке отрисовки (закреплённые в начале). */\n columnIndex: number;\n }) => boolean | undefined;\n /**\n * Точечное управление горизонтальной линией сверху строки. Вернуть true или\n * false, чтобы переопределить общую настройку horizontal, или undefined,\n * чтобы оставить её. Для summary-строк не вызывается. Зовётся на каждую\n * видимую строку при перерисовке, поэтому функция должна быть быстрой.\n */\n getHorizontalBorder?: (params: {\n /** Строка под линией (линия рисуется сверху этой строки). */\n row: RowType;\n /** Индекс строки среди отображаемых. При раскрытии subRows индексы сдвигаются. */\n rowIndex: number;\n /** Уровень вложенности subRows: 0 корень, 1 и больше дочерние. */\n treeLvl: number;\n }) => boolean | undefined;\n /**\n * Стороны рамки конкретной ячейки, вкл и выкл. Для ячеек без переопределений\n * возвращать undefined. Включает отрисовку линий с разбивкой по ячейкам,\n * поэтому функция должна быть быстрой: без тяжёлых вычислений и с готовыми\n * объектами-константами вместо новых на каждый вызов. Для summary-строк не\n * вызывается.\n */\n getCellBorder?: (params: {\n /** Индекс колонки среди отображаемых (без служебных). */\n col: number;\n /** Ключ колонки. */\n columnKey: string | undefined;\n /** Строка ячейки. */\n row: RowType;\n /** Индекс строки среди отображаемых. */\n rowIndex: number;\n /** Уровень вложенности subRows: 0 корень, 1 и больше дочерние. */\n treeLvl: number;\n }) => CellBorderVisibility | undefined;\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-подсветка ВКЛЮЧЕНА (цвета из темы);\n * `{ row: false }` — выключить явно.\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 * Управление рамками (линиями) таблицы: включение и выключение.\n *\n * Уровни, от слабого к сильному: общие настройки (vertical, horizontal),\n * затем колонка (getVerticalBorder) и строка (getHorizontalBorder), затем\n * ячейка (getCellBorder).\n *\n * `vertical: false` и `horizontal: false` убирают все вертикальные или\n * горизонтальные линии тела. `getCellBorder` включает и выключает стороны\n * рамки конкретной ячейки; при его использовании линии рисуются с разбивкой\n * по ячейкам.\n */\n borders?: BordersConfig<RowType>;\n /**\n * rowSize - размеры строк таблицы\n */\n rowSize?: Prettify<RowSize>;\n /**\n * rowHeight - размер высоты строк таблицы\n */\n rowHeight?: Maybe<number | RowHeightFunc<RowType>>;\n /**\n * headerRowHeight - высота одного ряда шапки (в px). По умолчанию 33.\n *\n * Значение применяется к КАЖДОМУ уровню шапки: как к листовому (нижнему) ряду\n * колонок, так и к каждому уровню объединённых (групповых) заголовков. Поэтому\n * при N уровнях группировки итоговая высота шапки = headerRowHeight * (1 + N).\n * Например, headerRowHeight={50} при 2 уровнях групп даст шапку 50 + 50 + 50 = 150px.\n */\n headerRowHeight?: Maybe<number>;\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 /**\n * stickyColumns - колонки, которые прилипают к левому краю при горизонтальной прокрутке,\n * как `position: sticky`. Ключи колонок или предикат по колонке.\n *\n * ```tsx\n * tableConfig={{ stickyColumns: ['region', 'total'] }}\n * tableConfig={{ stickyColumns: (column) => column.key.startsWith('total') }}\n * ```\n */\n stickyColumns?: StickyColumnsConfig<ColumnConfig<RowType, SummaryRowType>>;\n\n /**\n * stickyRows - строки, которые прилипают под шапкой при вертикальной прокрутке.\n * Предикат проверяется для каждой отображаемой строки данных (результаты кешируются); строки групп\n * (`rowsGrouping`) и заглушки загрузки в него не попадают и липкими не становятся.\n * Индексы передаются как есть — удобно для больших таблиц, где позиции известны заранее. Они\n * считаются по итоговому отображаемому списку: сортировка, фильтры, группировка и раскрытые узлы\n * дерева (`subRows`) сдвигают нумерацию — тогда индексы нужно пересчитывать или передать предикат.\n *\n * ```tsx\n * tableConfig={{ stickyRows: (row) => row.isSubtotal }}\n * tableConfig={{ stickyRows: [0, 41, 82] }}\n * ```\n */\n stickyRows?: StickyRowsConfig<RowType>;\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 /** @deprecated Используйте rightSidebarConfig. При наличии обоих приоритет у rightSidebarConfig. */\n sidebarConfig?: SidebarConfig;\n /** Конфигурация правой панели. */\n rightSidebarConfig?: RightSidebarConfig;\n /** Конфигурация пользовательских вкладок левой панели (режим строк). */\n leftSidebarConfig?: LeftSidebarConfig;\n /** Нижний слот в режиме строк. Не увеличивает внешний контейнер таблицы. */\n bottomSheetConfig?: BottomSheetConfig;\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```",
|
|
54413
55086
|
"api": [
|
|
54414
55087
|
{
|
|
54415
55088
|
"typeName": "FilteringConfig",
|
|
54416
|
-
"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 * callback при переключении тогла «Итоговые строки» в настройках таблицы.\n * Вызывается только по действию пользователя (не при монтировании),\n * поэтому подходит для сохранения выбора, например, в localStorage.\n * Сохранённое значение передавайте обратно в `showDefault`.\n */\n onChange?: (checked: boolean) => void;\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\n/**\n * Видимость сторон рамки ячейки: true рисовать, false не рисовать, не задано -\n * работает уровень ниже (настройка колонки, строки или общая).\n */\nexport type CellBorderVisibility = {\n top?: boolean;\n right?: boolean;\n bottom?: boolean;\n left?: boolean;\n};\n\n/**\n * Управление рамками (линиями) таблицы: включение и выключение. Уровни, от\n * слабого к сильному: общие настройки (vertical, horizontal), затем колонка\n * (getVerticalBorder) и строка (getHorizontalBorder), затем ячейка\n * (getCellBorder).\n */\nexport type BordersConfig<RowType = ObjectForExtending> = {\n /** Рисовать ли вертикальные линии между колонками. @default true */\n vertical?: boolean;\n /** Рисовать ли горизонтальные линии между строками тела. @default true */\n horizontal?: boolean;\n /**\n * Точечное управление вертикальной линией справа от колонки (разделитель\n * после неё). Вернуть true или false, чтобы переопределить общую настройку\n * vertical, или undefined, чтобы оставить её. Зовётся на каждую видимую\n * колонку при перерисовке, поэтому функция должна быть быстрой.\n */\n getVerticalBorder?: (params: {\n /** Ключ колонки, справа от которой рисуется линия. */\n columnKey: string;\n /** Индекс колонки в порядке отрисовки (закреплённые в начале). */\n columnIndex: number;\n }) => boolean | undefined;\n /**\n * Точечное управление горизонтальной линией сверху строки. Вернуть true или\n * false, чтобы переопределить общую настройку horizontal, или undefined,\n * чтобы оставить её. Для summary-строк не вызывается. Зовётся на каждую\n * видимую строку при перерисовке, поэтому функция должна быть быстрой.\n */\n getHorizontalBorder?: (params: {\n /** Строка под линией (линия рисуется сверху этой строки). */\n row: RowType;\n /** Индекс строки среди отображаемых. При раскрытии subRows индексы сдвигаются. */\n rowIndex: number;\n /** Уровень вложенности subRows: 0 корень, 1 и больше дочерние. */\n treeLvl: number;\n }) => boolean | undefined;\n /**\n * Стороны рамки конкретной ячейки, вкл и выкл. Для ячеек без переопределений\n * возвращать undefined. Включает отрисовку линий с разбивкой по ячейкам,\n * поэтому функция должна быть быстрой: без тяжёлых вычислений и с готовыми\n * объектами-константами вместо новых на каждый вызов. Для summary-строк не\n * вызывается.\n */\n getCellBorder?: (params: {\n /** Индекс колонки среди отображаемых (без служебных). */\n col: number;\n /** Ключ колонки. */\n columnKey: string | undefined;\n /** Строка ячейки. */\n row: RowType;\n /** Индекс строки среди отображаемых. */\n rowIndex: number;\n /** Уровень вложенности subRows: 0 корень, 1 и больше дочерние. */\n treeLvl: number;\n }) => CellBorderVisibility | undefined;\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 * Управление рамками (линиями) таблицы: включение и выключение.\n *\n * Уровни, от слабого к сильному: общие настройки (vertical, horizontal),\n * затем колонка (getVerticalBorder) и строка (getHorizontalBorder), затем\n * ячейка (getCellBorder).\n *\n * `vertical: false` и `horizontal: false` убирают все вертикальные или\n * горизонтальные линии тела. `getCellBorder` включает и выключает стороны\n * рамки конкретной ячейки; при его использовании линии рисуются с разбивкой\n * по ячейкам.\n */\n borders?: BordersConfig<RowType>;\n /**\n * rowSize - размеры строк таблицы\n */\n rowSize?: Prettify<RowSize>;\n /**\n * rowHeight - размер высоты строк таблицы\n */\n rowHeight?: Maybe<number | RowHeightFunc<RowType>>;\n /**\n * headerRowHeight - высота одного ряда шапки (в px). По умолчанию 33.\n *\n * Значение применяется к КАЖДОМУ уровню шапки: как к листовому (нижнему) ряду\n * колонок, так и к каждому уровню объединённых (групповых) заголовков. Поэтому\n * при N уровнях группировки итоговая высота шапки = headerRowHeight * (1 + N).\n * Например, headerRowHeight={50} при 2 уровнях групп даст шапку 50 + 50 + 50 = 150px.\n */\n headerRowHeight?: Maybe<number>;\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 *"
|
|
55089
|
+
"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 * Общие настройки пользовательских вкладок левой и правой панели TableCanvas.\n */\nexport type TableCanvasSidebarConfig = {\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 /**\n * Ширина контента без полоски вкладок (44px). Число — px, строка — CSS.\n * Проценты считаются от ширины рабочей области TableCanvas.\n * Изменение пропса сразу меняет ширину открытой панели.\n * По умолчанию: 300px слева, 400px справа.\n */\n width?: string | number;\n};\n\n/** Настройки правой панели; встроенные вкладки доступны только справа. */\nexport type SidebarConfig = TableCanvasSidebarConfig & {\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\n/** Конфигурация правой панели. SidebarConfig сохранён для совместимости. */\nexport type RightSidebarConfig = SidebarConfig;\n\n/** Пользовательские вкладки слева; встроенных вкладок настроек нет. */\nexport type LeftSidebarConfig = TableCanvasSidebarConfig;\n\n/** Нижний слот под canvas, над пагинацией, между боковыми панелями. */\nexport type BottomSheetConfig = {\n /** @default true */\n enabled?: boolean;\n /** Число — px, строка — CSS; 'auto' — по содержимому. Проценты — от рабочей области. @default 32 */\n height?: string | number;\n /** Минимальная высота, ограниченная доступным пространством. @default 32 */\n minHeight?: string | number;\n /** Максимальная высота в px или CSS, дополнительно ограниченная доступным пространством. */\n maxHeight?: string | number;\n /** Пользователь управляет содержимым и раскрытием; при height: 'auto' панель прокручивается сама. */\n content: React.ReactNode;\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 * callback при переключении тогла «Итоговые строки» в настройках таблицы.\n * Вызывается только по действию пользователя (не при монтировании),\n * поэтому подходит для сохранения выбора, например, в localStorage.\n * Сохранённое значение передавайте обратно в `showDefault`.\n */\n onChange?: (checked: boolean) => void;\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\n/**\n * Видимость сторон рамки ячейки: true рисовать, false не рисовать, не задано -\n * работает уровень ниже (настройка колонки, строки или общая).\n */\nexport type CellBorderVisibility = {\n top?: boolean;\n right?: boolean;\n bottom?: boolean;\n left?: boolean;\n};\n\n/**\n * Управление рамками (линиями) таблицы: включение и выключение. Уровни, от\n * слабого к сильному: общие настройки (vertical, horizontal), затем колонка\n * (getVerticalBorder) и строка (getHorizontalBorder), затем ячейка\n * (getCellBorder).\n */\nexport type BordersConfig<RowType = ObjectForExtending> = {\n /** Рисовать ли вертикальные линии между колонками. @default true */\n vertical?: boolean;\n /** Рисовать ли горизонтальные линии между строками тела. @default true */\n horizontal?: boolean;\n /**\n * Точечное управление вертикальной линией справа от колонки (разделитель\n * после неё). Вернуть true или false, чтобы переопределить общую настройку\n * vertical, или undefined, чтобы оставить её. Зовётся на каждую видимую\n * колонку при перерисовке, поэтому функция должна быть быстрой.\n */\n getVerticalBorder?: (params: {\n /** Ключ колонки, справа от которой рисуется линия. */\n columnKey: string;\n /** Индекс колонки в порядке отрисовки (закреплённые в начале). */\n columnIndex: number;\n }) => boolean | undefined;\n /**\n * Точечное управление горизонтальной линией сверху строки. Вернуть true или\n * false, чтобы переопределить общую настройку horizontal, или undefined,\n * чтобы оставить её. Для summary-строк не вызывается. Зовётся на каждую\n * видимую строку при перерисовке, поэтому функция должна быть быстрой.\n */\n getHorizontalBorder?: (params: {\n /** Строка под линией (линия рисуется сверху этой строки). */\n row: RowType;\n /** Индекс строки среди отображаемых. При раскрытии subRows индексы сдвигаются. */\n rowIndex: number;\n /** Уровень вложенности subRows: 0 корень, 1 и больше дочерние. */\n treeLvl: number;\n }) => boolean | undefined;\n /**\n * Стороны рамки конкретной ячейки, вкл и выкл. Для ячеек без переопределений\n * возвращать undefined. Включает отрисовку линий с разбивкой по ячейкам,\n * поэтому функция должна быть быстрой: без тяжёлых вычислений и с готовыми\n * объектами-константами вместо новых на каждый вызов. Для summary-строк не\n * вызывается.\n */\n getCellBorder?: (params: {\n /** Индекс колонки среди отображаемых (без служебных). */\n col: number;\n /** Ключ колонки. */\n columnKey: string | undefined;\n /** Строка ячейки. */\n row: RowType;\n /** Индекс строки среди отображаемых. */\n rowIndex: number;\n /** Уровень вложенности subRows: 0 корень, 1 и больше дочерние. */\n treeLvl: number;\n }) => CellBorderVisibility | undefined;\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-подсветка ВКЛЮЧЕНА (цвета из темы);\n * `{ row: false }` — выключить явно.\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 * Управление рамками (линиями) таблицы: включение и выключение.\n *\n * Уровни, от слабого к сильному: общие настройки (vertical, horizontal),\n * затем колонка (getVerticalBorder) и строка (getHorizontalBorder), затем\n * ячейка (getCellBorder).\n *\n * `vertical: false` и `horizontal: false` убирают все вертикальные или\n * горизонтальные линии тела. `getCellBorder` включает и выключает стороны\n * рамки конкретной ячейки; при его использовании линии рисуются с разбивкой\n * по ячейкам.\n */\n borders?: BordersConfig<RowType>;\n /**\n * rowSize - размеры строк таблицы\n */\n rowSize?: Prettify<RowSize>;\n /**\n * rowHeight - размер высоты строк таблицы\n */\n rowHeight?: Maybe<number | RowHeightFunc<RowType>>;\n /**\n * headerRowHeight - высота одного ряда шапки (в px). По умолчанию 33.\n *\n * Значение применяется к КАЖДОМУ уровню шапки: как к листовому (нижнему) ряду\n * колонок, так и к каждому уровню объединённых (групповых) заголовков. Поэтому\n * при N уровнях группировки итоговая высота шапки = headerRowHeight * (1 + N).\n * Например, headerRowHeight={50} при 2 уровнях групп даст шапку 50 + 50 + 50 = 150px.\n */\n headerRowHeight?: Maybe<number>;\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 *"
|
|
54417
55090
|
},
|
|
54418
55091
|
{
|
|
54419
55092
|
"typeName": "FilterComponentInPopoverProps",
|
|
@@ -54614,12 +55287,12 @@
|
|
|
54614
55287
|
"feature": "HoverEffects",
|
|
54615
55288
|
"legacy": false,
|
|
54616
55289
|
"summary": "Эффекты при наведении — единый расширяемый конфиг `tableConfig.hoverEffects`.",
|
|
54617
|
-
"docs": "# Hover Effects\n\nЭффекты при наведении — единый расширяемый конфиг `tableConfig.hoverEffects`.\nСейчас поддерживается **подсветка строки под курсором** (`row`). Чисто
|
|
54618
|
-
"apiDocs": "# HoverEffects API\n\n## HoverEffectsConfig\n\n`tableConfig.hoverEffects` — единый конфиг эффектов при наведении. Значения,\nцвета по зонам строки и приоритет слоёв описаны в комментариях к типу.\n\n```typescript\ntype HoverEffectsConfig = {\n /**\n * Подсветка строки под курсором. По умолчанию
|
|
55290
|
+
"docs": "# Hover Effects\n\nЭффекты при наведении — единый расширяемый конфиг `tableConfig.hoverEffects`.\nСейчас поддерживается **подсветка строки под курсором** (`row`). Чисто визуальная\nфича, по умолчанию **включена** (цвета из темы). В будущем в этом же объекте\nпоявятся hover по ячейке и т.д.\n\n## Как выключить\n\n```tsx\ntableConfig={{ hoverEffects: { row: false } }}\n```\n\n## Цвета (уровень темы)\n\n- **data-ячейки** hovered-строки — серый `bgRowHovered`;\n- **служебные колонки** (нумерация / чекбокс / инструменты строк) hovered-строки\n не сереют — темнеют голубым `bgServiceRowHovered`, тем же цветом, что\n сервис-зона при селектинге;\n- строка, **отмеченная чекбоксом** (`selecting`), под курсором темнеет целиком —\n `bgSelectedRowHovered` (как hover шапки), вместо серого.\n\n## Приоритеты слоёв (важно)\n\nHover — **самый нижний визуальный слой**, он не конкурирует с выделением:\n\n- выделение ячеек/строк/колонок (`cellsSelection`) и «залипшая» активная строка\n (`highlightActiveType='row'`) рисуются **поверх** и перекрывают hover;\n- после сброса выделения hover под курсором снова виден;\n- summary-строки hover не получают.\n\n## Особенности\n\n- Работает по всей строке: hover срабатывает над любой ячейкой строки,\n включая нумерацию и чекбокс.\n- Уход мыши с таблицы (или на шапку/групп-хедер) сбрасывает подсветку.\n- Не требует `themeOverride` и не влияет на copy/paste и прочую логику\n выделения — ось полностью независимая. Не путать с `highlightActiveType` —\n тот подсвечивает строку по **клику** («залипает»), hover — по наведению.\n\n> Подробнее о типах — [HoverEffects API](?path=/docs/локальные-компоненты-tablecanvas-hovereffects-api--docs)\n\n> Внутреннее устройство и почему такие приоритеты — в доке\n> `packages/ui-kit/src/components/TableCanvas/docs/SelectionAndHighlighting.md`,\n> раздел 7.",
|
|
55291
|
+
"apiDocs": "# HoverEffects API\n\n## HoverEffectsConfig\n\n`tableConfig.hoverEffects` — единый конфиг эффектов при наведении. Значения,\nцвета по зонам строки и приоритет слоёв описаны в комментариях к типу.\n\n```typescript\ntype HoverEffectsConfig = {\n /**\n * Подсветка строки под курсором. По умолчанию ВКЛЮЧЕНА.\n * - не задано или `true` — включена, цвета из темы;\n * - `false` — выключена явно.\n *\n * Цвета по зонам строки берутся из темы:\n * - data-ячейки — `bgRowHovered`;\n * - служебные колонки (нумерация, чекбокс) — `bgServiceRowHovered`, тот же\n * цвет, что у сервис-зоны при выделении;\n * - строка, отмеченная чекбоксом, темнеет целиком `bgSelectedRowHovered`;\n * - выбранная строка (`highlightActiveType: 'row'`) под курсором делает\n * шаг глубже: hover (с нажатым чекбоксом — hover2), цветные ячейки —\n * свой hover2.\n *\n * Hover — самый нижний слой: выделение ячеек, строк и колонок рисуется\n * поверх и перекрывает его; после сброса выделения он снова виден.\n * Summary-строки hover не получают.\n */\n row?: boolean;\n};\n```",
|
|
54619
55292
|
"api": [
|
|
54620
55293
|
{
|
|
54621
55294
|
"typeName": "HoverEffectsConfig",
|
|
54622
|
-
"source": "type HoverEffectsConfig = {\n /**\n * Подсветка строки под курсором. По умолчанию
|
|
55295
|
+
"source": "type HoverEffectsConfig = {\n /**\n * Подсветка строки под курсором. По умолчанию ВКЛЮЧЕНА.\n * - не задано или `true` — включена, цвета из темы;\n * - `false` — выключена явно.\n *\n * Цвета по зонам строки берутся из темы:\n * - data-ячейки — `bgRowHovered`;\n * - служебные колонки (нумерация, чекбокс) — `bgServiceRowHovered`, тот же\n * цвет, что у сервис-зоны при выделении;\n * - строка, отмеченная чекбоксом, темнеет целиком `bgSelectedRowHovered`;\n * - выбранная строка (`highlightActiveType: 'row'`) под курсором делает\n * шаг глубже: hover (с нажатым чекбоксом — hover2), цветные ячейки —\n * свой hover2.\n *\n * Hover — самый нижний слой: выделение ячеек, строк и колонок рисуется\n * поверх и перекрывает его; после сброса выделения он снова виден.\n * Summary-строки hover не получают.\n */\n row?: boolean;\n};"
|
|
54623
55296
|
}
|
|
54624
55297
|
],
|
|
54625
55298
|
"stories": [
|
|
@@ -55092,13 +55765,25 @@
|
|
|
55092
55765
|
"component": "TableCanvas",
|
|
55093
55766
|
"feature": "Sidebar",
|
|
55094
55767
|
"legacy": false,
|
|
55095
|
-
"summary": "
|
|
55096
|
-
"docs": "# Sidebar (TableCanvas)\n\n
|
|
55097
|
-
"apiDocs": "# Sidebar API\n\n##
|
|
55768
|
+
"summary": "Боковые панели таблицы с независимыми вкладками и произвольным React-контентом. Левая панель задаётся через `tableConfig.leftSidebarConfig`, правая — через `tableConfig.rightSidebarConfig`.",
|
|
55769
|
+
"docs": "# Sidebar (TableCanvas)\n\nБоковые панели таблицы с независимыми вкладками и произвольным React-контентом. Левая панель задаётся через `tableConfig.leftSidebarConfig`, правая — через `tableConfig.rightSidebarConfig`.\n\n## Ключевые особенности\n\n- Пользовательские вкладки с обеих сторон: навигация, сведения, дополнительные действия.\n- Встроенные настройки таблицы, колонок и фильтров в правой панели.\n- Независимое управление открытием и активной вкладкой каждой панели.\n- Динамическая ширина в пикселях, CSS-единицах, процентах и `calc()`.\n- Разная ширина панели для разных вкладок.\n- Совместимость правой панели с `tableConfig.sidebarConfig`.\n\n## Левая и правая панели\n\nНастройки пользовательских вкладок, ширины и открытия одинаковы для обеих сторон. Панелями можно управлять независимо.\n\nСлева доступны пользовательские вкладки. Справа дополнительно поддерживается `defaultTabs` для встроенных настроек таблицы, колонок и фильтров. Обе панели могут быть открыты одновременно на разных вкладках.\n\nДля правой панели `sidebarConfig` поддерживается как алиас `rightSidebarConfig`. Если переданы оба имени, используется `rightSidebarConfig`.\n\n## Пользовательские вкладки\n\nВ `customTabs` передайте вкладки с уникальным `id`, текстом подсказки `label`, иконкой `icon` и содержимым `content: ReactNode`. На полоске вкладок показывается иконка. `title` задаёт заголовок открытого контента; если его нет, используется `label`. `titleRightSlot` добавляет элемент справа от заголовка. `domMetadata` позволяет добавить data-атрибуты и классы для тестирования и аналитики.\n\nТип пользовательской вкладки импортируется как `TableCanvasSidebarTab` из `@daisforge/ui/components/TableCanvas`.\n\n`showInSidebar: false` скрывает вкладку. Через `customTabsOrder` можно изменить порядок пользовательских вкладок. Клик по вкладке открывает её; повторный клик по активной вкладке или крестик закрывает соответствующую панель. `enabled: false` отключает интерфейс панели.\n\n## Встроенные настройки справа\n\nНастройки открываются одной кнопкой-шестерёнкой. Внутри доступны разделы:\n\n- **Общие настройки** (`tableSettings`) — итоговые строки, выбор строк и пользовательские возможности из ControlBlock. `customGeneralSettingsSlot` добавляет контент после общих настроек.\n- **Колонки** (`columns`) — видимость, порядок и закрепление колонок. Доступен при включённом `columnsControl`.\n- **Фильтры** (`filtering`) — управление фильтрацией данных. Доступен при включённом `filtering`.\n\nЧерез `defaultTabs` можно переопределить подпись `label`, заголовок `title`, слот `titleRightSlot`, метаданные `domMetadata` и видимость `showInSidebar`. Для `tableSettings` также доступны `customGeneralSettingsSlot` и `iconTooltipText` — тултип кнопки-шестерёнки.\n\nЧтобы убрать все встроенные вкладки, передайте `showInSidebar: false` для каждого ID: `tableSettings`, `columns` и `filtering`. Пустой массив `defaultTabs` не отключает автоматически появляющиеся настройки.\n\n## Управление открытием и вкладкой\n\nПо умолчанию каждая панель закрыта. Можно задать начальное открытие и вкладку или управлять ими из своего компонента.\n\n- `defaultOpen` открывает панель при первом рендере.\n- `defaultActiveTabId` выбирает начальную вкладку. Если её нет или она скрыта, используется первая доступная.\n- `openState: [open, setOpen]` управляет открытием извне; при его наличии `defaultOpen` игнорируется.\n- `activeTabState: [activeTabId, setActiveTabId]` управляет активной вкладкой извне; при его наличии `defaultActiveTabId` игнорируется.\n- `onActiveTabChange(id, tab)` сообщает о выборе вкладки. При закрытии `id` равен `null`.\n\nДля внешнего открытия конкретной вкладки передайте `openState` и `activeTabState`, затем установите нужный ID и `open: true`.\n\n## Ширина\n\n`width` задаёт ширину контента без полоски вкладок 44px. Слева ширина контента по умолчанию 300px, справа — 400px; целиком открытые панели занимают 344px и 444px соответственно.\n\nЧисло означает пиксели; строка позволяет задать CSS-размер: `'320px'`, `'25%'`, `'calc(20% + 40px)'`. Проценты считаются от общей ширины рабочей области TableCanvas. Изменение `width` обновляет размер открытой панели; переход анимируется за 0.5 секунды.\n\nУ отдельной вкладки нет собственного `width`. Для разных размеров вкладок меняйте ширину панели по ID в `onActiveTabChange`. При `null` оставляйте прежний размер. Примеры ниже показывают 300px слева и 400px справа для вкладки «Отчёты», а для «Книги» — 35%.\n\nНа узком контейнере с левой или обеими панелями их контент сжимается, оставляя место для данных; полоски вкладок сохраняют ширину 44px. Если задана только правая панель, её ширина не сжимается.\n\n## Хуки внутри контента\n\n```tsx\n\n```\n\n`useLeftSidebar()` возвращает `isOpen`, `width: string | number` и `toggle()`. Шириной слева управляет `leftSidebarConfig.width`.\n\n`useRightSidebar()` и его алиас `useSidebar()` возвращают `isOpen`, `width: number`, `toggle()` и `setWidth(number)`. Если ширина не задана через `rightSidebarConfig.width`, её можно менять вызовом `setWidth(number)`; по умолчанию она равна 400px. Ширина из конфига имеет приоритет.\n\nИспользуйте эти хуки в компонентах, переданных в `content` вкладки. `useLeftSidebar` и `useRightSidebar` также доступны из `@daisforge/ui`. Для TableCanvas импортируйте `useSidebar` из `@daisforge/ui/components/TableCanvas`: `useSidebar` из корневого `@daisforge/ui` относится к компоненту `Table`.\n\n## Особенности\n\nПанели отображаются в режиме строк. При сворачивании таблицы они скрываются и исключаются из фокуса; размеры и выбранные вкладки сохраняются до разворачивания. Поддерживаются полноэкранный режим и совместная работа с нижней панелью BottomSheet.\n\nОткрытие любой Sidebar автоматически сворачивает панель массовых действий. Она автоматически разворачивается после закрытия всех Sidebar. Ручное сворачивание и разворачивание остаются доступными.\n\nНижняя панель и совместный пример со сворачиванием, пагинацией и другими возможностями — в разделе [BottomSheet](?path=/docs/локальные-компоненты-tablecanvas-bottomsheet--docs).\n\n## Примеры\n\n- **С кастомной вкладкой** — информация о строках и текущем выделении в правой панели.\n- **Открыт по умолчанию** — начальная пользовательская вкладка.\n- **Внешнее управление активной вкладкой** — открытие выбранной вкладки и закрытие панели кнопками.\n- **Колбэк активной вкладки** — текущая вкладка по уведомлениям панели.\n- **Левая панель** — пользовательская навигация с поиском, управлением открытием и шириной по ID вкладки.\n- **Правая панель** — пользовательский контент с разной шириной вкладок и отключёнными встроенными настройками.\n\nОписание типов — в разделе [Sidebar API](?path=/docs/локальные-компоненты-tablecanvas-sidebar-api--docs).",
|
|
55770
|
+
"apiDocs": "# Sidebar API\n\n## TableCanvasSidebarConfig\n\n```typescript\ntype TableCanvasSidebarConfig = {\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 /**\n * Ширина контента без полоски вкладок (44px). Число — px, строка — CSS.\n * Проценты считаются от ширины рабочей области TableCanvas.\n * Изменение пропса сразу меняет ширину открытой панели.\n * По умолчанию: 300px слева, 400px справа.\n */\n width?: string | number;\n};\n```\n\n## LeftSidebarConfig\n\n```typescript\ntype LeftSidebarConfig = TableCanvasSidebarConfig;\n```\n\n## RightSidebarConfig\n\n```typescript\ntype RightSidebarConfig = SidebarConfig;\n```\n\n## SidebarConfig\n\n```typescript\ntype SidebarConfig = TableCanvasSidebarConfig & {\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```\n\n## DefaultSidebarTabIds\n\n```typescript\ntype DefaultSidebarTabIds = 'columns' | 'tableSettings' | 'filtering';\n```\n\n## SidebarTab\n\n```typescript\ntype SidebarTab = {\n /**\n * Уникальный идентификатор таба\n */\n id: DefaultSidebarTabIds | string;\n /**\n * title таба (для Tooltip)\n */\n label: string;\n /**\n * Иконка таба\n */\n icon: ReactNode;\n /**\n * Контентная часть сайдбара\n */\n content: React.ReactNode;\n /**\n * Показывать ли в сайдбаре\n * @default true\n */\n showInSidebar?: boolean;\n /**\n * Заголовок контентной части сайдбара\n */\n title?: string;\n /**\n * Кастомный элемент справа от title в шапке сайдбара\n */\n titleRightSlot?: React.ReactNode;\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n domMetadata?: DomMetadata;\n};\n```\n\n## useLeftSidebar(): LeftSidebarContextValue\n\n```typescript\ntype LeftSidebarContextValue = Omit<\n SidebarContextValue,\n 'width' | 'setWidth'\n> & { width: string | number };\n```\n\n## useRightSidebar() / useSidebar(): SidebarContextValue\n\n```typescript\ntype SidebarContextValue = {\n isOpen: boolean;\n width: number;\n toggle: () => void;\n setWidth: (width: number) => void;\n};\n```",
|
|
55098
55771
|
"api": [
|
|
55772
|
+
{
|
|
55773
|
+
"typeName": "TableCanvasSidebarConfig",
|
|
55774
|
+
"source": "type TableCanvasSidebarConfig = {\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 /**\n * Ширина контента без полоски вкладок (44px). Число — px, строка — CSS.\n * Проценты считаются от ширины рабочей области TableCanvas.\n * Изменение пропса сразу меняет ширину открытой панели.\n * По умолчанию: 300px слева, 400px справа.\n */\n width?: string | number;\n};"
|
|
55775
|
+
},
|
|
55776
|
+
{
|
|
55777
|
+
"typeName": "LeftSidebarConfig",
|
|
55778
|
+
"source": "type LeftSidebarConfig = TableCanvasSidebarConfig;"
|
|
55779
|
+
},
|
|
55780
|
+
{
|
|
55781
|
+
"typeName": "RightSidebarConfig",
|
|
55782
|
+
"source": "type RightSidebarConfig = SidebarConfig;"
|
|
55783
|
+
},
|
|
55099
55784
|
{
|
|
55100
55785
|
"typeName": "SidebarConfig",
|
|
55101
|
-
"source": "type SidebarConfig =
|
|
55786
|
+
"source": "type SidebarConfig = TableCanvasSidebarConfig & {\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};"
|
|
55102
55787
|
},
|
|
55103
55788
|
{
|
|
55104
55789
|
"typeName": "DefaultSidebarTabIds",
|
|
@@ -55107,6 +55792,14 @@
|
|
|
55107
55792
|
{
|
|
55108
55793
|
"typeName": "SidebarTab",
|
|
55109
55794
|
"source": "type SidebarTab = {\n /**\n * Уникальный идентификатор таба\n */\n id: DefaultSidebarTabIds | string;\n /**\n * title таба (для Tooltip)\n */\n label: string;\n /**\n * Иконка таба\n */\n icon: ReactNode;\n /**\n * Контентная часть сайдбара\n */\n content: React.ReactNode;\n /**\n * Показывать ли в сайдбаре\n * @default true\n */\n showInSidebar?: boolean;\n /**\n * Заголовок контентной части сайдбара\n */\n title?: string;\n /**\n * Кастомный элемент справа от title в шапке сайдбара\n */\n titleRightSlot?: React.ReactNode;\n /**\n * Метки для автоматизированного тестирования и аналитики\n * Добавляет data-атрибуты и CSS-классы к элементам controlBlock\n */\n domMetadata?: DomMetadata;\n};"
|
|
55795
|
+
},
|
|
55796
|
+
{
|
|
55797
|
+
"typeName": "LeftSidebarContextValue",
|
|
55798
|
+
"source": "type LeftSidebarContextValue = Omit<\n SidebarContextValue,\n 'width' | 'setWidth'\n> & { width: string | number };"
|
|
55799
|
+
},
|
|
55800
|
+
{
|
|
55801
|
+
"typeName": "SidebarContextValue",
|
|
55802
|
+
"source": "type SidebarContextValue = {\n isOpen: boolean;\n width: number;\n toggle: () => void;\n setWidth: (width: number) => void;\n};"
|
|
55110
55803
|
}
|
|
55111
55804
|
],
|
|
55112
55805
|
"stories": [
|
|
@@ -55114,25 +55807,71 @@
|
|
|
55114
55807
|
"exportName": "WithCustomTab",
|
|
55115
55808
|
"displayName": "С кастомной вкладкой",
|
|
55116
55809
|
"type": "full-code",
|
|
55117
|
-
"code": "()
|
|
55810
|
+
"code": "import { TableCanvas, type ColumnConfig } from '@daisforge/ui/components/TableCanvas';\nimport { IconInfo } from '@daisforge/ui/icons';\nimport React, { useState } from 'react';\n\nfunction createSidebarData() {\n type Row = { id: number; task: string; priority: string };\n const priorities = ['Critical', 'High', 'Medium', 'Low'];\n const rows: Row[] = Array.from({ length: 12 }, (_, index) => ({\n id: index + 1,\n task: `Task ${index + 1}`,\n priority: priorities[index % priorities.length] ?? 'Low',\n }));\n const columnConfig: ColumnConfig<Row>[] = [\n { key: 'id', name: 'ID', width: 100 },\n { key: 'task', name: 'Title', width: 300 },\n { key: 'priority', name: 'Priority', width: 180 },\n ];\n return { rows, columnConfig };\n};\n\nfunction WithCustomTabExample() {\n const [{ rows, columnConfig }] = useState(createSidebarData);\n const [selectedRows, setSelectedRows] = useState<ReadonlySet<string>>(\n new Set(),\n );\n const [filters, setFilters] = useState({});\n\n return (\n <TableCanvas\n tableConfig={{\n containerStyle: { height: 480 },\n rightSidebarConfig: {\n customTabs: [\n {\n id: 'customInfo',\n label: 'Информация',\n icon: <IconInfo size=\"s\" />,\n content: (\n <>\n <p>Всего строк: {rows.length}</p>\n <p>Выбрано строк: {selectedRows.size}</p>\n </>\n ),\n title: 'Информация',\n showInSidebar: true,\n },\n ],\n },\n selecting: {\n state: [selectedRows, setSelectedRows],\n rowKeyGetter: (row) => row.id.toString(),\n },\n filtering: {\n state: [filters, setFilters],\n },\n }}\n columnConfig={columnConfig}\n rows={rows}\n />\n );\n};"
|
|
55118
55811
|
},
|
|
55119
55812
|
{
|
|
55120
55813
|
"exportName": "DefaultOpen",
|
|
55121
55814
|
"displayName": "Открыт по умолчанию на кастомной вкладке",
|
|
55122
55815
|
"type": "full-code",
|
|
55123
|
-
"code": "()
|
|
55816
|
+
"code": "import { TableCanvas, type ColumnConfig } from '@daisforge/ui/components/TableCanvas';\nimport { IconInfo } from '@daisforge/ui/icons';\nimport React, { useState } from 'react';\n\nfunction createSidebarData() {\n type Row = { id: number; task: string; priority: string };\n const priorities = ['Critical', 'High', 'Medium', 'Low'];\n const rows: Row[] = Array.from({ length: 12 }, (_, index) => ({\n id: index + 1,\n task: `Task ${index + 1}`,\n priority: priorities[index % priorities.length] ?? 'Low',\n }));\n const columnConfig: ColumnConfig<Row>[] = [\n { key: 'id', name: 'ID', width: 100 },\n { key: 'task', name: 'Title', width: 300 },\n { key: 'priority', name: 'Priority', width: 180 },\n ];\n return { rows, columnConfig };\n};\n\nfunction DefaultOpenExample() {\n const [{ rows, columnConfig }] = useState(createSidebarData);\n\n return (\n <TableCanvas\n tableConfig={{\n containerStyle: { height: 480 },\n rightSidebarConfig: {\n defaultOpen: true,\n defaultActiveTabId: 'customInfo',\n customTabs: [\n {\n id: 'customInfo',\n label: 'Информация',\n icon: <IconInfo size=\"s\" />,\n content: <p>Всего строк: {rows.length}</p>,\n title: 'Информация',\n showInSidebar: true,\n },\n ],\n },\n }}\n columnConfig={columnConfig}\n rows={rows}\n />\n );\n};"
|
|
55124
55817
|
},
|
|
55125
55818
|
{
|
|
55126
55819
|
"exportName": "ControlledActiveTab",
|
|
55127
55820
|
"displayName": "Внешнее управление активной вкладкой",
|
|
55128
55821
|
"type": "full-code",
|
|
55129
|
-
"code": "()
|
|
55822
|
+
"code": "import { TableCanvas, type ColumnConfig } from '@daisforge/ui/components/TableCanvas';\nimport { Button } from '@daisforge/ui';\nimport { IconInfo, IconSettings } from '@daisforge/ui/icons';\nimport React, { useState } from 'react';\n\nfunction createSidebarData() {\n type Row = { id: number; task: string; priority: string };\n const priorities = ['Critical', 'High', 'Medium', 'Low'];\n const rows: Row[] = Array.from({ length: 12 }, (_, index) => ({\n id: index + 1,\n task: `Task ${index + 1}`,\n priority: priorities[index % priorities.length] ?? 'Low',\n }));\n const columnConfig: ColumnConfig<Row>[] = [\n { key: 'id', name: 'ID', width: 100 },\n { key: 'task', name: 'Title', width: 300 },\n { key: 'priority', name: 'Priority', width: 180 },\n ];\n return { rows, columnConfig };\n};\n\nfunction ControlledActiveTabExample() {\n const [{ rows, columnConfig }] = useState(createSidebarData);\n const [isOpen, setIsOpen] = useState(false);\n const [activeTab, setActiveTab] = useState<string | null>(null);\n\n const openTab = (id: string) => {\n setActiveTab(id);\n setIsOpen(true);\n };\n\n return (\n <>\n <div style={{ display: 'flex', gap: 8, marginBottom: 12 }}>\n <Button onClick={() => openTab('customInfo')}>Инфо</Button>\n <Button onClick={() => openTab('customSettings')}>Настройки</Button>\n <Button onClick={() => setIsOpen(false)}>Закрыть</Button>\n </div>\n <TableCanvas\n tableConfig={{\n containerStyle: { height: 480 },\n rightSidebarConfig: {\n openState: [isOpen, setIsOpen],\n activeTabState: [activeTab, setActiveTab],\n customTabs: [\n {\n id: 'customInfo',\n label: 'Информация',\n icon: <IconInfo size=\"s\" />,\n content: <p>Вкладка «Информация».</p>,\n title: 'Информация',\n showInSidebar: true,\n },\n {\n id: 'customSettings',\n label: 'Настройки',\n icon: <IconSettings size=\"s\" />,\n content: <p>Вкладка «Настройки».</p>,\n title: 'Настройки',\n showInSidebar: true,\n },\n ],\n },\n }}\n columnConfig={columnConfig}\n rows={rows}\n />\n </>\n );\n};"
|
|
55130
55823
|
},
|
|
55131
55824
|
{
|
|
55132
55825
|
"exportName": "ActiveTabCallback",
|
|
55133
55826
|
"displayName": "Колбэк активной вкладки",
|
|
55134
55827
|
"type": "full-code",
|
|
55135
|
-
"code": "()
|
|
55828
|
+
"code": "import { TableCanvas, type ColumnConfig } from '@daisforge/ui/components/TableCanvas';\nimport { IconInfo, IconSettings } from '@daisforge/ui/icons';\nimport React, { useState } from 'react';\n\nfunction createSidebarData() {\n type Row = { id: number; task: string; priority: string };\n const priorities = ['Critical', 'High', 'Medium', 'Low'];\n const rows: Row[] = Array.from({ length: 12 }, (_, index) => ({\n id: index + 1,\n task: `Task ${index + 1}`,\n priority: priorities[index % priorities.length] ?? 'Low',\n }));\n const columnConfig: ColumnConfig<Row>[] = [\n { key: 'id', name: 'ID', width: 100 },\n { key: 'task', name: 'Title', width: 300 },\n { key: 'priority', name: 'Priority', width: 180 },\n ];\n return { rows, columnConfig };\n};\n\nfunction ActiveTabCallbackExample() {\n const [{ rows, columnConfig }] = useState(createSidebarData);\n const [currentTab, setCurrentTab] = useState<string | null>(null);\n\n return (\n <>\n <p style={{ marginBottom: 12 }}>\n Активная вкладка: <b>{currentTab ?? 'нет (сайдбар закрыт)'}</b>\n </p>\n <TableCanvas\n tableConfig={{\n containerStyle: { height: 480 },\n rightSidebarConfig: {\n onActiveTabChange: (tabId, tab) =>\n setCurrentTab(tab?.title ?? tabId),\n customTabs: [\n {\n id: 'customInfo',\n label: 'Информация',\n icon: <IconInfo size=\"s\" />,\n content: <p>Вкладка «Информация».</p>,\n title: 'Информация',\n showInSidebar: true,\n },\n {\n id: 'customSettings',\n label: 'Настройки',\n icon: <IconSettings size=\"s\" />,\n content: <p>Вкладка «Настройки».</p>,\n title: 'Настройки',\n showInSidebar: true,\n },\n ],\n },\n }}\n columnConfig={columnConfig}\n rows={rows}\n />\n </>\n );\n};"
|
|
55829
|
+
},
|
|
55830
|
+
{
|
|
55831
|
+
"exportName": "LeftSidebar",
|
|
55832
|
+
"displayName": "Левая панель: ширина по активной вкладке",
|
|
55833
|
+
"type": "full-code",
|
|
55834
|
+
"code": "import { TableCanvas } from '@daisforge/ui/components/TableCanvas';\nimport { Button, TextFieldSearch, BodyS } from '@daisforge/ui';\nimport { IconBookOpenOutline, IconDocumentOutline } from '@daisforge/ui/icons';\nimport React, { useState } from 'react';\n\nfunction LeftSidebarExample() {\n const [width, setWidth] = useState<string | number>(300);\n const [open, setOpen] = useState(true);\n const [query, setQuery] = useState('');\n const onActiveTabChange = (id: string | null) => {\n if (id === 'reports') setWidth(300);\n if (id === 'books') setWidth('35%');\n };\n const rows = [\n { id: 1, report: 'Финансовый отчёт' },\n { id: 2, report: 'Итоги квартала' },\n ];\n\n return (\n <div style={{ padding: 16 }}>\n <div style={{ display: 'flex', gap: 8, marginBottom: 12 }}>\n <Button size=\"xs\" view=\"secondary\" onClick={() => setWidth(360)}>\n 360px\n </Button>\n <Button size=\"xs\" view=\"secondary\" onClick={() => setWidth('25%')}>\n 25%\n </Button>\n <Button\n size=\"xs\"\n view=\"secondary\"\n onClick={() => setOpen((value) => !value)}\n >\n Переключить панель\n </Button>\n </div>\n <TableCanvas\n rows={rows}\n columnConfig={[\n { key: 'id', name: 'ID', width: 100 },\n { key: 'report', name: 'Отчёт', width: 360 },\n ]}\n tableConfig={{\n containerStyle: { height: 480 },\n leftSidebarConfig: {\n width,\n openState: [open, setOpen],\n defaultActiveTabId: 'reports',\n onActiveTabChange,\n customTabs: [\n {\n id: 'reports',\n label: 'Отчёты',\n icon: <IconDocumentOutline size=\"s\" />,\n content: (\n <div style={{ padding: 16 }}>\n <TextFieldSearch\n size=\"xs\"\n aria-label=\"Поиск отчёта\"\n placeholder=\"Поиск отчёта\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onClear={() => setQuery('')}\n />\n {rows\n .filter((row) =>\n row.report.toLowerCase().includes(query.toLowerCase()),\n )\n .map((row) => (\n <BodyS key={row.id} style={{ marginTop: 16 }}>\n {row.report}\n </BodyS>\n ))}\n </div>\n ),\n },\n {\n id: 'books',\n label: 'Книги',\n icon: <IconBookOpenOutline size=\"s\" />,\n content: (\n <div style={{ padding: 16 }}>\n <BodyS>Книги отчётов</BodyS>\n <Button\n size=\"xs\"\n view=\"secondary\"\n style={{ marginTop: 16 }}\n >\n Отчётность 2026\n </Button>\n </div>\n ),\n },\n ],\n },\n }}\n />\n </div>\n );\n};"
|
|
55835
|
+
},
|
|
55836
|
+
{
|
|
55837
|
+
"exportName": "RightSidebar",
|
|
55838
|
+
"displayName": "Правая панель: контент и ширина по активной вкладке",
|
|
55839
|
+
"type": "full-code",
|
|
55840
|
+
"code": "import { TableCanvas } from '@daisforge/ui/components/TableCanvas';\nimport { Button, BodyS } from '@daisforge/ui';\nimport { IconBookOpenOutline, IconDocumentOutline } from '@daisforge/ui/icons';\nimport React, { useState } from 'react';\n\nfunction RightSidebarExample() {\n const [width, setWidth] = useState<string | number>(400);\n const onActiveTabChange = (id: string | null) => {\n if (id === 'reports') setWidth(400);\n if (id === 'books') setWidth('35%');\n };\n\n return (\n <div style={{ padding: 16 }}>\n <TableCanvas\n rows={[\n { id: 1, report: 'Финансовый отчёт' },\n { id: 2, report: 'Итоги квартала' },\n ]}\n columnConfig={[\n { key: 'id', name: 'ID', width: 100 },\n { key: 'report', name: 'Отчёт', width: 360 },\n ]}\n tableConfig={{\n containerStyle: { height: 480 },\n rightSidebarConfig: {\n width,\n defaultOpen: true,\n defaultActiveTabId: 'reports',\n onActiveTabChange,\n defaultTabs: [\n { id: 'tableSettings', showInSidebar: false },\n { id: 'columns', showInSidebar: false },\n { id: 'filtering', showInSidebar: false },\n ],\n customTabs: [\n {\n id: 'reports',\n label: 'Отчёты',\n icon: <IconDocumentOutline size=\"s\" />,\n content: (\n <div style={{ padding: 16 }}>\n <BodyS>Сведения об отчёте</BodyS>\n <BodyS style={{ marginTop: 16 }}>\n Данные по подразделениям за 2026 год.\n </BodyS>\n </div>\n ),\n },\n {\n id: 'books',\n label: 'Книги',\n icon: <IconBookOpenOutline size=\"s\" />,\n content: (\n <div style={{ padding: 16 }}>\n <BodyS>Книги отчётов</BodyS>\n <Button\n size=\"xs\"\n view=\"secondary\"\n style={{ marginTop: 16 }}\n >\n Отчётность 2026\n </Button>\n </div>\n ),\n },\n ],\n },\n }}\n />\n </div>\n );\n};"
|
|
55841
|
+
}
|
|
55842
|
+
]
|
|
55843
|
+
},
|
|
55844
|
+
{
|
|
55845
|
+
"component": "TableCanvas",
|
|
55846
|
+
"feature": "BottomSheet",
|
|
55847
|
+
"legacy": false,
|
|
55848
|
+
"summary": "Нижняя панель с произвольным React-контентом, например журналом событий. Задаётся через `tableConfig.bottomSheetConfig` и располагается под областью данных, над общей пагинацией, между левой и правой боковыми панелями.",
|
|
55849
|
+
"docs": "# BottomSheet (TableCanvas)\n\nНижняя панель с произвольным React-контентом, например журналом событий. Задаётся через `tableConfig.bottomSheetConfig` и располагается под областью данных, над общей пагинацией, между левой и правой боковыми панелями.\n\n## Ключевые особенности\n\n- `height`, `minHeight` и `maxHeight` принимают число в пикселях или CSS-строку; по умолчанию `height` и `minHeight` равны 32px.\n- `height: 'auto'` подстраивает панель под содержимое, а `maxHeight` ограничивает её высоту. При переполнении панель прокручивается.\n- Содержимое, кнопку раскрытия и высоту открытой панели задаёт потребитель.\n- Панель работает вместе с Sidebar, пагинацией, выбором строк, массовыми действиями и полноэкранным режимом.\n- Collapse скрывает рабочую область и пагинацию, сохраняя размеры и состояние панелей.\n\n## Использование\n\n```tsx\n\nfunction TableWithEventLog() {\n const [height, setHeight] = useState<string | number>(32);\n\n return (\n <TableCanvas\n rows={rows}\n columnConfig={columns}\n tableConfig={{\n containerStyle: { height: 620 },\n bottomSheetConfig: {\n height,\n minHeight: 32,\n content: (\n <EventLog onToggle={() => setHeight(height === 32 ? 220 : 32)} />\n ),\n },\n }}\n />\n );\n}\n```\n\n## Особенности\n\n### Размеры и прокрутка\n\nПроценты в `height`, `minHeight` и `maxHeight` считаются от пространства, доступного строкам таблицы и BottomSheet. Блок управления, фильтры и пагинация в него не входят. Раскрытие не увеличивает внешний контейнер. Панель оставляет для области данных не менее 120px; если всё доступное пространство меньше 120px, высота панели равна нулю. `maxHeight` дополнительно ограничивает высоту, а `minHeight` не может превышать получившийся максимум.\n\nНапример, при высоте таблицы 620px, блоке управления 40px и пагинации 56px доступно `620 − 40 − 56 = 524px`. BottomSheet высотой 220px оставляет для области данных `524 − 220 = 304px`.\n\nДля высоты по содержимому передайте `height: 'auto'`. Панель растёт и уменьшается вместе с содержимым, а при достижении `maxHeight` или границы доступного пространства прокручивается. Содержимому в этом режиме не задавайте `height: 100%`: оно должно сохранять естественную высоту.\n\nПри фиксированной высоте прокрутку настраивают внутри `content`: задайте прокручиваемому блоку `overflow: auto` и `minHeight: 0`.\n\n### Раскрытие\n\nРаскрытие задаётся изменением `height`, а кнопка раскрытия размещается в `content`. Чтобы убрать панель, передайте `enabled: false` или удалите `bottomSheetConfig`.\n\nИзменение числовой или процентной высоты анимируется за 0.5 секунды. Плавный переход между фиксированной высотой и `auto` поддерживается в современных Chrome/Edge; в других браузерах высота может переключаться сразу. Добавление и удаление содержимого в режиме `auto` меняет высоту без отдельной анимации.\n\nДля плавного закрытия сохраняйте содержимое панели при изменении высоты. Не скрывайте его через `hidden` и не удаляйте условно. Закрытую часть содержимого исключайте из чтения скринридером через `aria-hidden` и из фокуса и взаимодействия через `inert`; кнопка раскрытия должна оставаться доступной.\n\n### Совместная работа с таблицей\n\nПри collapse область данных, обе боковые панели, BottomSheet и пагинация скрываются и исключаются из фокуса. После разворачивания сохраняются активные вкладки и размеры. Поддерживаются положения кнопки `inside` и `above`, а также полноэкранный режим.\n\nBottomSheet доступен в режиме строк. Error, empty state и skeleton сохраняют панель. Активный `loadingOverlay` заменяет всю таблицу вместе с Sidebar, BottomSheet и пагинацией.\n\n## Примеры\n\n**Высота, стрелка и пагинация** — минимальный пример раскрытия 32 ↔ 220px, высоты 35%, ограничения большой высоты и прокрутки журнала.\n\n**Высота по содержимому и maxHeight** — раскрытие 32 ↔ `auto`, добавление и удаление сообщений, короткий и длинный журнал, ограничение высоты в пикселях и процентах. Переполнение прокручивается на самой панели.\n\n**Все возможности таблицы** — совместная работа BottomSheet и обеих Sidebar с поиском, фильтрами, сортировкой, редактированием, выбором строк и ячеек, copy/paste/fill, итогами, настройками колонок и представления. Действия записываются в журнал.\n\nВ примере можно переключить плоские строки, группировку и дерево `subRows`, полный набор данных, страницы по 20 строк и локальную бесконечную загрузку. При группировке доступен только полный набор данных; страницы дерева формируются по верхним узлам.\n\nРедактирование, вставка и заполнение доступны в плоском режиме, группировке со слиянием и дереве `subRows`. Группировка деревом и `subRows` со слиянием в этом примере доступны для просмотра и копирования.\n\nОписание типов — в разделе [BottomSheet API](?path=/docs/локальные-компоненты-tablecanvas-bottomsheet-api--docs).",
|
|
55850
|
+
"apiDocs": "# BottomSheet API\n\n## BottomSheetConfig\n\n```typescript\ntype BottomSheetConfig = {\n /** @default true */\n enabled?: boolean;\n /** Число — px, строка — CSS; 'auto' — по содержимому. Проценты — от рабочей области. @default 32 */\n height?: string | number;\n /** Минимальная высота, ограниченная доступным пространством. @default 32 */\n minHeight?: string | number;\n /** Максимальная высота в px или CSS, дополнительно ограниченная доступным пространством. */\n maxHeight?: string | number;\n /** Пользователь управляет содержимым и раскрытием; при height: 'auto' панель прокручивается сама. */\n content: React.ReactNode;\n};\n```",
|
|
55851
|
+
"api": [
|
|
55852
|
+
{
|
|
55853
|
+
"typeName": "BottomSheetConfig",
|
|
55854
|
+
"source": "type BottomSheetConfig = {\n /** @default true */\n enabled?: boolean;\n /** Число — px, строка — CSS; 'auto' — по содержимому. Проценты — от рабочей области. @default 32 */\n height?: string | number;\n /** Минимальная высота, ограниченная доступным пространством. @default 32 */\n minHeight?: string | number;\n /** Максимальная высота в px или CSS, дополнительно ограниченная доступным пространством. */\n maxHeight?: string | number;\n /** Пользователь управляет содержимым и раскрытием; при height: 'auto' панель прокручивается сама. */\n content: React.ReactNode;\n};"
|
|
55855
|
+
}
|
|
55856
|
+
],
|
|
55857
|
+
"stories": [
|
|
55858
|
+
{
|
|
55859
|
+
"exportName": "BottomSheet",
|
|
55860
|
+
"displayName": "Высота, стрелка и пагинация",
|
|
55861
|
+
"type": "full-code",
|
|
55862
|
+
"code": "import { Button, IconButton, BodyS } from '@daisforge/ui';\nimport { TableCanvas } from '@daisforge/ui/components/TableCanvas';\nimport { IconChevronDown, IconChevronUp } from '@daisforge/ui/icons';\nimport React, { useId, useState } from 'react';\n\nfunction BottomSheetExample() {\n const [height, setHeight] = useState<string | number>(32);\n const [page, setPage] = useState(1);\n const [perPage, setPerPage] = useState(20);\n const contentId = useId();\n const rows = Array.from({ length: 40 }, (_, id) => ({\n id,\n report: `Отчёт ${id + 1}`,\n }));\n const expanded = height !== 32;\n const messages = Array.from(\n { length: 10 },\n (_, id) => `Сообщение ${id + 1}: данные отчёта обновлены.`,\n );\n\n return (\n <div style={{ padding: 16 }}>\n <div style={{ display: 'flex', gap: 8, marginBottom: 12 }}>\n <Button size=\"xs\" view=\"secondary\" onClick={() => setHeight(220)}>\n 220px\n </Button>\n <Button size=\"xs\" view=\"secondary\" onClick={() => setHeight('35%')}>\n 35%\n </Button>\n <Button size=\"xs\" view=\"secondary\" onClick={() => setHeight(1000)}>\n Больше доступного места\n </Button>\n </div>\n <TableCanvas\n rows={rows.slice((page - 1) * perPage, page * perPage)}\n columnConfig={[\n { key: 'id', name: 'ID', width: 100 },\n { key: 'report', name: 'Отчёт', width: 360 },\n ]}\n tableConfig={{\n containerStyle: { height: 480 },\n pagination: {\n value: page,\n perPage,\n count: rows.length,\n onChangePageValue(value, scrollToTop) {\n setPage(value ?? 1);\n scrollToTop();\n },\n onChange(value, pageSize, scrollToTop) {\n setPage(\n pageSize !== undefined && pageSize !== perPage ? 1 : value ?? 1,\n );\n setPerPage(pageSize ?? perPage);\n scrollToTop();\n },\n },\n bottomSheetConfig: {\n height,\n minHeight: 32,\n content: (\n <div\n style={{\n height: '100%',\n display: 'flex',\n flexDirection: 'column',\n }}\n >\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n minHeight: 30,\n whiteSpace: 'nowrap',\n flexShrink: 0,\n }}\n >\n <IconButton\n size=\"xxs\"\n view=\"clear\"\n aria-label={expanded ? 'Закрыть лог' : 'Открыть лог'}\n aria-expanded={expanded}\n aria-controls={contentId}\n style={{ flexShrink: 0 }}\n onClick={() => setHeight(expanded ? 32 : 220)}\n >\n {expanded ? (\n <IconChevronDown size=\"xs\" />\n ) : (\n <IconChevronUp size=\"xs\" />\n )}\n </IconButton>\n <BodyS\n style={{\n minWidth: 0,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n Журнал событий\n </BodyS>\n </div>\n <div\n id={contentId}\n aria-hidden={!expanded}\n {...(!expanded ? { inert: '' } : {})}\n style={{ overflow: 'auto', minHeight: 0, padding: '0 16px' }}\n >\n {messages.map((message) => (\n <BodyS key={message} style={{ padding: '12px 0' }}>\n {message}\n </BodyS>\n ))}\n </div>\n </div>\n ),\n },\n }}\n />\n </div>\n );\n};\n\n<BottomSheetExample />;"
|
|
55863
|
+
},
|
|
55864
|
+
{
|
|
55865
|
+
"exportName": "AllFeatures",
|
|
55866
|
+
"displayName": "Все возможности таблицы",
|
|
55867
|
+
"type": "full-code",
|
|
55868
|
+
"code": "import { Button, IconButton, Switch, TextFieldSearch, BodyS, BodyXS, H5 } from '@daisforge/ui';\nimport {\n Canvas,\n type CellsSelectionMode,\n type ColumnConfig,\n type ColumnOrColumnGroupConfig,\n CompactSelection,\n type ControlBlockSize,\n type GridSelection,\n type RowsChangeData,\n type SortColumn,\n TableCanvas,\n type TableConfig,\n} from '@daisforge/ui/components/TableCanvas';\nimport {\n IconBookOpenOutline,\n IconChevronDown,\n IconChevronUp,\n IconDocumentOutline,\n IconInfoCircleOutline,\n IconRefresh,\n IconStar,\n} from '@daisforge/ui/icons';\nimport { outlineSolidPrimary, surfaceInfoMinor, textNegative, textSecondary } from '@daisforge/ui/tokens';\nimport React, { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';\n\ntype BottomSheetRow = {\n id: number | string;\n task: string;\n priority: string;\n issueType: string;\n developer: string;\n complete: number;\n subRows?: BottomSheetRow[];\n};\n\ntype BottomSheetFilters = {\n priority: string;\n issueType: string[];\n developer: string;\n complete: string;\n globalFilter: string;\n};\n\ntype BottomSheetSummary = {\n type: 'top' | 'bottom';\n values: Array<{ columnId: string; value: string }>;\n};\n\ntype BottomSheetDataMode = 'all' | 'pagination' | 'infinity';\n\ntype AllFeaturesExampleProps = {\n refTable?: React.ComponentProps<typeof TableCanvas>['refTable'];\n initialCollapsed?: boolean;\n placement?: 'inside' | 'above';\n controlBlockSize?: ControlBlockSize;\n adaptive?: boolean;\n initialError?: boolean;\n initialEmpty?: boolean;\n initialLogHeight?: string | number;\n};\n\ntype AllFeaturesSettings = {\n structure:\n | 'flat'\n | 'group-tree'\n | 'group-merged'\n | 'subrows-tree'\n | 'subrows-merged';\n dataMode: 'all' | 'pagination' | 'infinity';\n selectionMode: CellsSelectionMode;\n axisSelection: boolean;\n highlight: boolean;\n hover: boolean;\n groupedHeaders: boolean;\n squash: boolean;\n merge: 'none' | 'values' | 'region';\n renderers: boolean;\n tooltips: boolean;\n preview: boolean;\n formats: boolean;\n theme: boolean;\n borders: 'all' | 'horizontal' | 'none' | 'custom';\n variableHeight: boolean;\n headerHeight: '33' | '48';\n unstickyHeader: boolean;\n controlBlockShow: boolean;\n controlBlockSize: ControlBlockSize;\n adaptive: boolean;\n placement: 'inside' | 'above';\n searchOnType: boolean;\n autocomplete: boolean;\n transferEnabled: boolean;\n pasteReadonly: 'skip' | 'abort';\n pasteOverflow: 'truncate' | 'abort';\n pasteValidation: 'none' | 'type-check';\n pasteBroadcast: boolean;\n fillEnabled: boolean;\n fillDirections: 'horizontal' | 'vertical' | 'orthogonal' | 'any';\n allowSubRows: boolean;\n};\n\ntype AllFeaturesEvent = {\n id: number;\n message: string;\n level: 'info' | 'warning' | 'error';\n};\n\ntype AllFeaturesChoiceProps = {\n label: string;\n value: string;\n items: Array<{ value: string; label: string }>;\n onChange: (value: string) => void;\n disabled?: boolean;\n};\n\ntype AllFeaturesToggleProps = {\n label: string;\n checked: boolean;\n onChange: (checked: boolean) => void;\n};\n\ntype AllFeaturesSettingsPanelProps = {\n settings: AllFeaturesSettings;\n onChange: (patch: Partial<AllFeaturesSettings>) => void;\n};\n\ntype AllFeaturesLogProps = {\n expanded: boolean;\n events: AllFeaturesEvent[];\n onToggle: () => void;\n onClear: () => void;\n};\n\ntype AllFeaturesNavigationProps = {\n rows: BottomSheetRow[];\n onSelect: (row: BottomSheetRow) => void;\n};\n\nfunction createBottomSheetRows(count = 100): BottomSheetRow[] {\n const priorities = ['Critical', 'High', 'Medium', 'Low'];\n const issueTypes = ['Bug', 'Improvement', 'Epic', 'Story'];\n const developers = ['Анна', 'Борис', 'Виктор', 'Дарья', 'Елена'];\n\n return Array.from({ length: Math.max(0, Math.floor(count)) }, (_, index) => {\n const id = index + 1;\n const priority = priorities[index % priorities.length] ?? 'Medium';\n const issueType =\n issueTypes[Math.floor(index / 4) % issueTypes.length] ?? 'Story';\n return {\n id,\n task: `Задача ${id}: подготовить отчёт и проверить данные`,\n priority,\n issueType,\n developer: developers[index % developers.length] ?? 'Анна',\n complete: (id * 17) % 101,\n subRows: Array.from({ length: 2 }, (_child, childIndex) => ({\n id: `${id}.${childIndex + 1}`,\n task: `Подзадача ${id}.${childIndex + 1}: ${\n childIndex === 0 ? 'реализация' : 'проверка'\n }`,\n priority,\n issueType,\n developer:\n developers[(index + childIndex + 1) % developers.length] ?? 'Анна',\n complete: (id * 17 + (childIndex + 1) * 13) % 101,\n })),\n };\n });\n};\n\nfunction cloneBottomSheetRows(\n rows: readonly BottomSheetRow[],\n): BottomSheetRow[] {\n return rows.map((row) => ({\n ...row,\n ...(row.subRows ? { subRows: cloneBottomSheetRows(row.subRows) } : {}),\n }));\n};\n\nfunction prepareBottomSheetRows(\n rows: readonly BottomSheetRow[],\n query: string,\n filters: BottomSheetFilters,\n sortColumns: readonly SortColumn[],\n tree = false,\n): BottomSheetRow[] {\n const search = query.trim().toLocaleLowerCase('ru');\n const globalFilter = filters.globalFilter.trim().toLocaleLowerCase('ru');\n const developer = filters.developer.trim().toLocaleLowerCase('ru');\n const minimumComplete = Number(filters.complete) || 0;\n const fields = [\n 'id',\n 'task',\n 'priority',\n 'issueType',\n 'developer',\n 'complete',\n ] as const;\n\n function matches(row: BottomSheetRow): boolean {\n const text = fields\n .map((key) => String(row[key]))\n .join(' ')\n .toLocaleLowerCase('ru');\n return (\n (!search || text.includes(search)) &&\n (!globalFilter || text.includes(globalFilter)) &&\n (!filters.priority ||\n filters.priority === 'All' ||\n row.priority === filters.priority) &&\n (!filters.issueType.length ||\n filters.issueType.includes(row.issueType)) &&\n (!developer ||\n row.developer.toLocaleLowerCase('ru').startsWith(developer)) &&\n row.complete >= minimumComplete\n );\n }\n\n function compare(left: BottomSheetRow, right: BottomSheetRow): number {\n return sortColumns.reduce((result, sort) => {\n if (result || !fields.some((key) => key === sort.columnKey))\n return result;\n const key = sort.columnKey as (typeof fields)[number];\n const difference =\n key === 'complete'\n ? left.complete - right.complete\n : String(left[key]).localeCompare(String(right[key]), 'ru', {\n numeric: key === 'id',\n });\n return sort.direction === 'DESC' ? -difference : difference;\n }, 0);\n }\n\n function visit(siblings: readonly BottomSheetRow[]): BottomSheetRow[] {\n return siblings\n .reduce<BottomSheetRow[]>((result, row) => {\n const children = tree && row.subRows ? visit(row.subRows) : undefined;\n if (matches(row) || children?.length) {\n const { subRows: _subRows, ...values } = row;\n result.push({\n ...values,\n ...(children?.length ? { subRows: children } : {}),\n });\n }\n return result;\n }, [])\n .sort(compare);\n }\n\n return visit(rows);\n};\n\nfunction applyBottomSheetRowChanges(\n rows: readonly BottomSheetRow[],\n changedRows: readonly BottomSheetRow[],\n): BottomSheetRow[] {\n const changes = new Map<string, BottomSheetRow>();\n\n function collect(siblings: readonly BottomSheetRow[]): void {\n siblings.forEach((row) => {\n changes.set(String(row.id), row);\n if (row.subRows) collect(row.subRows);\n });\n }\n\n function visit(siblings: readonly BottomSheetRow[]): BottomSheetRow[] {\n return siblings.map((row) => {\n const change = changes.get(String(row.id));\n return {\n ...row,\n ...(change\n ? {\n task: change.task,\n priority: change.priority,\n issueType: change.issueType,\n developer: change.developer,\n complete: change.complete,\n }\n : {}),\n ...(row.subRows ? { subRows: visit(row.subRows) } : {}),\n };\n });\n }\n\n collect(changedRows);\n return visit(rows);\n};\n\nfunction summarizeBottomSheetRows(\n rows: readonly BottomSheetRow[],\n tree = false,\n): BottomSheetSummary[] {\n const allRows: BottomSheetRow[] = [];\n\n function collect(siblings: readonly BottomSheetRow[]): void {\n siblings.forEach((row) => {\n allRows.push(row);\n if (tree && row.subRows) collect(row.subRows);\n });\n }\n\n collect(rows);\n const complete = allRows.reduce((sum, row) => sum + row.complete, 0);\n const average = allRows.length ? complete / allRows.length : 0;\n const developers = new Set(allRows.map((row) => row.developer));\n return [\n {\n type: 'top',\n values: [\n { columnId: 'id', value: String(allRows.length) },\n { columnId: 'task', value: 'Всего строк в выборке' },\n {\n columnId: 'priority',\n value: `Critical: ${\n allRows.filter((row) => row.priority === 'Critical').length\n }`,\n },\n {\n columnId: 'issueType',\n value: `Bug: ${\n allRows.filter((row) => row.issueType === 'Bug').length\n }`,\n },\n { columnId: 'developer', value: `Исполнителей: ${developers.size}` },\n { columnId: 'complete', value: `Сумма: ${complete}` },\n ],\n },\n {\n type: 'bottom',\n values: [\n { columnId: 'task', value: 'Средняя готовность всей выборки' },\n { columnId: 'complete', value: `${average.toFixed(1)}%` },\n ],\n },\n ];\n};\n\nfunction selectBottomSheetRows(\n rows: readonly BottomSheetRow[],\n mode: BottomSheetDataMode,\n page = 1,\n pageSize = 20,\n loadedCount = 20,\n): BottomSheetRow[] {\n if (mode === 'all') return [...rows];\n if (mode === 'infinity')\n return rows.slice(0, Math.max(0, Math.floor(loadedCount)));\n const size = Math.max(1, Math.floor(pageSize));\n const lastPage = Math.max(1, Math.ceil(rows.length / size));\n const currentPage = Math.min(lastPage, Math.max(1, Math.floor(page)));\n return rows.slice((currentPage - 1) * size, currentPage * size);\n};\n\nfunction AllFeaturesChoice(props: AllFeaturesChoiceProps) {\n const { label, value, items, disabled, onChange } = props;\n const id = useId();\n return (\n <label\n htmlFor={id}\n style={{ display: 'flex', flexDirection: 'column', gap: 4 }}\n >\n <BodyXS>{label}</BodyXS>\n <select\n id={id}\n aria-label={label}\n value={value}\n disabled={disabled}\n onChange={(event) => onChange(event.target.value)}\n style={{\n font: 'inherit',\n padding: '7px 10px',\n borderRadius: 6,\n border: `1px solid ${outlineSolidPrimary}`,\n background: 'transparent',\n color: 'inherit',\n }}\n >\n {items.map((item) => (\n <option key={item.value} value={item.value}>\n {item.label}\n </option>\n ))}\n </select>\n </label>\n );\n};\n\nfunction AllFeaturesToggle(props: AllFeaturesToggleProps) {\n const { label, checked, onChange } = props;\n return (\n <Switch\n label={label}\n checked={checked}\n onChange={(event) => onChange(event.target.checked)}\n />\n );\n};\n\nfunction AllFeaturesSettingsPanel(props: AllFeaturesSettingsPanelProps) {\n const { settings, onChange: update } = props;\n return (\n <details style={{ marginBottom: 12 }}>\n <summary style={{ cursor: 'pointer', padding: '8px 0' }}>\n Настройки всех возможностей\n </summary>\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fit, minmax(260px, 1fr))',\n gap: 16,\n padding: '12px 0',\n }}\n >\n <fieldset\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: 12,\n borderColor: outlineSolidPrimary,\n }}\n >\n <legend>Выделение и поиск</legend>\n <AllFeaturesChoice\n label=\"Режим выделения\"\n value={settings.selectionMode}\n items={['cell', 'range-cell', 'multi-range-cell', 'disabled'].map(\n (value) => ({ value, label: value }),\n )}\n onChange={(selectionMode) =>\n update({ selectionMode: selectionMode as CellsSelectionMode })\n }\n />\n <AllFeaturesToggle\n label=\"Выделение строк и колонок диапазоном\"\n checked={settings.axisSelection}\n onChange={(axisSelection) => update({ axisSelection })}\n />\n <AllFeaturesToggle\n label=\"Подсветка активной строки\"\n checked={settings.highlight}\n onChange={(highlight) => update({ highlight })}\n />\n <AllFeaturesToggle\n label=\"Подсветка при наведении\"\n checked={settings.hover}\n onChange={(hover) => update({ hover })}\n />\n <AllFeaturesToggle\n label=\"Поиск при вводе\"\n checked={settings.searchOnType}\n onChange={(searchOnType) => update({ searchOnType })}\n />\n <AllFeaturesToggle\n label=\"Подсказки поиска\"\n checked={settings.autocomplete}\n onChange={(autocomplete) => update({ autocomplete })}\n />\n </fieldset>\n <fieldset\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: 12,\n borderColor: outlineSolidPrimary,\n }}\n >\n <legend>Колонки и ячейки</legend>\n <AllFeaturesToggle\n label=\"Групповая шапка\"\n checked={settings.groupedHeaders}\n onChange={(groupedHeaders) => update({ groupedHeaders })}\n />\n <AllFeaturesToggle\n label=\"Объединение пустых ячеек шапки\"\n checked={settings.squash}\n onChange={(squash) => update({ squash })}\n />\n <AllFeaturesChoice\n label=\"Объединение ячеек тела\"\n value={settings.merge}\n items={[\n { value: 'none', label: 'Без объединения' },\n { value: 'values', label: 'По одинаковому приоритету' },\n { value: 'region', label: 'Регион первых двух типов задач' },\n ]}\n onChange={(merge) =>\n update({ merge: merge as AllFeaturesSettings['merge'] })\n }\n />\n <AllFeaturesToggle\n label=\"Canvas-элементы в ячейках\"\n checked={settings.renderers}\n onChange={(renderers) => update({ renderers })}\n />\n <AllFeaturesToggle\n label=\"Числовое форматирование\"\n checked={settings.formats}\n onChange={(formats) => update({ formats })}\n />\n <AllFeaturesToggle\n label=\"Тултипы\"\n checked={settings.tooltips}\n onChange={(tooltips) => update({ tooltips })}\n />\n <AllFeaturesToggle\n label=\"Превью readonly-ячеек\"\n checked={settings.preview}\n onChange={(preview) => update({ preview })}\n />\n </fieldset>\n <fieldset\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: 12,\n borderColor: outlineSolidPrimary,\n }}\n >\n <legend>Буфер обмена и протяжка</legend>\n <AllFeaturesToggle\n label=\"Copy / paste / fill\"\n checked={settings.transferEnabled}\n onChange={(transferEnabled) => update({ transferEnabled })}\n />\n <AllFeaturesChoice\n label=\"Readonly-ячейки\"\n value={settings.pasteReadonly}\n items={[\n { value: 'skip', label: 'Пропустить' },\n { value: 'abort', label: 'Отменить операцию' },\n ]}\n onChange={(pasteReadonly) =>\n update({\n pasteReadonly:\n pasteReadonly as AllFeaturesSettings['pasteReadonly'],\n })\n }\n />\n <AllFeaturesChoice\n label=\"Вставка за границами\"\n value={settings.pasteOverflow}\n items={[\n { value: 'truncate', label: 'Обрезать' },\n { value: 'abort', label: 'Отменить операцию' },\n ]}\n onChange={(pasteOverflow) =>\n update({\n pasteOverflow:\n pasteOverflow as AllFeaturesSettings['pasteOverflow'],\n })\n }\n />\n <AllFeaturesChoice\n label=\"Проверка значений\"\n value={settings.pasteValidation}\n items={[\n { value: 'type-check', label: 'Проверять тип' },\n { value: 'none', label: 'Без проверки' },\n ]}\n onChange={(pasteValidation) =>\n update({\n pasteValidation:\n pasteValidation as AllFeaturesSettings['pasteValidation'],\n })\n }\n />\n <AllFeaturesToggle\n label=\"Тиражировать вставку на выделение\"\n checked={settings.pasteBroadcast}\n onChange={(pasteBroadcast) => update({ pasteBroadcast })}\n />\n <AllFeaturesToggle\n label=\"Протяжка ячеек\"\n checked={settings.fillEnabled}\n onChange={(fillEnabled) => update({ fillEnabled })}\n />\n <AllFeaturesChoice\n label=\"Направления протяжки\"\n value={settings.fillDirections}\n items={['orthogonal', 'horizontal', 'vertical', 'any'].map(\n (value) => ({ value, label: value }),\n )}\n onChange={(fillDirections) =>\n update({\n fillDirections:\n fillDirections as AllFeaturesSettings['fillDirections'],\n })\n }\n />\n <AllFeaturesToggle\n label=\"Вставка и протяжка в дочерние строки\"\n checked={settings.allowSubRows}\n onChange={(allowSubRows) => update({ allowSubRows })}\n />\n </fieldset>\n <fieldset\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: 12,\n borderColor: outlineSolidPrimary,\n }}\n >\n <legend>Размеры и оформление</legend>\n <AllFeaturesToggle\n label=\"Переменная высота строк\"\n checked={settings.variableHeight}\n onChange={(variableHeight) => update({ variableHeight })}\n />\n <AllFeaturesChoice\n label=\"Высота ряда шапки\"\n value={settings.headerHeight}\n items={[\n { value: '33', label: '33 px' },\n { value: '48', label: '48 px' },\n ]}\n onChange={(headerHeight) =>\n update({\n headerHeight:\n headerHeight as AllFeaturesSettings['headerHeight'],\n })\n }\n />\n <AllFeaturesToggle\n label=\"Открепить шапку\"\n checked={settings.unstickyHeader}\n onChange={(unstickyHeader) => update({ unstickyHeader })}\n />\n <AllFeaturesChoice\n label=\"Линии сетки\"\n value={settings.borders}\n items={[\n { value: 'all', label: 'Все линии' },\n { value: 'horizontal', label: 'Только горизонтальные' },\n { value: 'none', label: 'Без линий' },\n { value: 'custom', label: 'По строке, колонке и ячейке' },\n ]}\n onChange={(borders) =>\n update({ borders: borders as AllFeaturesSettings['borders'] })\n }\n />\n <AllFeaturesToggle\n label=\"Выделить ячейки с высоким приоритетом\"\n checked={settings.theme}\n onChange={(theme) => update({ theme })}\n />\n <AllFeaturesToggle\n label=\"Блок управления\"\n checked={settings.controlBlockShow}\n onChange={(controlBlockShow) => update({ controlBlockShow })}\n />\n <AllFeaturesChoice\n label=\"Размер блока управления\"\n value={settings.controlBlockSize}\n items={['m', 's', 'xs'].map((value) => ({ value, label: value }))}\n onChange={(controlBlockSize) =>\n update({ controlBlockSize: controlBlockSize as ControlBlockSize })\n }\n />\n <AllFeaturesToggle\n label=\"Адаптивное сжатие\"\n checked={settings.adaptive}\n onChange={(adaptive) => update({ adaptive })}\n />\n <AllFeaturesChoice\n label=\"Кнопка сворачивания\"\n value={settings.placement}\n items={[\n { value: 'inside', label: 'В блоке управления' },\n { value: 'above', label: 'Над таблицей' },\n ]}\n onChange={(placement) =>\n update({\n placement: placement as AllFeaturesSettings['placement'],\n })\n }\n />\n </fieldset>\n </div>\n </details>\n );\n};\n\nfunction AllFeaturesLog(props: AllFeaturesLogProps) {\n const { expanded, events, onToggle, onClear } = props;\n const contentId = useId();\n return (\n <div style={{ height: '100%', display: 'flex', flexDirection: 'column' }}>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n minHeight: 30,\n flexShrink: 0,\n padding: '0 8px',\n borderBottom: `1px solid ${outlineSolidPrimary}`,\n whiteSpace: 'nowrap',\n }}\n >\n <IconButton\n size=\"xxs\"\n view=\"clear\"\n aria-label={expanded ? 'Закрыть лог' : 'Открыть лог'}\n aria-expanded={expanded}\n aria-controls={contentId}\n onClick={onToggle}\n >\n {expanded ? (\n <IconChevronDown size=\"xs\" />\n ) : (\n <IconChevronUp size=\"xs\" />\n )}\n </IconButton>\n <BodyS\n style={{\n flex: 1,\n minWidth: 0,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n Журнал событий ({events.length})\n </BodyS>\n <Button size=\"xxs\" view=\"clear\" onClick={onClear}>\n Очистить журнал\n </Button>\n </div>\n <div\n id={contentId}\n aria-hidden={!expanded}\n {...(!expanded ? { inert: '' } : {})}\n style={{ overflow: 'auto', minHeight: 0 }}\n >\n {events.map((event) => (\n <div\n key={event.id}\n style={{\n display: 'flex',\n alignItems: 'flex-start',\n gap: 8,\n padding: '12px 16px',\n borderBottom: `1px solid ${outlineSolidPrimary}`,\n }}\n >\n <IconInfoCircleOutline\n size=\"s\"\n color={event.level === 'error' ? textNegative : textSecondary}\n />\n <BodyS>{event.message}</BodyS>\n </div>\n ))}\n </div>\n </div>\n );\n};\n\nfunction AllFeaturesNavigation(props: AllFeaturesNavigationProps) {\n const { rows, onSelect } = props;\n const [query, setQuery] = useState('');\n return (\n <div\n style={{ display: 'flex', flexDirection: 'column', gap: 12, padding: 16 }}\n >\n <TextFieldSearch\n size=\"xs\"\n aria-label=\"Поиск отчёта\"\n placeholder=\"Поиск отчёта\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onClear={() => setQuery('')}\n />\n <BodyXS style={{ color: textSecondary }}>Последние отчёты</BodyXS>\n {rows\n .filter((row) => row.task.toLowerCase().includes(query.toLowerCase()))\n .slice(0, 8)\n .map((row) => (\n <Button\n key={row.id}\n view=\"clear\"\n size=\"xs\"\n style={{ justifyContent: 'flex-start' }}\n onClick={() => onSelect(row)}\n >\n {row.task}\n </Button>\n ))}\n </div>\n );\n};\n\nfunction createAllFeaturesSettings(options: AllFeaturesExampleProps) {\n const settings: AllFeaturesSettings = {\n structure: 'flat',\n dataMode: 'pagination',\n selectionMode: 'range-cell',\n axisSelection: true,\n highlight: true,\n hover: true,\n groupedHeaders: false,\n squash: true,\n merge: 'none',\n renderers: true,\n tooltips: true,\n preview: true,\n formats: true,\n theme: false,\n borders: 'all',\n variableHeight: false,\n headerHeight: '33',\n unstickyHeader: false,\n controlBlockShow: true,\n controlBlockSize: options.controlBlockSize ?? 'm',\n adaptive: options.adaptive ?? true,\n placement: options.placement ?? 'inside',\n searchOnType: true,\n autocomplete: false,\n transferEnabled: true,\n pasteReadonly: 'skip',\n pasteOverflow: 'truncate',\n pasteValidation: 'type-check',\n pasteBroadcast: false,\n fillEnabled: true,\n fillDirections: 'orthogonal',\n allowSubRows: true,\n };\n return settings;\n};\n\nfunction createAllFeaturesSelection(): GridSelection {\n return { rows: CompactSelection.empty(), columns: CompactSelection.empty() };\n};\n\nfunction getBottomSheetRowId(row: BottomSheetRow) {\n return row.id;\n};\n\nfunction getBottomSheetChildren(row: BottomSheetRow) {\n return row.subRows;\n};\n\nfunction findBottomSheetRow(\n rows: BottomSheetRow[],\n id: string | number,\n): BottomSheetRow | undefined {\n if (!rows.length) return undefined;\n const direct = rows.find((row) => row.id === id);\n return (\n direct ??\n findBottomSheetRow(\n rows.flatMap((row) => row.subRows ?? []),\n id,\n )\n );\n};\n\nfunction AllFeaturesExample(options: AllFeaturesExampleProps = {}) {\n const [masterRows, setMasterRows] = useState(createBottomSheetRows);\n const savedRows = useRef(masterRows);\n const [settings, setSettings] = useState(() =>\n createAllFeaturesSettings(options),\n );\n const [filters, setFilters] = useState<BottomSheetFilters>({\n priority: 'All',\n issueType: [],\n developer: '',\n complete: '',\n globalFilter: '',\n });\n const [sortColumns, setSortColumns] = useState<readonly SortColumn[]>([]);\n const [query, setQuery] = useState('');\n const [page, setPage] = useState(1);\n const [pageSize, setPageSize] = useState(20);\n const [loadedCount, setLoadedCount] = useState(20);\n const [loadingMore, setLoadingMore] = useState(false);\n const loadTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const [groupBy, setGroupBy] = useState<string[]>(['priority', 'issueType']);\n const [expandedIds, setExpandedIds] = useState<Set<string | number>>(\n new Set(),\n );\n const [selectedRows, setSelectedRows] = useState<\n ReadonlySet<string | number>\n >(new Set([1, 2]));\n const [cellsSelection, setCellsSelection] = useState(\n createAllFeaturesSelection,\n );\n const [editMode, setEditMode] = useState(false);\n const [selectedRow, setSelectedRow] = useState<BottomSheetRow | null>(null);\n const [leftOpen, setLeftOpen] = useState(true);\n const [rightOpen, setRightOpen] = useState(false);\n const [leftTab, setLeftTab] = useState<string | null>('reports');\n const [rightTab, setRightTab] = useState<string | null>(null);\n const [leftWidth, setLeftWidth] = useState<string | number>(300);\n const [rightWidth, setRightWidth] = useState<string | number>(400);\n const [height, setHeight] = useState<string | number>(\n options.initialLogHeight ?? 32,\n );\n const [sheetEnabled, setSheetEnabled] = useState(true);\n const [showReports, setShowReports] = useState(true);\n const [collapsed, setCollapsed] = useState(options.initialCollapsed ?? false);\n const [containerHeight, setContainerHeight] = useState(620);\n const [containerWidth, setContainerWidth] = useState('100%');\n const [status, setStatus] = useState<\n 'normal' | 'skeleton' | 'overlay' | 'error' | 'empty'\n >(() => {\n if (options.initialError) return 'error';\n if (options.initialEmpty) return 'empty';\n return 'normal';\n });\n const [favorite, setFavorite] = useState(true);\n const [customStatus, setCustomStatus] = useState('active');\n const nextEventId = useRef(3);\n const [events, setEvents] = useState<AllFeaturesEvent[]>([\n { id: 0, message: 'Данные обновлены', level: 'info' },\n { id: 1, message: 'Отчёт сохранён', level: 'info' },\n {\n id: 2,\n message:\n 'Выберите строки, измените ячейки или откройте контекстное меню: события появятся здесь.',\n level: 'info',\n },\n ]);\n const log = useCallback(\n (message: string, level: AllFeaturesEvent['level'] = 'info') => {\n const event = { id: nextEventId.current, message, level };\n nextEventId.current += 1;\n setEvents((previous) => [event, ...previous].slice(0, 100));\n },\n [],\n );\n const isGrouping = settings.structure.startsWith('group-');\n const isTree = settings.structure.startsWith('subrows-');\n const canEdit =\n settings.structure !== 'group-tree' &&\n settings.structure !== 'subrows-merged';\n const effectiveDataMode = isGrouping ? 'all' : settings.dataMode;\n const filteredRows = useMemo(\n () =>\n prepareBottomSheetRows(masterRows, query, filters, sortColumns, isTree),\n [masterRows, query, filters, sortColumns, isTree],\n );\n const effectivePage = Math.max(\n 1,\n Math.min(page, Math.ceil(filteredRows.length / pageSize) || 1),\n );\n const visibleRows = useMemo(\n () =>\n selectBottomSheetRows(\n filteredRows,\n effectiveDataMode,\n effectivePage,\n pageSize,\n loadedCount,\n ),\n [filteredRows, effectiveDataMode, effectivePage, pageSize, loadedCount],\n );\n const summaryRows = useMemo(\n () => summarizeBottomSheetRows(filteredRows, isTree),\n [filteredRows, isTree],\n );\n const rowsForTable = status === 'empty' ? [] : visibleRows;\n const selectedDetails = selectedRow\n ? findBottomSheetRow(masterRows, selectedRow.id) ?? selectedRow\n : null;\n const loadMore = useCallback(() => {\n if (\n loadTimer.current ||\n effectiveDataMode !== 'infinity' ||\n loadedCount >= filteredRows.length\n )\n return;\n setLoadingMore(true);\n log('Начата подгрузка следующей порции');\n loadTimer.current = setTimeout(() => {\n setLoadedCount((value) => value + 20);\n setLoadingMore(false);\n loadTimer.current = null;\n log('Подгружено ещё 20 верхних строк');\n }, 500);\n }, [effectiveDataMode, loadedCount, filteredRows.length, log]);\n const onLeftTabChange = useCallback(\n (id: string | null) => log(`Левая панель: ${id ?? 'закрыта'}`),\n [log],\n );\n const onRightTabChange = useCallback(\n (id: string | null) => log(`Правая панель: ${id ?? 'закрыта'}`),\n [log],\n );\n const onHighlightedRowChange = useCallback(\n (info: { row: BottomSheetRow | undefined; index: number | undefined }) => {\n setSelectedRow(info.row ?? null);\n if (info.row) log(`Активная строка: ${info.row.task ?? 'группа'}`);\n },\n [log],\n );\n const updateSettings = useCallback(\n (patch: Partial<AllFeaturesSettings>) => {\n setSettings((previous) => ({ ...previous, ...patch }));\n if (patch.structure || patch.dataMode) {\n setPage(1);\n setLoadedCount(20);\n setExpandedIds(new Set());\n setCellsSelection(createAllFeaturesSelection());\n if (loadTimer.current) clearTimeout(loadTimer.current);\n loadTimer.current = null;\n setLoadingMore(false);\n }\n log(`Настройки изменены: ${Object.keys(patch).join(', ')}`);\n },\n [log],\n );\n useEffect(() => {\n setPage(1);\n setLoadedCount(20);\n if (loadTimer.current) clearTimeout(loadTimer.current);\n loadTimer.current = null;\n setLoadingMore(false);\n }, [query, filters, sortColumns]);\n useEffect(\n () => () => {\n if (loadTimer.current) clearTimeout(loadTimer.current);\n },\n [],\n );\n useEffect(() => {\n if (page !== effectivePage) setPage(effectivePage);\n }, [page, effectivePage]);\n const previousControls = useRef({\n filters,\n sortColumns,\n selectedRows,\n cellsSelection,\n collapsed,\n });\n useEffect(() => {\n const previous = previousControls.current;\n if (previous.collapsed !== collapsed)\n log(`Таблица ${collapsed ? 'свёрнута' : 'развёрнута'}`);\n if (previous.filters !== filters)\n log(`Фильтры: ${JSON.stringify(filters)}`);\n if (previous.sortColumns !== sortColumns)\n log(\n `Сортировка: ${\n sortColumns\n .map((column) => `${column.columnKey} ${column.direction}`)\n .join(', ') || 'сброшена'\n }`,\n );\n if (previous.selectedRows !== selectedRows)\n log(`Выбрано задач: ${selectedRows.size}`);\n if (previous.cellsSelection !== cellsSelection)\n log(\n cellsSelection.current\n ? `Выделение ячеек: ${cellsSelection.current.range.width} × ${cellsSelection.current.range.height}`\n : 'Выделение ячеек сброшено',\n );\n previousControls.current = {\n filters,\n sortColumns,\n selectedRows,\n cellsSelection,\n collapsed,\n };\n }, [filters, sortColumns, selectedRows, cellsSelection, collapsed, log]);\n\n const onRowsChange = useCallback(\n (\n _rows: BottomSheetRow[],\n data: RowsChangeData<BottomSheetRow, BottomSheetSummary>,\n ) => {\n setMasterRows((previous) =>\n applyBottomSheetRowChanges(\n previous,\n data.rows.map((change) => change.after),\n ),\n );\n log(\n `${data.type}: изменено строк ${data.rows.length}, колонка ${data.column.key}`,\n );\n },\n [log],\n );\n const markSelectedComplete = useCallback(() => {\n const changes: BottomSheetRow[] = [];\n function collect(rows: BottomSheetRow[]) {\n rows.forEach((row) => {\n if (selectedRows.has(row.id)) changes.push({ ...row, complete: 100 });\n if (row.subRows) collect(row.subRows);\n });\n }\n collect(masterRows);\n setMasterRows((previous) => applyBottomSheetRowChanges(previous, changes));\n log(`Обработать: завершено задач ${changes.length}`);\n }, [masterRows, selectedRows, log]);\n\n const columns = useMemo<\n readonly ColumnOrColumnGroupConfig<BottomSheetRow, BottomSheetSummary>[]\n >(() => {\n const renderSummary: NonNullable<\n ColumnConfig<BottomSheetRow, BottomSheetSummary>['renderSummaryCell']\n > = (props) =>\n props.row.values.find((value) => value.columnId === props.column.key)\n ?.value ?? '';\n const leafColumns: ColumnConfig<BottomSheetRow, BottomSheetSummary>[] = [\n {\n key: 'id',\n name: 'ID (readonly)',\n width: 100,\n sortingType: 'numberSort',\n renderSummaryCell: renderSummary,\n renderCellPreview: settings.preview ? 'cellEditorAsPreview' : 'none',\n keyText: {\n key: 'idKey',\n name: 'Ключ ID',\n renderCell: (props) => `KEY-${props.row.id}`,\n },\n rowsGrouping: { groupByColumn: false },\n },\n {\n key: 'task',\n name: 'Задача',\n width: 280,\n sortingType: 'stringSort',\n editingCell: { component: 'inputString' },\n renderSummaryCell: renderSummary,\n headerCellTooltip: settings.tooltips\n ? 'Название задачи; двойной клик открывает редактор.'\n : undefined,\n cellTooltip: settings.tooltips\n ? (props) => `${props.row.task}\\nID: ${props.row.id}`\n : undefined,\n rowsGrouping: { groupByColumn: false },\n subRow: {\n keyOfColumnInSubRow: 'task',\n isColumnWithArrow: settings.structure === 'subrows-tree',\n editingCell: { component: 'inputString' },\n },\n },\n {\n key: 'priority',\n name: 'Приоритет',\n width: 160,\n sortingType: 'stringSort',\n editingCell: {\n component: 'select',\n options: {\n type: 'constant',\n options: ['Critical', 'High', 'Medium', 'Low'].map((value) => ({\n value,\n text: value,\n })),\n },\n },\n renderSummaryCell: renderSummary,\n filtering: {\n component: 'select',\n keyInFilterState: 'priority',\n selectOptions: {\n type: 'constant',\n options: ['All', 'Critical', 'High', 'Medium', 'Low'].map(\n (value) => ({ value, text: value }),\n ),\n },\n valueInRow: (row) => row.priority,\n filter: {\n typeOfValue: 'single',\n filteringType: (value, rowValue) =>\n value === 'All' || value === rowValue,\n },\n },\n rowsGrouping: { columnGroupLabel: 'Приоритет' },\n renderCell: settings.renderers\n ? (props) => (\n <Canvas.Container\n padding={{\n left: props.theme.cellHorizontalPadding,\n right: props.theme.cellHorizontalPadding,\n }}\n >\n <Canvas.Badge text={props.row.priority ?? ''} size=\"s\" />\n </Canvas.Container>\n )\n : undefined,\n copyData: (row) => row.priority,\n renderCellPreview: settings.preview ? 'cellEditorAsPreview' : 'none',\n themeOverride: settings.theme\n ? (props) =>\n props.row.priority === 'Critical'\n ? { bgCell: surfaceInfoMinor }\n : undefined\n : undefined,\n subRow: {\n keyOfColumnInSubRow: 'priority',\n parentKeyAsDefault: true,\n editingCell: { component: 'inputString' },\n },\n },\n {\n key: 'issueType',\n name: 'Тип задачи',\n width: 180,\n sortingType: 'stringSort',\n editingCell: {\n component: 'select',\n options: {\n type: 'constant',\n options: ['Bug', 'Improvement', 'Epic', 'Story'].map((value) => ({\n value,\n text: value,\n })),\n },\n },\n renderSummaryCell: renderSummary,\n filtering: {\n component: 'select',\n keyInFilterState: 'issueType',\n selectOptions: {\n type: 'stateInHeaderContext',\n optionsKeyInHeaderContext: 'issueTypeOptions',\n },\n valueInRow: (row) => row.issueType,\n filter: {\n typeOfValue: 'multiple',\n filteringType: (values, rowValue) =>\n !values.length || values.includes(rowValue),\n },\n },\n rowsGrouping: { columnGroupLabel: 'Тип задачи' },\n subRow: {\n keyOfColumnInSubRow: 'issueType',\n parentKeyAsDefault: true,\n editingCell: { component: 'inputString' },\n },\n },\n {\n key: 'developer',\n name: 'Исполнитель',\n width: 220,\n sortingType: 'stringSort',\n editingCell: { component: 'inputString' },\n renderSummaryCell: renderSummary,\n filtering: {\n component: 'input',\n keyInFilterState: 'developer',\n valueInRow: (row) => row.developer,\n filter: 'startWith',\n },\n rowsGrouping: { groupByColumn: false },\n cellTooltip: settings.tooltips\n ? (props) => `Исполнитель: ${props.row.developer}`\n : undefined,\n subRow: {\n keyOfColumnInSubRow: 'developer',\n editingCell: { component: 'inputString' },\n },\n },\n {\n key: 'complete',\n name: 'Выполнено, %',\n width: 160,\n sortingType: 'numberSort',\n editingCell: { component: 'inputNumber' },\n renderSummaryCell: renderSummary,\n filtering: {\n component: 'input',\n keyInFilterState: 'complete',\n valueInRow: (row) => row.complete,\n filter: (value, rowValue) => Number(rowValue) >= Number(value || 0),\n },\n rowsGrouping: { groupByColumn: false },\n contentFormat: settings.formats\n ? {\n type: 'number',\n decimalSeparator: ',',\n thousandSeparator: ' ',\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n alignContent: 'right',\n }\n : undefined,\n subRow: {\n keyOfColumnInSubRow: 'complete',\n contentFormat: settings.formats ? 'number' : undefined,\n editingCell: { component: 'inputNumber' },\n },\n },\n ];\n const [idColumn] = leafColumns;\n if (!settings.groupedHeaders || !idColumn) return leafColumns;\n return [\n idColumn,\n {\n key: 'taskDetails',\n name: 'Задача и классификация',\n children: leafColumns.slice(1, 4),\n },\n {\n key: 'taskProgress',\n name: 'Исполнение',\n children: leafColumns.slice(4),\n },\n ];\n }, [settings]);\n\n let mergeCells: TableConfig<\n BottomSheetRow,\n BottomSheetSummary,\n string | number,\n BottomSheetFilters\n >['mergeCells'];\n if (settings.merge === 'values')\n mergeCells = { mergeByCellValues: ['priority'] };\n if (settings.merge === 'region') {\n const [first, second] = masterRows;\n mergeCells = {\n rowKeyGetter: getBottomSheetRowId,\n mergedCellsRegions:\n first && second\n ? [{ rowKeys: [first.id, second.id], colKeys: ['issueType'] }]\n : [],\n };\n }\n\n const tableConfig: TableConfig<\n BottomSheetRow,\n BottomSheetSummary,\n string | number,\n BottomSheetFilters\n > = {\n containerStyle: { height: containerHeight },\n fullScreenEnabled: {\n domMetadata: {\n dataAttributes: { 'data-testid': 'bottom-sheet-fullscreen' },\n },\n },\n resizableColumn: true,\n columnsGrouping: { squashEmptyCells: settings.squash },\n columnsControl: {\n enable: true,\n hiding: true,\n pinning: true,\n reorderingAside: true,\n reorderingHeader: true,\n disableHiding: ['id'],\n pinnedDefault: ['id'],\n hiddenColumnsIndicator: true,\n onReorderingHeader: (info) =>\n log(`Порядок колонок: ${info.newOrder.join(', ')}`),\n onHiddenColumnsIndicatorExpand: (info) =>\n log(`Показаны колонки: ${info.keys.join(', ')}`),\n onConfirm: (info) =>\n log(\n `Настройки колонок: закреплено ${info.pinned.length}, скрыто ${info.hidden.length}`,\n ),\n pinDomMetadata: {\n onClick: (_event, info) =>\n log(`Колонки: ${info?.action ?? 'закрепление'}`),\n },\n switchDomMetadata: {\n onClick: (_event, info) =>\n log(`Колонки: ${info?.action ?? 'видимость'}`),\n },\n },\n rowSize: {\n default: 'big',\n showInControl: true,\n onRowSizeChange: (size) => log(`Размер строк: ${size}`),\n },\n rowHeight: settings.variableHeight\n ? (row, size) => size.rowSizeValue + (Number(row.id) % 3 === 0 ? 24 : 0)\n : undefined,\n headerRowHeight: Number(settings.headerHeight),\n unstickyHeader: settings.unstickyHeader,\n rowMarkers: {\n startIndex:\n effectiveDataMode === 'pagination'\n ? (effectivePage - 1) * pageSize + 1\n : 1,\n },\n hoverEffects: settings.hover ? { row: true } : undefined,\n highlightActiveType: settings.highlight ? 'row' : 'disabled',\n highlightActiveRow: { onChange: onHighlightedRowChange },\n cellsSelection: {\n mode: settings.selectionMode,\n state: [cellsSelection, setCellsSelection],\n enableColumnSelection: settings.axisSelection,\n enableRowSelection: settings.axisSelection,\n enableSelectAll: settings.axisSelection,\n },\n selecting: {\n state: [selectedRows, setSelectedRows],\n rowKeyGetter: getBottomSheetRowId,\n showDefault: true,\n },\n editing: {\n onRowsChange,\n rowKeyGetter: getBottomSheetRowId,\n subRowsKey: 'subRows',\n deepCloneRows: true,\n enabled: canEdit ? [editMode, setEditMode] : false,\n showButtons: canEdit,\n onEnableEditing: (enable) => {\n savedRows.current = cloneBottomSheetRows(masterRows);\n log('Редактирование включено');\n enable();\n },\n onSave: (disable) => {\n savedRows.current = cloneBottomSheetRows(masterRows);\n log('Изменения сохранены');\n disable();\n },\n onCancel: (disable) => {\n setMasterRows(cloneBottomSheetRows(savedRows.current));\n log('Изменения отменены');\n disable();\n },\n editModeLeftSlot: (\n <BodyXS style={{ color: textSecondary }}>\n Copy / paste / fill доступны в режиме редактирования\n </BodyXS>\n ),\n },\n cellTransfer: {\n enabled: settings.transferEnabled ? undefined : false,\n paste: {\n readonlyBehavior: settings.pasteReadonly,\n overflowBehavior: settings.pasteOverflow,\n validation: settings.pasteValidation,\n broadcast: settings.pasteBroadcast,\n allowSubRows: settings.allowSubRows,\n },\n fillHandle: {\n enabled: canEdit && editMode && settings.fillEnabled,\n allowedDirections: settings.fillDirections,\n readonlyBehavior: settings.pasteReadonly,\n allowSubRows: settings.allowSubRows,\n },\n onBeforeCopy: (data) => {\n log(`Копирование: ${data.length} строк`);\n return data;\n },\n onBeforePaste: (data) => {\n if (!canEdit || !editMode) return false;\n log(`Вставка: ${data.length} строк`);\n return data;\n },\n onBeforeFill: (data) => {\n if (!canEdit || !editMode) return false;\n log(`Протяжка: ${data.length} строк`);\n return data;\n },\n },\n notifications: {\n onNotification: (event) =>\n log(`${event.type} / ${event.code}: ${event.message}`, event.level),\n },\n searching: {\n enabled: true,\n manualSearching: true,\n searchQueryState: [query, setQuery],\n debounceDelay: 300,\n searchOnType: settings.searchOnType,\n onDebouncedChange: (value) => log(`Поиск: ${value || 'все задачи'}`),\n ...(settings.autocomplete\n ? {\n autocomplete: {\n suggestions: masterRows\n .slice(0, 10)\n .map((row) => ({ label: row.task })),\n onSuggestionSelect: (value) => {\n setQuery(value.label);\n log(`Подсказка поиска: ${value.label}`);\n },\n },\n }\n : {}),\n },\n sorting: { state: [sortColumns, setSortColumns], manualSorting: true },\n filtering: {\n state: [filters, setFilters],\n manualFiltering: true,\n filtersInfo: {\n priority: { label: 'Приоритет', clearedValue: 'All' },\n issueType: { label: 'Тип задачи', clearedValue: [] },\n developer: { label: 'Исполнитель', clearedValue: '' },\n complete: { label: 'Выполнено, %', clearedValue: '' },\n globalFilter: { label: 'Общий фильтр', clearedValue: '' },\n },\n },\n summaryRows: {\n showDefault: true,\n showInControl: true,\n onChange: (enabled) =>\n log(`Итоговые строки: ${enabled ? 'показаны' : 'скрыты'}`),\n },\n keyText: { showInControl: true, controlBlock: {}, sidebar: {} },\n ...(isGrouping\n ? {\n rowsGrouping: {\n groupByState: [groupBy, setGroupBy],\n rowKeyGetter: getBottomSheetRowId,\n view: settings.structure === 'group-merged' ? 'merged' : 'tree',\n groupedColumnProps: { name: 'Группировка', width: 240 },\n },\n }\n : {}),\n ...(isTree\n ? {\n subRows: {\n getSubRows: getBottomSheetChildren,\n rowKeyGetter: getBottomSheetRowId,\n expandedIdsState: [expandedIds, setExpandedIds],\n view: settings.structure === 'subrows-merged' ? 'merged' : 'tree',\n ...(settings.structure === 'subrows-merged'\n ? { mergedColumns: ['task'] }\n : {}),\n },\n }\n : {}),\n mergeCells,\n tooltip: { enabled: settings.tooltips },\n borders: {\n vertical: settings.borders === 'all' || settings.borders === 'custom',\n horizontal: settings.borders !== 'none',\n ...(settings.borders === 'custom'\n ? {\n getVerticalBorder: (info) =>\n info.columnKey === 'developer' ? false : undefined,\n getHorizontalBorder: (info) =>\n Number(info.row.id) % 2 === 0 ? false : undefined,\n getCellBorder: (info) =>\n info.columnKey === 'complete' && info.row.complete === 100\n ? { bottom: true, top: true, left: true, right: true }\n : undefined,\n }\n : {}),\n },\n isLoading:\n status === 'skeleton' ? { boolean: true, skeletonRowsCount: 5 } : false,\n loadingOverlay: {\n active: status === 'overlay',\n title: 'Загрузка отчётов',\n subtitle: 'Подготавливаем структуру таблицы',\n showSubtitleDelay: 1000,\n },\n errorState: {\n enabled: status === 'error',\n size: 's',\n statusCode: 503,\n customStatuses: {\n 503: {\n title: 'Не удалось загрузить отчёты',\n description: 'Проверьте подключение и повторите попытку.',\n button: { label: 'Повторить', view: 'accent' },\n },\n },\n buttonHandler: () => {\n setStatus('normal');\n log('Повторная загрузка завершена');\n },\n },\n emptyState: {\n enabled: true,\n size: 's',\n variant: 'no-content',\n title: 'Отчётов пока нет',\n subtitle: 'Измените поиск или создайте первый отчёт.',\n buttons: [\n {\n type: 'button',\n props: {\n children: 'Создать отчёт',\n view: 'accent',\n onClick: () => {\n setStatus('normal');\n setQuery('');\n setFilters({\n priority: 'All',\n issueType: [],\n developer: '',\n complete: '',\n globalFilter: '',\n });\n log('Данные восстановлены');\n },\n },\n },\n ],\n },\n collapsing: {\n enableCollapse: true,\n collapsedState: [collapsed, setCollapsed],\n collapseButtonPlacement: settings.placement,\n titleText: 'Отчёты',\n collapseButtonAboveRightSlot: (\n <BodyXS>Все возможности с BottomSheet</BodyXS>\n ),\n },\n leftSidebarConfig: {\n width: leftWidth,\n openState: [leftOpen, setLeftOpen],\n activeTabState: [leftTab, setLeftTab],\n onActiveTabChange: onLeftTabChange,\n customTabs: [\n ...(showReports\n ? [\n {\n id: 'reports',\n label: 'Навигация по отчётам',\n icon: <IconDocumentOutline size=\"s\" />,\n content: (\n <AllFeaturesNavigation\n rows={masterRows}\n onSelect={(row) => {\n setSelectedRow(row);\n setRightOpen(true);\n setRightTab('details');\n log(`Открыты сведения: ${row.task}`);\n }}\n />\n ),\n },\n ]\n : []),\n {\n id: 'books',\n label: 'Книги',\n icon: <IconBookOpenOutline size=\"s\" />,\n content: (\n <div style={{ padding: 16 }}>\n <H5>Книги отчётов</H5>\n <Button\n size=\"xs\"\n view=\"secondary\"\n style={{ marginTop: 16 }}\n onClick={() => log('Открыта книга Отчётность 2026')}\n >\n Отчётность 2026\n </Button>\n </div>\n ),\n },\n ],\n },\n rightSidebarConfig: {\n width: rightWidth,\n openState: [rightOpen, setRightOpen],\n activeTabState: [rightTab, setRightTab],\n onActiveTabChange: onRightTabChange,\n defaultTabs: [\n {\n id: 'tableSettings',\n customGeneralSettingsSlot: (\n <BodyXS style={{ color: textSecondary }}>\n Выбрано задач: {selectedRows.size}. Все действия записываются в\n журнал.\n </BodyXS>\n ),\n },\n ],\n customTabs: [\n {\n id: 'details',\n label: 'Сведения',\n icon: <IconDocumentOutline size=\"s\" />,\n titleRightSlot: <BodyXS>{selectedRows.size} выбрано</BodyXS>,\n content: (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: 12,\n padding: 16,\n }}\n >\n <H5>{selectedDetails?.task ?? 'Финансовый отчёт'}</H5>\n <BodyS>\n {selectedDetails\n ? `Исполнитель: ${selectedDetails.developer}`\n : 'Выберите задачу в таблице или навигации.'}\n </BodyS>\n <BodyXS style={{ color: textSecondary }}>\n Строк в выборке: {filteredRows.length}. Выбрано:{' '}\n {selectedRows.size}.\n </BodyXS>\n <Button\n size=\"xs\"\n view=\"secondary\"\n onClick={() =>\n setRightWidth((value) => (value === 400 ? '35%' : 400))\n }\n >\n Изменить ширину правой панели\n </Button>\n </div>\n ),\n },\n ],\n },\n bottomSheetConfig: {\n enabled: sheetEnabled,\n height,\n minHeight: 32,\n content: (\n <AllFeaturesLog\n expanded={height !== 32}\n events={events}\n onToggle={() => setHeight((value) => (value === 32 ? 220 : 32))}\n onClear={() => setEvents([])}\n />\n ),\n },\n controlBlock: {\n show: settings.controlBlockShow,\n size: settings.controlBlockSize,\n enableAdaptiveCompress: settings.adaptive,\n rightSideInner: [\n {\n text: 'Обновить',\n contentLeft: <IconRefresh />,\n onClick: () => log('Данные обновлены вручную'),\n },\n ],\n customFeatures: [\n {\n value: 'favorite',\n label: 'В избранном',\n Icon: IconStar,\n onClick: () => {\n setFavorite((value) => !value);\n log('Избранное переключено');\n },\n details: {\n type: 'switch',\n label: 'В избранном',\n checked: favorite,\n onChange: (event) => {\n setFavorite(event.target.checked);\n log('Избранное переключено');\n },\n },\n },\n {\n value: 'refreshLog',\n label: 'Записать событие',\n Icon: IconRefresh,\n onClick: () => log('Данные обновлены через пользовательскую фичу'),\n details: {\n type: 'button',\n label: 'Записать событие',\n icon: <IconRefresh />,\n onClick: () => log('Данные обновлены через настройки'),\n },\n },\n {\n value: 'reportStatus',\n label: 'Статус',\n Icon: IconInfoCircleOutline,\n onClick: () => {\n setCustomStatus((value) =>\n value === 'active' ? 'inactive' : 'active',\n );\n log('Статус переключён');\n },\n details: {\n type: 'select',\n label: 'Статус отчёта',\n icon: <IconInfoCircleOutline />,\n value: customStatus,\n options: [\n { value: 'active', label: 'Активный' },\n { value: 'inactive', label: 'Неактивный' },\n ],\n onChange: (value) => {\n setCustomStatus(value);\n log(`Статус отчёта: ${value}`);\n },\n },\n },\n ],\n massActionPanel: {\n buttons: [\n {\n type: 'button',\n children: 'Обработать',\n onClick: markSelectedComplete,\n },\n {\n type: 'button',\n children: 'Снять выбор',\n view: 'secondary',\n onClick: () => {\n setSelectedRows(new Set());\n log('Выбор строк снят');\n },\n },\n ],\n },\n },\n onHeaderContextMenuDropdown: {\n type: 'dropdown',\n getDropdownItems: (info) => [\n { value: 'info', label: `Колонка: ${info.column.name}` },\n {\n value: 'sort',\n label: 'Сортировка',\n items: [\n { value: 'asc', label: 'По возрастанию' },\n { value: 'desc', label: 'По убыванию' },\n ],\n },\n ],\n onItemSelect: (item, info) => {\n if (item.value === 'asc' || item.value === 'desc')\n setSortColumns([\n {\n columnKey: info.column.key,\n direction: item.value === 'asc' ? 'ASC' : 'DESC',\n },\n ]);\n log(`Меню заголовка: ${item.label}`);\n },\n },\n onCellContextMenuDropdown: {\n type: 'dropdown',\n getDropdownItems: () => [\n { value: 'details', label: 'Открыть сведения' },\n {\n value: 'complete',\n label: 'Отметить выполненной',\n disabled: !canEdit,\n },\n ],\n onItemSelect: (item, info) => {\n if (item.value === 'details') {\n setSelectedRow(info.row);\n setRightOpen(true);\n setRightTab('details');\n } else if (canEdit) {\n const original = findBottomSheetRow(masterRows, info.row.id);\n if (original)\n setMasterRows((previous) =>\n applyBottomSheetRowChanges(previous, [\n { ...original, complete: 100 },\n ]),\n );\n }\n log(`Меню ячейки: ${item.label} (${info.row.task})`);\n },\n },\n onCellClicked: (_cell, info) => {\n if ('row' in info) setSelectedRow(info.row);\n },\n ...(effectiveDataMode === 'pagination'\n ? {\n pagination: {\n value: effectivePage,\n count: filteredRows.length,\n perPage: pageSize,\n perPageList: isTree ? [5, 10, 20] : [20, 50, 100],\n responsiveSlots: true,\n onChange: (nextPage, nextPageSize, scrollToTop) => {\n if (\n typeof nextPageSize === 'number' &&\n nextPageSize !== pageSize\n ) {\n setPageSize(nextPageSize);\n setPage(1);\n } else if (typeof nextPage === 'number') setPage(nextPage);\n scrollToTop?.();\n log(\n `Пагинация: страница ${nextPage ?? page}, по ${\n nextPageSize ?? pageSize\n }`,\n );\n },\n },\n }\n : {}),\n ...(effectiveDataMode === 'infinity'\n ? {\n infinityScroll: {\n isLoading: loadingMore,\n hasMore: loadedCount < filteredRows.length,\n rowThreshold: 5,\n onTrigger: loadMore,\n },\n }\n : {}),\n };\n\n return (\n <div\n style={{ padding: 16 }}\n data-testid=\"bottom-sheet-all-features\"\n data-total-rows={masterRows.length}\n data-filtered-rows={filteredRows.length}\n data-visible-rows={visibleRows.length}\n data-structure={settings.structure}\n data-data-mode={effectiveDataMode}\n >\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))',\n gap: 12,\n marginBottom: 12,\n }}\n >\n <AllFeaturesChoice\n label=\"Структура данных\"\n value={settings.structure}\n items={[\n { value: 'flat', label: 'Плоские строки' },\n { value: 'group-tree', label: 'Группировка деревом' },\n { value: 'group-merged', label: 'Группировка объединением' },\n { value: 'subrows-tree', label: 'Дерево дочерних строк' },\n { value: 'subrows-merged', label: 'Дерево объединением' },\n ]}\n onChange={(structure) =>\n updateSettings({\n structure: structure as AllFeaturesSettings['structure'],\n })\n }\n />\n <AllFeaturesChoice\n label=\"Получение данных\"\n value={effectiveDataMode}\n disabled={isGrouping}\n items={[\n { value: 'all', label: 'Все данные' },\n { value: 'pagination', label: 'Пагинация' },\n { value: 'infinity', label: 'Бесконечный скролл' },\n ]}\n onChange={(dataMode) =>\n updateSettings({\n dataMode: dataMode as AllFeaturesSettings['dataMode'],\n })\n }\n />\n <AllFeaturesChoice\n label=\"Состояние таблицы\"\n value={status}\n items={[\n { value: 'normal', label: 'Обычное' },\n { value: 'skeleton', label: 'Скелетоны' },\n { value: 'overlay', label: 'Загрузка структуры' },\n { value: 'error', label: 'Ошибка' },\n { value: 'empty', label: 'Нет данных' },\n ]}\n onChange={(value) => {\n setStatus(value as typeof status);\n log(`Состояние таблицы: ${value}`);\n }}\n />\n </div>\n <AllFeaturesSettingsPanel settings={settings} onChange={updateSettings} />\n <div\n style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 12 }}\n >\n <Button size=\"xs\" view=\"secondary\" onClick={() => setLeftWidth(360)}>\n Ширина 360\n </Button>\n <Button size=\"xs\" view=\"secondary\" onClick={() => setLeftWidth('25%')}>\n Ширина 25%\n </Button>\n <Button\n size=\"xs\"\n view=\"secondary\"\n onClick={() => setLeftWidth('calc(20% + 40px)')}\n >\n Ширина calc\n </Button>\n <Button size=\"xs\" view=\"secondary\" onClick={() => setHeight('35%')}>\n Лог 35%\n </Button>\n <Button size=\"xs\" view=\"secondary\" onClick={() => setHeight(1000)}>\n Большой лог\n </Button>\n <Button\n size=\"xs\"\n view=\"secondary\"\n onClick={() => setCollapsed((value) => !value)}\n >\n Collapse\n </Button>\n <Button\n size=\"xs\"\n view=\"secondary\"\n onClick={() =>\n setStatus((value) => (value === 'error' ? 'normal' : 'error'))\n }\n >\n Error state\n </Button>\n <Button\n size=\"xs\"\n view=\"secondary\"\n onClick={() =>\n setStatus((value) => (value === 'empty' ? 'normal' : 'empty'))\n }\n >\n Empty state\n </Button>\n <Button\n size=\"xs\"\n view=\"secondary\"\n onClick={() => setSheetEnabled((value) => !value)}\n >\n Нижний слот\n </Button>\n <Button\n size=\"xs\"\n view=\"secondary\"\n onClick={() => setShowReports((value) => !value)}\n >\n Удалить вкладку\n </Button>\n <Button\n size=\"xs\"\n view=\"secondary\"\n onClick={() => setLeftOpen((value) => !value)}\n >\n Открытие извне\n </Button>\n <Button\n size=\"xs\"\n view=\"secondary\"\n onClick={() =>\n setContainerHeight((value) => (value === 620 ? 350 : 620))\n }\n >\n Высота контейнера\n </Button>\n <Button\n size=\"xs\"\n view=\"secondary\"\n onClick={() =>\n setContainerWidth((value) => (value === '100%' ? '80%' : '100%'))\n }\n >\n Ширина контейнера\n </Button>\n <Button\n size=\"xs\"\n view=\"secondary\"\n onClick={() => setRightOpen((value) => !value)}\n >\n Правая панель\n </Button>\n </div>\n {effectiveDataMode === 'infinity' && (\n <Button\n size=\"xs\"\n view=\"secondary\"\n style={{ marginBottom: 12 }}\n disabled={loadingMore || loadedCount >= filteredRows.length}\n onClick={loadMore}\n >\n Загрузить ещё 20 строк\n </Button>\n )}\n <div style={{ width: containerWidth }}>\n <TableCanvas\n refTable={options.refTable}\n rows={rowsForTable}\n columnConfig={columns}\n tableConfig={tableConfig}\n bottomSummaryRows={summaryRows}\n headerContextValue={{\n issueTypeOptions: ['Bug', 'Improvement', 'Epic', 'Story'].map(\n (value) => ({ value, text: value }),\n ),\n }}\n />\n </div>\n </div>\n );\n};\n\n<AllFeaturesExample />;"
|
|
55869
|
+
},
|
|
55870
|
+
{
|
|
55871
|
+
"exportName": "AutoHeight",
|
|
55872
|
+
"displayName": "Высота по содержимому и maxHeight",
|
|
55873
|
+
"type": "full-code",
|
|
55874
|
+
"code": "import { Button, IconButton, BodyS } from '@daisforge/ui';\nimport { TableCanvas } from '@daisforge/ui/components/TableCanvas';\nimport { IconChevronDown, IconChevronUp } from '@daisforge/ui/icons';\nimport React, { useId, useState } from 'react';\n\nfunction AutoHeightExample() {\n const [expanded, setExpanded] = useState(false);\n const [messageCount, setMessageCount] = useState(3);\n const [maxHeight, setMaxHeight] = useState<string | number | undefined>(240);\n const contentId = useId();\n const rows = Array.from({ length: 20 }, (_, id) => ({\n id,\n report: `Отчёт ${id + 1}`,\n }));\n const messages = Array.from(\n { length: messageCount },\n (_, id) => `Сообщение ${id + 1}: данные отчёта обновлены.`,\n );\n\n return (\n <div\n data-testid=\"bottom-sheet-auto-example\"\n data-expanded={expanded}\n data-message-count={messageCount}\n data-max-height={maxHeight ?? 'none'}\n style={{ padding: 16 }}\n >\n <div\n style={{ display: 'flex', flexWrap: 'wrap', gap: 8, marginBottom: 12 }}\n >\n <Button\n size=\"xs\"\n view=\"secondary\"\n onClick={() => setMessageCount((count) => count + 1)}\n >\n Добавить сообщение\n </Button>\n <Button\n size=\"xs\"\n view=\"secondary\"\n disabled={messageCount === 0}\n onClick={() => setMessageCount((count) => Math.max(0, count - 1))}\n >\n Удалить сообщение\n </Button>\n <Button size=\"xs\" view=\"secondary\" onClick={() => setMessageCount(2)}>\n Короткий журнал\n </Button>\n <Button size=\"xs\" view=\"secondary\" onClick={() => setMessageCount(30)}>\n Длинный журнал\n </Button>\n <Button size=\"xs\" view=\"secondary\" onClick={() => setMaxHeight(160)}>\n Максимум 160px\n </Button>\n <Button size=\"xs\" view=\"secondary\" onClick={() => setMaxHeight('40%')}>\n Максимум 40%\n </Button>\n <Button\n size=\"xs\"\n view=\"secondary\"\n onClick={() => setMaxHeight(undefined)}\n >\n Без maxHeight\n </Button>\n </div>\n <TableCanvas\n rows={rows}\n columnConfig={[\n { key: 'id', name: 'ID', width: 100 },\n { key: 'report', name: 'Отчёт', width: 360 },\n ]}\n tableConfig={{\n containerStyle: { height: 480 },\n bottomSheetConfig: {\n height: expanded ? 'auto' : 32,\n minHeight: 32,\n maxHeight,\n content: (\n <div>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n minHeight: 31,\n whiteSpace: 'nowrap',\n }}\n >\n <IconButton\n size=\"xxs\"\n view=\"clear\"\n aria-label={\n expanded ? 'Закрыть авто-панель' : 'Открыть авто-панель'\n }\n aria-expanded={expanded}\n aria-controls={contentId}\n style={{ flexShrink: 0 }}\n onClick={() => setExpanded((value) => !value)}\n >\n {expanded ? (\n <IconChevronDown size=\"xs\" />\n ) : (\n <IconChevronUp size=\"xs\" />\n )}\n </IconButton>\n <BodyS\n style={{\n minWidth: 0,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n Журнал событий\n </BodyS>\n </div>\n <div\n id={contentId}\n data-testid=\"bottom-sheet-auto-content\"\n aria-hidden={!expanded}\n {...(!expanded ? { inert: '' } : {})}\n >\n {messages.map((message) => (\n <BodyS\n key={message}\n data-testid=\"bottom-sheet-auto-message\"\n style={{ padding: '8px 12px' }}\n >\n {message}\n </BodyS>\n ))}\n </div>\n </div>\n ),\n },\n }}\n />\n </div>\n );\n};\n\n<AutoHeightExample />;"
|
|
55136
55875
|
}
|
|
55137
55876
|
]
|
|
55138
55877
|
},
|
|
@@ -55184,6 +55923,107 @@
|
|
|
55184
55923
|
}
|
|
55185
55924
|
]
|
|
55186
55925
|
},
|
|
55926
|
+
{
|
|
55927
|
+
"component": "TableCanvas",
|
|
55928
|
+
"feature": "StickyRowsCols",
|
|
55929
|
+
"legacy": false,
|
|
55930
|
+
"summary": "*tableConfig.stickyColumns, tableConfig.stickyRows**",
|
|
55931
|
+
"docs": "# Липкие строки и колонки (TableCanvas)\n\n**tableConfig.stickyColumns, tableConfig.stickyRows**\n\nСтроки и колонки, которые прилипают к краю таблицы при прокрутке, как `position: sticky` в CSS.\n\n- Элемент едет вместе с таблицей, пока не дойдёт до края, затем остаётся на месте.\n- Следующие липкие встают под ним (строки) или правее него (колонки).\n- В отличие от закреплённых колонок (`columnsControl.pinnedDefault`), липкая колонка остаётся на своём месте в таблице.\n\n## Ключевые особенности\n\n- Колонки задаются ключами или предикатом по колонке — порядок колонок и реордер не важны.\n- Строки задаются предикатом или индексами. Предикат работает с сортировкой и фильтрами, его результаты кешируются (подгрузка чанками проверяет только новые строки). Индексы не требуют прохода по строкам — для таблиц на миллионы строк.\n- Сочетается с закреплёнными колонками, нумерацией строк, группировкой колонок, итоговыми строками и слитыми ячейками.\n- Разная высота строк поддерживается.\n\n> Подробнее о типах — [StickyRowsCols API](?path=/docs/локальные-компоненты-tablecanvas-stickyrowscols-api--docs)",
|
|
55932
|
+
"apiDocs": "# StickyRowsCols API\n\n## tableConfig.stickyColumns\n\n```ts\nstickyColumns?: readonly string[] | ((column: ColumnConfig<RowType>) => boolean);\n```\n\nКолонки, которые прилипают к левому краю при горизонтальной прокрутке. Два способа задать:\n\n**Ключи** (`key` из `columnConfig`):\n\n```tsx\ntableConfig={{ stickyColumns: ['region', 'total'] }}\n```\n\n**Предикат** — когда липкость зависит от свойств колонки:\n\n```tsx\ntableConfig={{ stickyColumns: (column) => column.key.startsWith('total') }}\n```\n\n- Порядок ключей не важен, несуществующие ключи игнорируются.\n- Служебные колонки (нумерация строк, чекбоксы) липкими не становятся — они и так закреплены.\n- Липкие колонки встают правее закреплённых (`columnsControl.pinnedDefault`) и колонки нумерации.\n\n## tableConfig.stickyRows\n\n```ts\nstickyRows?: readonly number[] | ((row: RowType, rowIndex: number) => boolean);\n```\n\nСтроки, которые прилипают под шапкой. Два способа задать:\n\n**Предикат** — вызывается для отображаемых строк данных, `true` — строка липкая.\n\n```tsx\ntableConfig={{ stickyRows: (row) => row.kind === 'subtotal' }}\n```\n\n- Работает с сортировкой и фильтрами: `rowIndex` — индекс среди отображаемых строк.\n- Получает только строки данных (`RowType`): строки групп (`rowsGrouping`) и заглушки загрузки (скелетоны) в предикат не попадают и липкими не становятся.\n- Результаты кешируются: строка, оставшаяся тем же объектом на том же месте, повторно не проверяется. При подгрузке чанками предикат вызывается только для новых строк, при редактировании — только для изменённых.\n- Кеш привязан к функции: передавайте стабильный предикат (`useCallback` или константа вне компонента), иначе каждый рендер проверит все строки заново.\n\n**Индексы** — передаются в таблицу как есть, без прохода по строкам.\n\n```tsx\ntableConfig={{ stickyRows: [0, 250000, 500000] }}\n```\n\n- Подходит для больших таблиц, где позиции липких строк известны заранее (например, их возвращает сервер).\n- Индексы относятся к итоговому отображаемому списку, а не к исходному массиву `rows`. Сортировка, фильтры, группировка (`rowsGrouping` добавляет строки групп) и раскрытые узлы дерева (`subRows`) сдвигают нумерацию — индексы пересчитывает тот, кто их передаёт. Если позиции зависят от этих фич, удобнее предикат.\n- Индексы за пределами таблицы игнорируются.\n\nИтоговые строки (`bottomSummaryRows`) закреплены снизу всегда и липкими не становятся.\n\n## Рекомендации\n\n- Держите число липких строк небольшим: прилипшие строки занимают место под шапкой.\n- Для отчётов удобно делать липкими итоги разделов — при прокрутке видно, к какому разделу относятся данные.\n- Для миллионов строк передавайте индексы; для подгружаемых чанками данных — стабильный предикат.",
|
|
55933
|
+
"api": [],
|
|
55934
|
+
"stories": [
|
|
55935
|
+
{
|
|
55936
|
+
"exportName": "StickyColumns",
|
|
55937
|
+
"displayName": "Липкие колонки",
|
|
55938
|
+
"type": "full-code",
|
|
55939
|
+
"code": "() => (\n <>\n <StoryHint>\n Прокрутите вправо: колонка <b>Регион</b> прилипает к левому краю, а{' '}\n <b>Год</b> встаёт рядом с ней, когда доедет.\n </StoryHint>\n <TableCanvas\n tableConfig={{\n containerStyle: CONTAINER_STYLE,\n stickyColumns: ['region', 'total'],\n }}\n columnConfig={COLUMNS}\n rows={REPORT_ROWS}\n />\n </>\n )"
|
|
55940
|
+
},
|
|
55941
|
+
{
|
|
55942
|
+
"exportName": "StickyColumnsByPredicate",
|
|
55943
|
+
"displayName": "Липкие колонки по условию",
|
|
55944
|
+
"type": "full-code",
|
|
55945
|
+
"code": "() => (\n <>\n <StoryHint>\n Колонки заданы функцией: липкими становятся первые месяцы кварталов.\n Прокрутите вправо — <b>Янв</b>, <b>Апр</b>, <b>Июл</b>, <b>Окт</b> по\n очереди встают у левого края.\n </StoryHint>\n <TableCanvas\n tableConfig={{\n containerStyle: { height: '600px', width: '760px' },\n stickyColumns: (column) => QUARTER_START_MONTHS.has(column.key),\n }}\n columnConfig={COLUMNS}\n rows={REPORT_ROWS}\n />\n </>\n )"
|
|
55946
|
+
},
|
|
55947
|
+
{
|
|
55948
|
+
"exportName": "StickyRows",
|
|
55949
|
+
"displayName": "Липкие строки",
|
|
55950
|
+
"type": "full-code",
|
|
55951
|
+
"code": "() => (\n <>\n <StoryHint>\n Прокрутите вниз: итоги собираются под шапкой — сначала общий, затем итог\n каждого региона, до которого вы доскроллили.\n </StoryHint>\n <TableCanvas\n tableConfig={{\n containerStyle: CONTAINER_STYLE,\n stickyRows: isSubtotalOrTotal,\n }}\n columnConfig={COLUMNS}\n rows={REPORT_ROWS}\n />\n </>\n )"
|
|
55952
|
+
},
|
|
55953
|
+
{
|
|
55954
|
+
"exportName": "RowsAndColumns",
|
|
55955
|
+
"displayName": "Строки и колонки вместе",
|
|
55956
|
+
"type": "full-code",
|
|
55957
|
+
"code": "() => (\n <>\n <StoryHint>\n Липкие колонки <b>Продукт</b> и <b>Год</b>, липкие строки — общий итог и\n итог по Казани. Нумерация строк остаётся слева.\n </StoryHint>\n <TableCanvas\n tableConfig={{\n containerStyle: CONTAINER_STYLE,\n rowMarkers: { startIndex: 1 },\n stickyColumns: ['product', 'total'],\n stickyRows: (row) =>\n row.kind === 'total' ||\n (row.kind === 'subtotal' && row.region === 'Казань'),\n }}\n columnConfig={COLUMNS}\n rows={REPORT_ROWS}\n />\n </>\n )"
|
|
55958
|
+
},
|
|
55959
|
+
{
|
|
55960
|
+
"exportName": "WithPinnedColumns",
|
|
55961
|
+
"displayName": "Вместе с закреплёнными колонками",
|
|
55962
|
+
"type": "full-code",
|
|
55963
|
+
"code": "() => (\n <>\n <StoryHint>\n Колонка <b>№</b> закреплена всегда (\n <code>columnsControl.pinnedDefault</code>), а <b>Продукт</b> и{' '}\n <b>Июн</b> прилипают правее неё. Закрепление можно менять в меню\n колонок.\n </StoryHint>\n <TableCanvas\n tableConfig={{\n containerStyle: CONTAINER_STYLE,\n columnsControl: {\n enable: true,\n pinning: true,\n pinnedDefault: ['id'],\n },\n stickyColumns: ['product', 'm6'],\n stickyRows: (row) => row.kind === 'total',\n }}\n columnConfig={COLUMNS}\n rows={REPORT_ROWS}\n />\n </>\n )"
|
|
55964
|
+
},
|
|
55965
|
+
{
|
|
55966
|
+
"exportName": "WithColumnGroups",
|
|
55967
|
+
"displayName": "С группировкой колонок",
|
|
55968
|
+
"type": "full-code",
|
|
55969
|
+
"code": "() => (\n <>\n <StoryHint>\n Группа в шапке разрывается на границе липкой зоны: <b>Регион</b>{' '}\n остаётся под «Подразделением», а <b>Июл</b> прилипает вместе с подписью\n своей группы.\n </StoryHint>\n <TableCanvas\n tableConfig={{\n containerStyle: CONTAINER_STYLE,\n stickyColumns: ['region', 'm7'],\n stickyRows: isSubtotalOrTotal,\n }}\n columnConfig={GROUPED_COLUMNS}\n rows={REPORT_ROWS}\n />\n </>\n )"
|
|
55970
|
+
},
|
|
55971
|
+
{
|
|
55972
|
+
"exportName": "WithSorting",
|
|
55973
|
+
"displayName": "С сортировкой",
|
|
55974
|
+
"type": "full-code",
|
|
55975
|
+
"code": "() => {\n const sortingState = useState<readonly SortColumn[]>([]);\n\n return (\n <>\n <StoryHint>\n Отсортируйте по <b>Году</b>: итоги переедут на новые места, но\n останутся липкими — строки задаются условием, а не номером.\n </StoryHint>\n <TableCanvas\n tableConfig={{\n containerStyle: CONTAINER_STYLE,\n sorting: { state: sortingState },\n stickyColumns: ['region'],\n stickyRows: isSubtotalOrTotal,\n }}\n columnConfig={SORTABLE_COLUMNS}\n rows={SHORT_REPORT_ROWS}\n />\n </>\n );\n }"
|
|
55976
|
+
},
|
|
55977
|
+
{
|
|
55978
|
+
"exportName": "VariableRowHeight",
|
|
55979
|
+
"displayName": "Разная высота строк",
|
|
55980
|
+
"type": "full-code",
|
|
55981
|
+
"code": "() => (\n <>\n <StoryHint>\n Общий итог высотой 64 px, итоги регионов — 48 px. Полоса прилипших строк\n растёт ступенями, строки под ней уходят без зазоров.\n </StoryHint>\n <TableCanvas\n tableConfig={{\n containerStyle: CONTAINER_STYLE,\n rowHeight: (row, size) =>\n ROW_HEIGHT_BY_KIND[row.kind] ?? size.rowSizeValue,\n stickyColumns: ['product'],\n stickyRows: isSubtotalOrTotal,\n }}\n columnConfig={COLUMNS}\n rows={REPORT_ROWS}\n />\n </>\n )"
|
|
55982
|
+
},
|
|
55983
|
+
{
|
|
55984
|
+
"exportName": "WithSummaryRows",
|
|
55985
|
+
"displayName": "С итоговой строкой снизу",
|
|
55986
|
+
"type": "full-code",
|
|
55987
|
+
"code": "() => (\n <>\n <StoryHint>\n Итоги регионов прилипают сверху, а итоговая строка (\n <code>bottomSummaryRows</code>) всегда закреплена снизу.\n </StoryHint>\n <TableCanvas\n tableConfig={{\n containerStyle: CONTAINER_STYLE,\n summaryRows: { showDefault: true, showInControl: true },\n stickyColumns: ['product', 'total'],\n stickyRows: (row) => row.kind === 'subtotal',\n }}\n columnConfig={COLUMNS_WITH_SUMMARY}\n rows={REPORT_ROWS}\n bottomSummaryRows={SUMMARY_ROWS}\n />\n </>\n )"
|
|
55988
|
+
},
|
|
55989
|
+
{
|
|
55990
|
+
"exportName": "WithMergedCells",
|
|
55991
|
+
"displayName": "Со слитыми ячейками",
|
|
55992
|
+
"type": "full-code",
|
|
55993
|
+
"code": "() => (\n <>\n <StoryHint>\n Регионы слиты в одну ячейку. Когда итог по Санкт-Петербургу прилипает,\n название региона переезжает в прилипшую строку, а остаток блока\n прокручивается под ней.\n </StoryHint>\n <TableCanvas\n tableConfig={{\n containerStyle: CONTAINER_STYLE,\n mergeCells: { mergeByCellValues: ['region'] },\n stickyColumns: ['product'],\n stickyRows: (row) =>\n row.kind === 'subtotal' && row.region === 'Санкт-Петербург',\n }}\n columnConfig={MERGE_COLUMNS}\n rows={MERGE_REPORT_ROWS}\n />\n </>\n )"
|
|
55994
|
+
},
|
|
55995
|
+
{
|
|
55996
|
+
"exportName": "StickyMergedColumn",
|
|
55997
|
+
"displayName": "Липкая колонка со слитыми ячейками",
|
|
55998
|
+
"type": "full-code",
|
|
55999
|
+
"code": "() => (\n <>\n <StoryHint>\n Колонка <b>Регион</b> слита по значениям и при этом липкая. Прокрутите\n вправо — слитые блоки регионов прилипают к левому краю целиком;\n прокрутите вниз — итоги регионов прилипают под шапкой, и название\n региона переезжает в прилипшую строку.\n </StoryHint>\n <TableCanvas\n tableConfig={{\n containerStyle: CONTAINER_STYLE,\n mergeCells: { mergeByCellValues: ['region'] },\n stickyColumns: ['region'],\n stickyRows: (row) => row.kind === 'subtotal',\n }}\n columnConfig={MERGE_COLUMNS}\n rows={MERGE_REPORT_ROWS}\n />\n </>\n )"
|
|
56000
|
+
},
|
|
56001
|
+
{
|
|
56002
|
+
"exportName": "LargeData",
|
|
56003
|
+
"displayName": "20 000 строк",
|
|
56004
|
+
"type": "full-code",
|
|
56005
|
+
"code": "() => {\n const [rows] = useState(() => createReportRows(4000));\n\n return (\n <>\n <StoryHint>\n 20 000 строк и 17 колонок: позиции считаются только по видимым\n строкам, поэтому прокрутка остаётся плавной.\n </StoryHint>\n <TableCanvas\n tableConfig={{\n containerStyle: CONTAINER_STYLE,\n rowMarkers: { startIndex: 1 },\n stickyColumns: ['region', 'total'],\n stickyRows: isSubtotalOrTotal,\n }}\n columnConfig={COLUMNS}\n rows={rows}\n />\n </>\n );\n }"
|
|
56006
|
+
},
|
|
56007
|
+
{
|
|
56008
|
+
"exportName": "MillionRowsByIndexes",
|
|
56009
|
+
"displayName": "1 000 000 строк, липкие по индексам",
|
|
56010
|
+
"type": "full-code",
|
|
56011
|
+
"code": "() => {\n const [rows] = useState(() => createBigRows(0, MILLION));\n\n return (\n <>\n <StoryHint>\n Миллион строк. Липкие строки переданы индексами (\n <code>stickyRows: [0, 250000, …]</code>) — таблица не проходит по\n строкам вообще. Перетащите ползунок прокрутки вниз.\n </StoryHint>\n <TableCanvas\n tableConfig={{\n containerStyle: CONTAINER_STYLE,\n stickyColumns: ['region'],\n stickyRows: MILLION_STICKY_ROWS,\n }}\n columnConfig={BIG_COLUMNS}\n rows={rows}\n />\n </>\n );\n }"
|
|
56012
|
+
},
|
|
56013
|
+
{
|
|
56014
|
+
"exportName": "ChunkLoading",
|
|
56015
|
+
"displayName": "Подгрузка чанками",
|
|
56016
|
+
"type": "full-code",
|
|
56017
|
+
"code": "() => {\n const [rows, setRows] = useState(() => createBigRows(0, CHUNK_SIZE));\n const predicateCalls = useRef(0);\n const [callsShown, setCallsShown] = useState(0);\n\n const isSticky = useCallback((row: BigRow) => {\n predicateCalls.current += 1;\n return row.kind !== 'item';\n }, []);\n\n useEffect(() => setCallsShown(predicateCalls.current), [rows]);\n\n const loadChunk = () =>\n setRows((current) => [\n ...current,\n ...createBigRows(current.length, CHUNK_SIZE),\n ]);\n\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>\n <StoryHint>\n Строки подгружаются чанками по {formatNumber(CHUNK_SIZE)}. Липкие\n строки заданы предикатом; его результаты кешируются, поэтому после\n подгрузки он вызывается только для новых строк — счётчик растёт на\n размер чанка, а не на всю таблицу.\n </StoryHint>\n <div style={{ display: 'flex', gap: 16, alignItems: 'center' }}>\n <Button size=\"s\" view=\"secondary\" onClick={loadChunk}>\n Загрузить ещё {formatNumber(CHUNK_SIZE)}\n </Button>\n <span>\n Строк: <b>{formatNumber(rows.length)}</b> · вызовов предиката:{' '}\n <b>{formatNumber(callsShown)}</b>\n </span>\n </div>\n <TableCanvas\n tableConfig={{\n containerStyle: { height: '540px' },\n stickyColumns: ['region'],\n stickyRows: isSticky,\n }}\n columnConfig={BIG_COLUMNS}\n rows={rows}\n />\n </div>\n );\n }"
|
|
56018
|
+
},
|
|
56019
|
+
{
|
|
56020
|
+
"exportName": "Playground",
|
|
56021
|
+
"displayName": "Песочница",
|
|
56022
|
+
"type": "full-code",
|
|
56023
|
+
"code": "() => {\n const [stickyColumns, setStickyColumns] = useState(['region', 'total']);\n const [stickyIdsText, setStickyIdsText] = useState('1, 2, 23');\n\n const stickyRows = useMemo(() => {\n const ids = parseIds(stickyIdsText);\n return (row: ReportRow) => ids.has(row.id);\n }, [stickyIdsText]);\n\n const toggleColumn = (key: string, checked: boolean) =>\n setStickyColumns((current) =>\n checked ? [...current, key] : current.filter((item) => item !== key),\n );\n\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>\n <StoryHint>\n Укажите номера липких строк (колонка <b>№</b>) и отметьте липкие\n колонки — таблица обновится сразу.\n </StoryHint>\n <div style={{ width: 320 }}>\n <TextField\n size=\"s\"\n label=\"Липкие строки\"\n labelPlacement=\"outer\"\n placeholder=\"Например: 1, 2, 23\"\n value={stickyIdsText}\n onChange={(event) => setStickyIdsText(event.target.value)}\n />\n </div>\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px 20px' }}>\n {COLUMNS.map(({ key, name }) => (\n <Checkbox\n key={key}\n size=\"s\"\n label={typeof name === 'string' ? name : key}\n checked={stickyColumns.includes(key)}\n onChange={(event) => toggleColumn(key, event.target.checked)}\n />\n ))}\n </div>\n <TableCanvas\n tableConfig={{\n containerStyle: { height: '520px' },\n rowMarkers: { startIndex: 1 },\n stickyColumns,\n stickyRows,\n }}\n columnConfig={COLUMNS}\n rows={PLAYGROUND_ROWS}\n />\n </div>\n );\n }"
|
|
56024
|
+
}
|
|
56025
|
+
]
|
|
56026
|
+
},
|
|
55187
56027
|
{
|
|
55188
56028
|
"component": "TableCanvas",
|
|
55189
56029
|
"feature": "SubRows",
|
|
@@ -56544,6 +57384,41 @@
|
|
|
56544
57384
|
"importStatement": "import { DataAttributes } from '@daisforge/ui';",
|
|
56545
57385
|
"sourceFile": "packages/ui-kit/src/components/Table/types/utils.type.ts"
|
|
56546
57386
|
},
|
|
57387
|
+
"AiAgentLeftPanelProps": {
|
|
57388
|
+
"name": "AiAgentLeftPanelProps",
|
|
57389
|
+
"definition": "export type AiAgentLeftPanelProps = {\n /**\n * Разделы панели: иконки в полосе и их контент.\n */\n items: AiAgentLeftPanelItem[];\n /**\n * Ключ открытого раздела. null или undefined — открыта полоса иконок,\n * раздел закрыт. Управляемый режим: значение задаёт потребитель.\n */\n activeKey?: string | null;\n /**\n * Начальный открытый раздел в неуправляемом режиме (когда activeKey\n * не передан).\n */\n defaultActiveKey?: string | null;\n /**\n * Смена открытого раздела: ключ раздела при клике по иконке, null\n * при закрытии крестиком.\n */\n onActiveKeyChange?: (key: string | null) => void;\n};",
|
|
57390
|
+
"importPath": "@daisforge/ui",
|
|
57391
|
+
"importStatement": "import { AiAgentLeftPanelProps } from '@daisforge/ui';",
|
|
57392
|
+
"sourceFile": "packages/ui-kit/src/components/AiAgentPopup/AiAgentPopup.types.ts"
|
|
57393
|
+
},
|
|
57394
|
+
"AiAgentPopupPosition": {
|
|
57395
|
+
"name": "AiAgentPopupPosition",
|
|
57396
|
+
"definition": "export type AiAgentPopupPosition = { x: number; y: number };",
|
|
57397
|
+
"importPath": "@daisforge/ui",
|
|
57398
|
+
"importStatement": "import { AiAgentPopupPosition } from '@daisforge/ui';",
|
|
57399
|
+
"sourceFile": "packages/ui-kit/src/components/AiAgentPopup/AiAgentPopup.types.ts"
|
|
57400
|
+
},
|
|
57401
|
+
"AiAgentPopupPositionState": {
|
|
57402
|
+
"name": "AiAgentPopupPositionState",
|
|
57403
|
+
"definition": "export type AiAgentPopupPositionState = [\n AiAgentPopupPosition,\n Dispatch<SetStateAction<AiAgentPopupPosition>>,\n];",
|
|
57404
|
+
"importPath": "@daisforge/ui",
|
|
57405
|
+
"importStatement": "import { AiAgentPopupPositionState } from '@daisforge/ui';",
|
|
57406
|
+
"sourceFile": "packages/ui-kit/src/components/AiAgentPopup/AiAgentPopup.types.ts"
|
|
57407
|
+
},
|
|
57408
|
+
"AiAgentPopupDragBoundary": {
|
|
57409
|
+
"name": "AiAgentPopupDragBoundary",
|
|
57410
|
+
"definition": "export type AiAgentPopupDragBoundary = {\n top?: number;\n right?: number;\n bottom?: number;\n left?: number;\n};",
|
|
57411
|
+
"importPath": "@daisforge/ui",
|
|
57412
|
+
"importStatement": "import { AiAgentPopupDragBoundary } from '@daisforge/ui';",
|
|
57413
|
+
"sourceFile": "packages/ui-kit/src/components/AiAgentPopup/AiAgentPopup.types.ts"
|
|
57414
|
+
},
|
|
57415
|
+
"AiAgentPopupSize": {
|
|
57416
|
+
"name": "AiAgentPopupSize",
|
|
57417
|
+
"definition": "export type AiAgentPopupSize = { width: number; height: number };",
|
|
57418
|
+
"importPath": "@daisforge/ui",
|
|
57419
|
+
"importStatement": "import { AiAgentPopupSize } from '@daisforge/ui';",
|
|
57420
|
+
"sourceFile": "packages/ui-kit/src/components/AiAgentPopup/AiAgentPopup.types.ts"
|
|
57421
|
+
},
|
|
56547
57422
|
"AnalyticalWidgetSize": {
|
|
56548
57423
|
"name": "AnalyticalWidgetSize",
|
|
56549
57424
|
"definition": "export type AnalyticalWidgetSize = 'l' | 'm' | 's';",
|
|
@@ -56749,7 +57624,7 @@
|
|
|
56749
57624
|
},
|
|
56750
57625
|
"HoverEffectsConfig": {
|
|
56751
57626
|
"name": "HoverEffectsConfig",
|
|
56752
|
-
"definition": "export type HoverEffectsConfig = {\n /**\n * Подсветка строки под курсором. По умолчанию
|
|
57627
|
+
"definition": "export type HoverEffectsConfig = {\n /**\n * Подсветка строки под курсором. По умолчанию ВКЛЮЧЕНА.\n * - не задано или `true` — включена, цвета из темы;\n * - `false` — выключена явно.\n *\n * Цвета по зонам строки берутся из темы:\n * - data-ячейки — `bgRowHovered`;\n * - служебные колонки (нумерация, чекбокс) — `bgServiceRowHovered`, тот же\n * цвет, что у сервис-зоны при выделении;\n * - строка, отмеченная чекбоксом, темнеет целиком `bgSelectedRowHovered`;\n * - выбранная строка (`highlightActiveType: 'row'`) под курсором делает\n * шаг глубже: hover (с нажатым чекбоксом — hover2), цветные ячейки —\n * свой hover2.\n *\n * Hover — самый нижний слой: выделение ячеек, строк и колонок рисуется\n * поверх и перекрывает его; после сброса выделения он снова виден.\n * Summary-строки hover не получают.\n */\n row?: boolean;\n};",
|
|
56753
57628
|
"importPath": "@daisforge/ui/components/TableCanvas",
|
|
56754
57629
|
"importStatement": "import { HoverEffectsConfig } from '@daisforge/ui/components/TableCanvas';",
|
|
56755
57630
|
"sourceFile": "packages/ui-kit/src/components/TableGlide/types.ts"
|
|
@@ -56901,6 +57776,13 @@
|
|
|
56901
57776
|
"importStatement": "import { AiAgentPopoverCustomPlacement } from '@daisforge/ui';",
|
|
56902
57777
|
"sourceFile": "packages/ui-kit/src/components/AiAgentPopover/AiAgentPopover.types.ts"
|
|
56903
57778
|
},
|
|
57779
|
+
"AiAgentLeftPanelItem": {
|
|
57780
|
+
"name": "AiAgentLeftPanelItem",
|
|
57781
|
+
"definition": "export type AiAgentLeftPanelItem = {\n /**\n * Уникальный ключ раздела: по нему определяется открытый раздел\n * (activeKey) и приходит смена в onActiveKeyChange.\n */\n key: string;\n /**\n * Иконка в полосе (свёрнутое состояние левой панели).\n */\n icon: ReactNode;\n /**\n * Иконка слева в шапке открытого раздела, компонент ставит её по центру\n * квадрата 40x40. Если не задана, берётся icon.\n */\n titleIcon?: ReactNode;\n /**\n * Заголовок открытого раздела (в шапке, рядом с иконкой и крестиком).\n */\n title: ReactNode;\n /**\n * Контент открытого раздела под шапкой. Отступы, скролл и наполнение\n * полностью на стороне потребителя.\n */\n content: ReactNode;\n};",
|
|
57782
|
+
"importPath": "@daisforge/ui",
|
|
57783
|
+
"importStatement": "import { AiAgentLeftPanelItem } from '@daisforge/ui';",
|
|
57784
|
+
"sourceFile": "packages/ui-kit/src/components/AiAgentPopup/AiAgentPopup.types.ts"
|
|
57785
|
+
},
|
|
56904
57786
|
"ChipCompProps": {
|
|
56905
57787
|
"name": "ChipCompProps",
|
|
56906
57788
|
"definition": "export type ChipCompProps = ComponentProps<typeof Chip>;",
|
|
@@ -57372,7 +58254,7 @@
|
|
|
57372
58254
|
},
|
|
57373
58255
|
"ColumnGlideCustoms": {
|
|
57374
58256
|
"name": "ColumnGlideCustoms",
|
|
57375
|
-
"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};",
|
|
58257
|
+
"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 /**\n * Свой цвет ячеек колонки (тема ячейки).\n *\n * Цвет лучше брать из темы (`cellInfo.theme`), например статусные\n * `theme.bgCellPositive / bgCellNegative / bgCellWarning / bgCellInfo`:\n * они свои для каждой темы. Фиксированный hex в тёмной теме останется\n * таким же светлым, как в светлой.\n *\n * Подробнее. Если вернуть `bgCell` hex-цветом (`#RGB`, `#RRGGBB`,\n * `#RRGGBBAA` — прозрачный цвет сначала смешивается с фоном ячейки),\n * таблица сама посчитает его состояния (под курсором, в выбранной строке,\n * в выделении) — цвет ведёт себя как встроенные. Не-hex значение\n * (`rgba()`, `var()` и т. п.) применяется как есть, без состояний: ячейка\n * не отреагирует на курсор и выделение.\n */\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};",
|
|
57376
58258
|
"internal": true,
|
|
57377
58259
|
"importNotice": "Тип \"ColumnGlideCustoms\" не экспортируется из публичной точки входа — импортировать его нельзя. Определение приведено для понимания структуры: опишите нужную форму по месту либо возьмите её из типа, который экспортирован.",
|
|
57378
58260
|
"sourceFile": "packages/ui-kit/src/components/TableGlide/types.ts"
|
|
@@ -57440,6 +58322,41 @@
|
|
|
57440
58322
|
"importNotice": "Тип \"AiAgentPopoverResizableConfig\" не экспортируется из публичной точки входа — импортировать его нельзя. Определение приведено для понимания структуры: опишите нужную форму по месту либо возьмите её из типа, который экспортирован.",
|
|
57441
58323
|
"sourceFile": "packages/ui-kit/src/components/AiAgentPopover/AiAgentPopover.types.ts"
|
|
57442
58324
|
},
|
|
58325
|
+
"TextAreaProps": {
|
|
58326
|
+
"name": "TextAreaProps",
|
|
58327
|
+
"definition": "type TextAreaProps = ComponentProps<typeof TextArea>;",
|
|
58328
|
+
"internal": true,
|
|
58329
|
+
"importNotice": "Тип \"TextAreaProps\" не экспортируется из публичной точки входа — импортировать его нельзя. Определение приведено для понимания структуры: опишите нужную форму по месту либо возьмите её из типа, который экспортирован.",
|
|
58330
|
+
"sourceFile": "packages/ui-kit/src/components/AiAgentPopup/AiAgentPopup.types.ts"
|
|
58331
|
+
},
|
|
58332
|
+
"PopupProps": {
|
|
58333
|
+
"name": "PopupProps",
|
|
58334
|
+
"definition": "type PopupProps = ComponentProps<typeof Popup>;",
|
|
58335
|
+
"internal": true,
|
|
58336
|
+
"importNotice": "Тип \"PopupProps\" не экспортируется из публичной точки входа — импортировать его нельзя. Определение приведено для понимания структуры: опишите нужную форму по месту либо возьмите её из типа, который экспортирован.",
|
|
58337
|
+
"sourceFile": "packages/ui-kit/src/components/AiAgentPopup/AiAgentPopup.types.ts"
|
|
58338
|
+
},
|
|
58339
|
+
"AiAgentPopupFrame": {
|
|
58340
|
+
"name": "AiAgentPopupFrame",
|
|
58341
|
+
"definition": "export type AiAgentPopupFrame = PopupProps['frame'];",
|
|
58342
|
+
"internal": true,
|
|
58343
|
+
"importNotice": "Тип \"AiAgentPopupFrame\" не экспортируется из публичной точки входа — импортировать его нельзя. Определение приведено для понимания структуры: опишите нужную форму по месту либо возьмите её из типа, который экспортирован.",
|
|
58344
|
+
"sourceFile": "packages/ui-kit/src/components/AiAgentPopup/AiAgentPopup.types.ts"
|
|
58345
|
+
},
|
|
58346
|
+
"AiAgentPopupTargetGap": {
|
|
58347
|
+
"name": "AiAgentPopupTargetGap",
|
|
58348
|
+
"definition": "export type AiAgentPopupTargetGap = number | { x?: number; y?: number };",
|
|
58349
|
+
"importPath": "@daisforge/ui",
|
|
58350
|
+
"importStatement": "import { AiAgentPopupTargetGap } from '@daisforge/ui';",
|
|
58351
|
+
"sourceFile": "packages/ui-kit/src/components/AiAgentPopup/AiAgentPopup.types.ts"
|
|
58352
|
+
},
|
|
58353
|
+
"AiAgentPopupResizableConfig": {
|
|
58354
|
+
"name": "AiAgentPopupResizableConfig",
|
|
58355
|
+
"definition": "export type AiAgentPopupResizableConfig = Exclude<\n PopupProps['resizable'],\n boolean | undefined\n>;",
|
|
58356
|
+
"importPath": "@daisforge/ui",
|
|
58357
|
+
"importStatement": "import { AiAgentPopupResizableConfig } from '@daisforge/ui';",
|
|
58358
|
+
"sourceFile": "packages/ui-kit/src/components/AiAgentPopup/AiAgentPopup.types.ts"
|
|
58359
|
+
},
|
|
57443
58360
|
"AutocompleteBaseProps": {
|
|
57444
58361
|
"name": "AutocompleteBaseProps",
|
|
57445
58362
|
"definition": "type AutocompleteBaseProps = ComponentProps<typeof BaseAutocomplete>;",
|
|
@@ -57764,7 +58681,7 @@
|
|
|
57764
58681
|
},
|
|
57765
58682
|
"TableCanvas.TableConfig": {
|
|
57766
58683
|
"name": "TableConfig",
|
|
57767
|
-
"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 *
|
|
58684
|
+
"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-подсветка ВКЛЮЧЕНА (цвета из темы);\n * `{ row: false }` — выключить явно.\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 * Управление рамками (линиями) таблицы: включение и выключение.\n *\n * Уровни, от слабого к сильному: общие настройки (vertical, horizontal),\n * затем колонка (getVerticalBorder) и строка (getHorizontalBorder), затем\n * ячейка (getCellBorder).\n *\n * `vertical: false` и `horizontal: false` убирают все вертикальные или\n * горизонтальные линии тела. `getCellBorder` включает и выключает стороны\n * рамки конкретной ячейки; при его использовании линии рисуются с разбивкой\n * по ячейкам.\n */\n borders?: BordersConfig<RowType>;\n /**\n * rowSize - размеры строк таблицы\n */\n rowSize?: Prettify<RowSize>;\n /**\n * rowHeight - размер высоты строк таблицы\n */\n rowHeight?: Maybe<number | RowHeightFunc<RowType>>;\n /**\n * headerRowHeight - высота одного ряда шапки (в px). По умолчанию 33.\n *\n * Значение применяется к КАЖДОМУ уровню шапки: как к листовому (нижнему) ряду\n * колонок, так и к каждому уровню объединённых (групповых) заголовков. Поэтому\n * при N уровнях группировки итоговая высота шапки = headerRowHeight * (1 + N).\n * Например, headerRowHeight={50} при 2 уровнях групп даст шапку 50 + 50 + 50 = 150px.\n */\n headerRowHeight?: Maybe<number>;\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 * columnConf…",
|
|
57768
58685
|
"importPath": "@daisforge/ui/components/TableCanvas",
|
|
57769
58686
|
"importStatement": "import { TableConfig } from '@daisforge/ui/components/TableCanvas';",
|
|
57770
58687
|
"sourceFile": "packages/ui-kit/src/components/TableCanvas/types/table-config.type.ts"
|
|
@@ -57832,6 +58749,20 @@
|
|
|
57832
58749
|
"importStatement": "import { RowsChangeDataGlideInstance } from '@daisforge/ui/components/TableCanvas';",
|
|
57833
58750
|
"sourceFile": "packages/ui-kit/src/components/TableCanvas/TableGlideInstance/type.ts"
|
|
57834
58751
|
},
|
|
58752
|
+
"StickyColumnsConfig": {
|
|
58753
|
+
"name": "StickyColumnsConfig",
|
|
58754
|
+
"definition": "export type StickyColumnsConfig<ColumnType> =\n | readonly string[]\n | ((column: ColumnType) => boolean);",
|
|
58755
|
+
"internal": true,
|
|
58756
|
+
"importNotice": "Тип \"StickyColumnsConfig\" не экспортируется из публичной точки входа — импортировать его нельзя. Определение приведено для понимания структуры: опишите нужную форму по месту либо возьмите её из типа, который экспортирован.",
|
|
58757
|
+
"sourceFile": "packages/ui-kit/src/components/TableCanvas/feature-sticky/types.ts"
|
|
58758
|
+
},
|
|
58759
|
+
"StickyRowsConfig": {
|
|
58760
|
+
"name": "StickyRowsConfig",
|
|
58761
|
+
"definition": "export type StickyRowsConfig<RowType> =\n | readonly number[]\n | ((row: RowType, rowIndex: number) => boolean);",
|
|
58762
|
+
"internal": true,
|
|
58763
|
+
"importNotice": "Тип \"StickyRowsConfig\" не экспортируется из публичной точки входа — импортировать его нельзя. Определение приведено для понимания структуры: опишите нужную форму по месту либо возьмите её из типа, который экспортирован.",
|
|
58764
|
+
"sourceFile": "packages/ui-kit/src/components/TableCanvas/feature-sticky/types.ts"
|
|
58765
|
+
},
|
|
57835
58766
|
"TableGlideInstanceContextMenu": {
|
|
57836
58767
|
"name": "TableGlideInstanceContextMenu",
|
|
57837
58768
|
"definition": "export type TableGlideInstanceContextMenu<\n R extends ObjectForExtending,\n SR = unknown,\n CustomCtxs extends ObjectForExtending = {},\n> = {\n onHeaderContextMenu?: (\n ...args: [\n ...Parameters<NonNullable<TableGlideProps<R, SR>['onHeaderContextMenu']>>,\n TableInfoBase<R, SR, CustomCtxs>,\n ]\n ) => void;\n onCellContextMenu?: (\n ...args: [\n ...Parameters<NonNullable<TableGlideProps<R, SR>['onCellContextMenu']>>,\n TableInfoWithRow<R, SR, CustomCtxs>,\n ]\n ) => void;\n};",
|
|
@@ -57897,7 +58828,7 @@
|
|
|
57897
58828
|
},
|
|
57898
58829
|
"TableGlideCustomProps": {
|
|
57899
58830
|
"name": "TableGlideCustomProps",
|
|
57900
|
-
"definition": "export type TableGlideCustomProps<\n R extends ObjectForExtending,\n SR = unknown\n> = {\n columns: ColumnGlideLast<R, SR>[];\n rows: readonly R[];\n bottomSummaryRows?: readonly SR[];\n rowSize?: SIZE;\n rowHeight?:\n | ((\n row: R,\n currentRowSize: {\n rowSizeName: SIZE;\n rowSizeValue: number;\n },\n rowIndex: number\n ) => number)\n | number\n | undefined\n | null;\n ctxs?: ObjectForExtending;\n renderGroupHeader?: (\n args: RenderGroupHeaderArgs\n ) => 'default' | { defaultWithCustomGroupName: string } | CanvasEl;\n /** Выравнивание текста в объединённой шапке по ключу группы (ColumnGroupConfig.key). */\n groupAlignMap?: Map<string, SpanAlignment>;\n refTable?: Ref<DataEditorRef>;\n onColumnsReorder?: (sourceKey: string, targetKey: string) => void;\n /** Ref на контейнер таблицы — события portal hover диспатчатся на него, чтобы несколько таблиц не перехватывали чужие тултипы */\n portalEventTargetRef?: RefObject<HTMLElement | null>;\n /** Откреплённая шапка — header уезжает вместе со скроллом */\n unstickyHeader?: boolean;\n // отключает resize колонок (по умолчанию true)\n resizableColumn?: boolean;\n /** Внешний ref на wrapper-div (для TableCanvas - refTableContainer) */\n containerRef?: Ref<HTMLDivElement>;\n /** className для wrapper-div */\n containerClassName?: string;\n /** inline-style для wrapper-div */\n containerStyle?: CSSProperties;\n /** Рендер overlay-фич (tooltip, contextMenu, popover) внутри wrapper-div когда DOM готов */\n renderOverlayFeatures?: (ctx: {\n containerElement: HTMLDivElement;\n renderInContainer: (children: ReactNode) => ReactPortal | null;\n }) => ReactNode;\n /** Не рендерить canvas-grid, оставив только overlay-content внутри wrapper. */\n hideGrid?: boolean;\n /** DOM-узел content-state (empty/error), рендерится как прямой child контейнера. */\n contentStateNode?: ReactNode;\n /** Флаг fullscreen - пересканирование DOM при переключении */\n fullScreened?: boolean;\n /** Переносит editor overlay внутрь контейнера (вместо document.body). Для модалок с CSS transform. */\n editorOverlayPortal?: 'inside';\n groupHeaderHeight?: number[];\n /** Управляет canvas-подсветкой активной сущности поверх glide selection. */\n highlightActiveType?: HighlightActiveType;\n /** Режим выделения ячеек (нативный glide selection). По умолчанию 'range-cell'. */\n cellsSelectionMode?: CellsSelectionMode;\n /** Канал для copy/paste (selectionRef потребителя), отдельно от controlled gridSelection. */\n onSelectionEmit?: (selection: GridSelection) => void;\n /**\n * Ключи выделенных КОЛОНОК (объединение: одиночный клик/Shift/select-all +\n * Ctrl-мультивыбор), без сервисных колонок. Канал наверх для контрл-блока\n * (например «Закрепить столбцы»). Обычное выделение ячеек сюда не попадает.\n */\n onColumnSelectionChange?: (selectedColumnKeys: string[]) => void;\n /**\n * Follow-выделение: после реордера (закрепление колонок) заново выделить эти\n * ключи. Пустой массив → снять выделение. null/undefined → не трогать.\n */\n pendingColumnSelectionKeys?: string[] | null;\n /** Вызывается после применения pendingColumnSelectionKeys (сброс pending). */\n onColumnSelectionApplied?: () => void;\n /** Controlled-значение подсвеченной строки (highlightActiveType='row'). */\n highlightActiveRow?: number;\n /**\n * Controlled-сеттер подсвеченной строки. Вторым аргументом отдаёт сам объект\n * строки (`rows[index]`) — чтобы потребитель получал узел без onCellClicked.\n */\n onHighlightActiveRowChange?: (\n row: number | undefined,\n rowData?: R | undefined\n ) => void;\n /**\n * Режим подсветки строки controlled (значением владеют снаружи). Если не\n * задан — таблица крутит подсветку внутренним стейтом, но колбэк всё равно\n * вызывается (подписка без владения).\n */\n highlightActiveRowControlled?: boolean;\n /** Выделение колонок по клику на шапку (независимо от highlightActiveType). По умолчанию true. */\n enableColumnSelection?: boolean;\n /** Выделение строк по клику/драгу на колонке нумерации. По умолчанию true. */\n enableRowSelection?: boolean;\n /** Выделение всей таблицы кликом по шапке колонки нумерации. По умолчанию true. */\n enableSelectAll?: boolean;\n /** Индексы строк, выбранных через checkbox selection. */\n checkboxSelectedRowIndexes?: ReadonlySet<number>;\n
|
|
58831
|
+
"definition": "export type TableGlideCustomProps<\n R extends ObjectForExtending,\n SR = unknown\n> = {\n columns: ColumnGlideLast<R, SR>[];\n rows: readonly R[];\n bottomSummaryRows?: readonly SR[];\n rowSize?: SIZE;\n rowHeight?:\n | ((\n row: R,\n currentRowSize: {\n rowSizeName: SIZE;\n rowSizeValue: number;\n },\n rowIndex: number\n ) => number)\n | number\n | undefined\n | null;\n ctxs?: ObjectForExtending;\n renderGroupHeader?: (\n args: RenderGroupHeaderArgs\n ) => 'default' | { defaultWithCustomGroupName: string } | CanvasEl;\n /** Выравнивание текста в объединённой шапке по ключу группы (ColumnGroupConfig.key). */\n groupAlignMap?: Map<string, SpanAlignment>;\n refTable?: Ref<DataEditorRef>;\n onColumnsReorder?: (sourceKey: string, targetKey: string) => void;\n /** Ref на контейнер таблицы — события portal hover диспатчатся на него, чтобы несколько таблиц не перехватывали чужие тултипы */\n portalEventTargetRef?: RefObject<HTMLElement | null>;\n /** Откреплённая шапка — header уезжает вместе со скроллом */\n unstickyHeader?: boolean;\n // отключает resize колонок (по умолчанию true)\n resizableColumn?: boolean;\n /** Внешний ref на wrapper-div (для TableCanvas - refTableContainer) */\n containerRef?: Ref<HTMLDivElement>;\n /** className для wrapper-div */\n containerClassName?: string;\n /** inline-style для wrapper-div */\n containerStyle?: CSSProperties;\n /** Рендер overlay-фич (tooltip, contextMenu, popover) внутри wrapper-div когда DOM готов */\n renderOverlayFeatures?: (ctx: {\n containerElement: HTMLDivElement;\n renderInContainer: (children: ReactNode) => ReactPortal | null;\n }) => ReactNode;\n /** Не рендерить canvas-grid, оставив только overlay-content внутри wrapper. */\n hideGrid?: boolean;\n /** DOM-узел content-state (empty/error), рендерится как прямой child контейнера. */\n contentStateNode?: ReactNode;\n /** Дополнительный контент wrapper-div, не зависящий от готовности canvas-grid. */\n containerSlot?: ReactNode;\n /** Флаг fullscreen - пересканирование DOM при переключении */\n fullScreened?: boolean;\n /** Переносит editor overlay внутрь контейнера (вместо document.body). Для модалок с CSS transform. */\n editorOverlayPortal?: 'inside';\n groupHeaderHeight?: number[];\n /** Управляет canvas-подсветкой активной сущности поверх glide selection. */\n highlightActiveType?: HighlightActiveType;\n /** Режим выделения ячеек (нативный glide selection). По умолчанию 'range-cell'. */\n cellsSelectionMode?: CellsSelectionMode;\n /** Канал для copy/paste (selectionRef потребителя), отдельно от controlled gridSelection. */\n onSelectionEmit?: (selection: GridSelection) => void;\n /**\n * Ключи выделенных КОЛОНОК (объединение: одиночный клик/Shift/select-all +\n * Ctrl-мультивыбор), без сервисных колонок. Канал наверх для контрл-блока\n * (например «Закрепить столбцы»). Обычное выделение ячеек сюда не попадает.\n */\n onColumnSelectionChange?: (selectedColumnKeys: string[]) => void;\n /**\n * Follow-выделение: после реордера (закрепление колонок) заново выделить эти\n * ключи. Пустой массив → снять выделение. null/undefined → не трогать.\n */\n pendingColumnSelectionKeys?: string[] | null;\n /** Вызывается после применения pendingColumnSelectionKeys (сброс pending). */\n onColumnSelectionApplied?: () => void;\n /** Controlled-значение подсвеченной строки (highlightActiveType='row'). */\n highlightActiveRow?: number;\n /**\n * Controlled-сеттер подсвеченной строки. Вторым аргументом отдаёт сам объект\n * строки (`rows[index]`) — чтобы потребитель получал узел без onCellClicked.\n */\n onHighlightActiveRowChange?: (\n row: number | undefined,\n rowData?: R | undefined\n ) => void;\n /**\n * Режим подсветки строки controlled (значением владеют снаружи). Если не\n * задан — таблица крутит подсветку внутренним стейтом, но колбэк всё равно\n * вызывается (подписка без владения).\n */\n highlightActiveRowControlled?: boolean;\n /** Выделение колонок по клику на шапку (независимо от highlightActiveType). По умолчанию true. */\n enableColumnSelection?: boolean;\n /** Выделение строк по клику/драгу на колонке нумерации. По умолчанию true. */\n enableRowSelection?: boolean;\n /** Выделение всей таблицы кликом по шапке колонки нумерации. По умолчанию true. */\n enableSelectAll?: boolean;\n /** Индексы строк, выбранных через checkbox selection. */\n checkboxSelectedRowIndexes?: ReadonlySet<number>;\n /**\n * Индексы строк, у которых ЕСТЬ (виден) чекбокс.\n * @deprecated На цвет не влияет: наличие чекбокса не меняет цвет выбранной\n * строки, ступень добавляет только НАЖАТЫЙ чекбокс\n * (`checkboxSelectedRowIndexes`). Удалить в следующем мажоре.\n */\n checkboxVisibleRowIndexes?: ReadonlySet<number>;\n /**\n * Эффекты при наведении. `hoverEffects.row` — подсветка строки под курсором:\n * рисуется через bgCell (getRowThemeOverride), т.е. лежит ПОД селектингом и\n * highlightActiveType — они рисуются поверх (highlightRegions) и визуально\n * перекрывают hover. По умолчанию row-подсветка ВКЛЮЧЕНА; выключение —\n * явное `{ row: false }`.\n */\n hoverEffects?: HoverEffectsConfig;\n /** Включает компенсацию тонких canvas-линий при browser zoom ниже 100% / DPR < 1. */\n enableLowDprHairline?: boolean;\n};",
|
|
57901
58832
|
"importPath": "@daisforge/ui/components/TableCanvas",
|
|
57902
58833
|
"importStatement": "import { TableGlideCustomProps } from '@daisforge/ui/components/TableCanvas';",
|
|
57903
58834
|
"sourceFile": "packages/ui-kit/src/components/TableGlide/types.ts"
|
|
@@ -58912,7 +59843,7 @@
|
|
|
58912
59843
|
},
|
|
58913
59844
|
"TableCanvas.SidebarConfig": {
|
|
58914
59845
|
"name": "SidebarConfig",
|
|
58915
|
-
"definition": "export type SidebarConfig =
|
|
59846
|
+
"definition": "export type SidebarConfig = TableCanvasSidebarConfig & {\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};",
|
|
58916
59847
|
"importPath": "@daisforge/ui/components/TableCanvas",
|
|
58917
59848
|
"importStatement": "import { SidebarConfig } from '@daisforge/ui/components/TableCanvas';",
|
|
58918
59849
|
"sourceFile": "packages/ui-kit/src/components/TableCanvas/types/table-config.type.ts"
|
|
@@ -59526,9 +60457,30 @@
|
|
|
59526
60457
|
"importStatement": "import { TableCanvasErrorStateConfig } from '@daisforge/ui/components/TableCanvas';",
|
|
59527
60458
|
"sourceFile": "packages/ui-kit/src/components/TableCanvas/feature-content-state/types.ts"
|
|
59528
60459
|
},
|
|
60460
|
+
"RightSidebarConfig": {
|
|
60461
|
+
"name": "RightSidebarConfig",
|
|
60462
|
+
"definition": "export type RightSidebarConfig = SidebarConfig;",
|
|
60463
|
+
"importPath": "@daisforge/ui",
|
|
60464
|
+
"importStatement": "import { RightSidebarConfig } from '@daisforge/ui';",
|
|
60465
|
+
"sourceFile": "packages/ui-kit/src/components/TableCanvas/types/table-config.type.ts"
|
|
60466
|
+
},
|
|
60467
|
+
"LeftSidebarConfig": {
|
|
60468
|
+
"name": "LeftSidebarConfig",
|
|
60469
|
+
"definition": "export type LeftSidebarConfig = TableCanvasSidebarConfig;",
|
|
60470
|
+
"importPath": "@daisforge/ui",
|
|
60471
|
+
"importStatement": "import { LeftSidebarConfig } from '@daisforge/ui';",
|
|
60472
|
+
"sourceFile": "packages/ui-kit/src/components/TableCanvas/types/table-config.type.ts"
|
|
60473
|
+
},
|
|
60474
|
+
"BottomSheetConfig": {
|
|
60475
|
+
"name": "BottomSheetConfig",
|
|
60476
|
+
"definition": "export type BottomSheetConfig = {\n /** @default true */\n enabled?: boolean;\n /** Число — px, строка — CSS; 'auto' — по содержимому. Проценты — от рабочей области. @default 32 */\n height?: string | number;\n /** Минимальная высота, ограниченная доступным пространством. @default 32 */\n minHeight?: string | number;\n /** Максимальная высота в px или CSS, дополнительно ограниченная доступным пространством. */\n maxHeight?: string | number;\n /** Пользователь управляет содержимым и раскрытием; при height: 'auto' панель прокручивается сама. */\n content: React.ReactNode;\n};",
|
|
60477
|
+
"importPath": "@daisforge/ui",
|
|
60478
|
+
"importStatement": "import { BottomSheetConfig } from '@daisforge/ui';",
|
|
60479
|
+
"sourceFile": "packages/ui-kit/src/components/TableCanvas/types/table-config.type.ts"
|
|
60480
|
+
},
|
|
59529
60481
|
"TableGlideInstanceProps": {
|
|
59530
60482
|
"name": "TableGlideInstanceProps",
|
|
59531
|
-
"definition": "export type TableGlideInstanceProps<\n R extends ObjectForExtending,\n SR = unknown,\n CustomCtxs extends ObjectForExtending = {},\n> = Omit<\n TableGlideProps<R, SR>,\n 'columns' | 'onHeaderContextMenu' | 'onCellContextMenu'\n> & {\n columns: readonly ColumnGlideInstance<R, SR, CustomCtxs>[];\n onHeaderContextMenuDropdown?: HeaderContextMenuDropdownProps<\n R,\n SR,\n CustomCtxs\n >;\n onCellContextMenuDropdown?: CellContextMenuDropdownProps<R, SR>;\n containerProps?: {\n className?: string;\n style?: React.CSSProperties;\n ref?: React.Ref<HTMLDivElement>;\n };\n contentStateOverlay?: TableContentStateOverlay;\n renderOverlayFeatures?: (ctx: {\n containerElement: HTMLDivElement;\n renderInContainer: (children: React.ReactNode) => React.ReactPortal | null;\n }) => React.ReactNode;\n CellReadOnlyEditor: (\n props: CellReadOnlyEditorGlideInstanceProps<R, SR>,\n ) => ReactNode;\n onRowsChange?: (\n rows: R[],\n data: RowsChangeDataGlideInstance<R, SR, CustomCtxs>,\n ) => void;\n onCellClicked?: (\n cell: readonly [number, number],\n info: TableInfoWithRow<R, SR, CustomCtxs>,\n ) => void;\n} & TableGlideInstanceContextMenu<R, SR, CustomCtxs>;",
|
|
60483
|
+
"definition": "export type TableGlideInstanceProps<\n R extends ObjectForExtending,\n SR = unknown,\n CustomCtxs extends ObjectForExtending = {},\n> = Omit<\n TableGlideProps<R, SR>,\n 'columns' | 'onHeaderContextMenu' | 'onCellContextMenu'\n> & {\n columns: readonly ColumnGlideInstance<R, SR, CustomCtxs>[];\n onHeaderContextMenuDropdown?: HeaderContextMenuDropdownProps<\n R,\n SR,\n CustomCtxs\n >;\n onCellContextMenuDropdown?: CellContextMenuDropdownProps<R, SR>;\n containerProps?: {\n className?: string;\n style?: React.CSSProperties;\n ref?: React.Ref<HTMLDivElement>;\n };\n contentStateOverlay?: TableContentStateOverlay;\n renderOverlayFeatures?: (ctx: {\n containerElement: HTMLDivElement;\n renderInContainer: (children: React.ReactNode) => React.ReactPortal | null;\n }) => React.ReactNode;\n CellReadOnlyEditor: (\n props: CellReadOnlyEditorGlideInstanceProps<R, SR>,\n ) => ReactNode;\n onRowsChange?: (\n rows: R[],\n data: RowsChangeDataGlideInstance<R, SR, CustomCtxs>,\n ) => void;\n onCellClicked?: (\n cell: readonly [number, number],\n info: TableInfoWithRow<R, SR, CustomCtxs>,\n ) => void;\n stickyColumnsConfig?: StickyColumnsConfig<\n ColumnGlideInstance<R, SR, CustomCtxs>\n >;\n stickyRowsConfig?: StickyRowsConfig<R>;\n} & TableGlideInstanceContextMenu<R, SR, CustomCtxs>;",
|
|
59532
60484
|
"importPath": "@daisforge/ui/components/TableCanvas",
|
|
59533
60485
|
"importStatement": "import { TableGlideInstanceProps } from '@daisforge/ui/components/TableCanvas';",
|
|
59534
60486
|
"sourceFile": "packages/ui-kit/src/components/TableCanvas/TableGlideInstance/type.ts"
|