UNPKG

@itwin/presentation-components

Version:

React components based on iTwin.js Presentation library

153 lines 7.8 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /* eslint-disable @typescript-eslint/no-deprecated */ /** @packageDocumentation * @module Tree */ import "../../common/DisposePolyfill.js"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { MutableTreeModel, TreeModelSource, usePagedTreeNodeLoader, } from "@itwin/components-react"; import { IModelApp } from "@itwin/core-frontend"; import { Presentation } from "@itwin/presentation-frontend"; import { PresentationTreeDataProvider } from "../DataProvider.js"; import { reloadTree } from "./TreeReloader.js"; import { useFilteredNodeLoader, useNodeHighlightingProps } from "./UseControlledTreeFiltering.js"; /** * Custom hooks which creates PagedTreeNodeLoader with PresentationTreeDataProvider using * supplied imodel and ruleset. * @public * @deprecated in 4.x. This hook is not compatible with React 18 `StrictMode`. Use [[usePresentationTreeState]] instead. */ export function usePresentationTreeNodeLoader(props) { const { seedTreeModel, ...rest } = props; const firstRenderRef = useRef(true); const treeNodeLoaderStateProps = useMemo(() => ({ ...rest, seedTreeModel: firstRenderRef.current ? seedTreeModel : undefined }), Object.values(rest)); const [{ modelSource, dataProvider }, setState] = useState(() => ({ modelSource: new TreeModelSource(new MutableTreeModel(treeNodeLoaderStateProps.seedTreeModel)), dataProvider: new PresentationTreeDataProvider({ ...treeNodeLoaderStateProps }), })); useEffect(() => { const provider = new PresentationTreeDataProvider({ ...treeNodeLoaderStateProps }); setState({ modelSource: new TreeModelSource(new MutableTreeModel(treeNodeLoaderStateProps.seedTreeModel)), dataProvider: provider, }); return () => { provider[Symbol.dispose](); }; }, [treeNodeLoaderStateProps]); const nodeLoader = usePagedTreeNodeLoader(dataProvider, rest.pagingSize, modelSource); const renderedItems = useRef(undefined); /* c8 ignore next 3 */ const onItemsRendered = useCallback((items) => { renderedItems.current = items; }, []); const params = { pageSize: rest.pagingSize, modelSource, dataProviderProps: treeNodeLoaderStateProps, rulesetId: dataProvider.rulesetId, setTreeNodeLoaderState: setState, renderedItems, }; useModelSourceUpdateOnIModelHierarchyUpdate(params); useModelSourceUpdateOnRulesetModification(params); useModelSourceUpdateOnRulesetVariablesChange(params); useModelSourceUpdateOnUnitSystemChange(params); firstRenderRef.current = false; return { nodeLoader, onItemsRendered }; } /** * A custom hook that creates filtered model source and node loader for supplied filter. * If filter string is not provided or filtering is still in progress it returns supplied * model source and node loader. * * @public * @deprecated in 5.7. All tree-related APIs have been deprecated in favor of the new generation hierarchy * building APIs (see https://github.com/iTwin/presentation/blob/33e79ee8d77f30580a9bab81a72884bda008db25/README.md#the-packages). */ export function useControlledPresentationTreeFiltering(props) { const { filteredNodeLoader, filteredProvider, isFiltering, matchesCount } = useFilteredNodeLoader({ dataProvider: props.nodeLoader.dataProvider, filter: props.filter, }); const nodeHighlightingProps = useNodeHighlightingProps(props.filter, filteredProvider, props.activeMatchIndex); return { nodeHighlightingProps, filteredNodeLoader: filteredNodeLoader || props.nodeLoader, filteredModelSource: filteredNodeLoader?.modelSource || props.nodeLoader.modelSource, isFiltering, matchesCount, }; } function useModelSourceUpdateOnIModelHierarchyUpdate(params) { const { dataProviderProps, rulesetId, pageSize, modelSource, setTreeNodeLoaderState, renderedItems } = params; useEffect(() => { let subscription; const removeListener = Presentation.presentation.onIModelHierarchyChanged.addListener((args) => { if (args.rulesetId !== rulesetId || args.imodelKey !== dataProviderProps.imodel.key) { return; } subscription = startTreeReload({ dataProviderProps, rulesetId, pageSize, modelSource, renderedItems, setTreeNodeLoaderState }); }); return () => { removeListener(); subscription?.unsubscribe(); }; }, [modelSource, pageSize, dataProviderProps, rulesetId, setTreeNodeLoaderState, renderedItems]); } function useModelSourceUpdateOnRulesetModification(params) { const { dataProviderProps, rulesetId, pageSize, modelSource, setTreeNodeLoaderState, renderedItems } = params; useEffect(() => { let subscription; const removeListener = Presentation.presentation.rulesets().onRulesetModified.addListener((ruleset) => { if (ruleset.id !== rulesetId) { return; } subscription = startTreeReload({ dataProviderProps, rulesetId, pageSize, modelSource, renderedItems, setTreeNodeLoaderState }); }); return () => { removeListener(); subscription?.unsubscribe(); }; }, [dataProviderProps, rulesetId, modelSource, pageSize, setTreeNodeLoaderState, renderedItems]); } function useModelSourceUpdateOnRulesetVariablesChange(params) { const { dataProviderProps, pageSize, rulesetId, modelSource, setTreeNodeLoaderState, renderedItems } = params; useEffect(() => { let subscription; const removeListener = Presentation.presentation.vars(rulesetId).onVariableChanged.addListener(() => { // note: we should probably debounce these events while accumulating changed variables in case multiple vars are changed subscription = startTreeReload({ dataProviderProps, rulesetId, pageSize, modelSource, renderedItems, setTreeNodeLoaderState }); }); return () => { removeListener(); subscription?.unsubscribe(); }; }, [dataProviderProps, modelSource, pageSize, rulesetId, setTreeNodeLoaderState, renderedItems]); } function useModelSourceUpdateOnUnitSystemChange(params) { const { dataProviderProps, pageSize, rulesetId, modelSource, setTreeNodeLoaderState, renderedItems } = params; useEffect(() => { let subscription; const removeListener = IModelApp.quantityFormatter.onActiveFormattingUnitSystemChanged.addListener(() => { subscription = startTreeReload({ dataProviderProps, rulesetId, pageSize, modelSource, renderedItems, setTreeNodeLoaderState }); }); return () => { removeListener(); subscription?.unsubscribe(); }; }, [dataProviderProps, modelSource, pageSize, rulesetId, setTreeNodeLoaderState, renderedItems]); } function startTreeReload({ dataProviderProps, rulesetId, modelSource, pageSize, renderedItems, setTreeNodeLoaderState }) { const dataProvider = new PresentationTreeDataProvider({ ...dataProviderProps, ruleset: rulesetId }); return reloadTree(modelSource.getModel(), dataProvider, pageSize, renderedItems.current).subscribe({ next: (newModelSource) => setTreeNodeLoaderState({ modelSource: newModelSource, dataProvider, }), }); } //# sourceMappingURL=TreeHooks.js.map