@itwin/presentation-components
Version:
React components based on iTwin.js Presentation library
136 lines • 6.61 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
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.usePresentationTreeState = usePresentationTreeState;
require("../../common/DisposePolyfill.js");
const react_1 = require("react");
const components_react_1 = require("@itwin/components-react");
const DataProvider_js_1 = require("../DataProvider.js");
const ReportingTreeNodeLoader_js_1 = require("../ReportingTreeNodeLoader.js");
const UseControlledTreeFiltering_js_1 = require("./UseControlledTreeFiltering.js");
const UseTreeReload_js_1 = require("./UseTreeReload.js");
/**
* Custom hook that creates and manages state for [ControlledTree]($components-react) component based on presentation data.
* @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).
*/
function usePresentationTreeState({ onHierarchyLimitExceeded, onNodeLoaded, eventHandlerFactory, seedTreeModel, filteringParams, ...dataProviderProps }) {
const firstRenderRef = (0, react_1.useRef)(true);
const treeStateProps = (0, react_1.useMemo)(() => ({
...dataProviderProps,
treeModel: firstRenderRef.current ? seedTreeModel : undefined,
}), Object.values(dataProviderProps));
const { state, onReload } = useTreeState({ treeStateProps, onNodeLoaded, onHierarchyLimitExceeded });
const renderedItems = (0, react_1.useRef)(undefined);
/* c8 ignore next 3 */
const onItemsRendered = (0, react_1.useCallback)((items) => {
renderedItems.current = items;
}, []);
(0, UseTreeReload_js_1.useTreeReload)({
pageSize: dataProviderProps.pagingSize,
modelSource: state?.nodeLoader.modelSource,
dataProviderProps: treeStateProps,
ruleset: dataProviderProps.ruleset,
onReload,
renderedItems,
});
const filteredTree = usePresentationTreeFiltering({
dataProvider: state?.nodeLoader.dataProvider,
filter: filteringParams?.filter,
activeMatchIndex: filteringParams?.activeMatchIndex,
});
const activeNodeLoader = filteredTree?.filteredNodeLoader ?? state?.nodeLoader;
const eventHandler = useEventHandler(eventHandlerFactory, activeNodeLoader);
firstRenderRef.current = false;
if (!activeNodeLoader || !eventHandler) {
return undefined;
}
return {
nodeLoader: activeNodeLoader,
eventHandler,
onItemsRendered,
filteringResult: filteredTree
? {
isFiltering: filteredTree.isFiltering,
filteredProvider: filteredTree.filteredProvider,
highlightProps: filteredTree.highlightProps,
matchesCount: filteredTree.matchesCount,
}
: undefined,
};
}
function useTreeState(props) {
const [state, setState] = (0, react_1.useState)();
const onNodeLoadedRef = useLatest(props.onNodeLoaded);
const onHierarchyLimitExceededRef = useLatest(props.onHierarchyLimitExceeded);
const prevStateRef = useLatest(state);
(0, react_1.useEffect)(() => {
const { treeModel, ...providerProps } = props.treeStateProps;
const modelSource = new components_react_1.TreeModelSource(new components_react_1.MutableTreeModel(treeModel));
const dataProvider = new DataProvider_js_1.PresentationTreeDataProvider({ ...providerProps, onHierarchyLimitExceeded: () => onHierarchyLimitExceededRef.current?.() });
const pagedLoader = new components_react_1.PagedTreeNodeLoader(dataProvider, modelSource, providerProps.pagingSize);
const nodeLoader = new ReportingTreeNodeLoader_js_1.ReportingTreeNodeLoader(pagedLoader, (nodeLoadedProps) => onNodeLoadedRef.current?.(nodeLoadedProps));
const newState = {
modelSource,
nodeLoader,
dataProvider,
};
setState(newState);
return () => {
// eslint-disable-next-line react-hooks/exhaustive-deps
prevStateRef.current?.dataProvider[Symbol.dispose]();
};
}, [props.treeStateProps, onNodeLoadedRef, onHierarchyLimitExceededRef, prevStateRef]);
const onReload = (0, react_1.useCallback)((reloadedTree) => {
prevStateRef.current?.dataProvider[Symbol.dispose]();
const { modelSource, dataProvider } = reloadedTree;
const pagedLoader = new components_react_1.PagedTreeNodeLoader(dataProvider, modelSource, dataProvider.pagingSize);
const nodeLoader = new ReportingTreeNodeLoader_js_1.ReportingTreeNodeLoader(pagedLoader, (nodeLoadedProps) => onNodeLoadedRef.current?.(nodeLoadedProps));
setState({ dataProvider, nodeLoader });
}, [onNodeLoadedRef, prevStateRef]);
return { state, onReload };
}
function useEventHandler(factory, nodeLoader) {
const [state, setState] = (0, react_1.useState)();
(0, react_1.useEffect)(() => {
if (!nodeLoader) {
return;
}
const params = { modelSource: nodeLoader.modelSource, nodeLoader };
const newHandler = factory ? factory(params) : new components_react_1.TreeEventHandler(params);
setState(newHandler);
return () => {
newHandler?.dispose();
};
}, [factory, nodeLoader]);
return state;
}
function usePresentationTreeFiltering({ activeMatchIndex, ...rest }) {
const { filteredNodeLoader, filteredProvider, isFiltering, matchesCount } = (0, UseControlledTreeFiltering_js_1.useFilteredNodeLoader)(rest);
const highlightProps = (0, UseControlledTreeFiltering_js_1.useNodeHighlightingProps)(rest.filter, filteredProvider, activeMatchIndex);
return rest.filter && rest.dataProvider
? {
highlightProps,
filteredNodeLoader,
filteredProvider,
isFiltering,
matchesCount,
}
: undefined;
}
function useLatest(value) {
const ref = (0, react_1.useRef)(value);
(0, react_1.useEffect)(() => {
ref.current = value;
}, [value]);
return ref;
}
//# sourceMappingURL=UsePresentationTreeState.js.map