@itwin/presentation-components
Version:
React components based on iTwin.js Presentation library
153 lines • 7.8 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* 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