UNPKG

@itwin/presentation-components

Version:

React components based on iTwin.js Presentation library

207 lines 9.88 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * 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.UnifiedSelectionTreeEventHandler = void 0; exports.useUnifiedSelectionTreeEventHandler = useUnifiedSelectionTreeEventHandler; require("../../common/DisposePolyfill.js"); const react_1 = require("react"); const rxjs_1 = require("rxjs"); const components_react_1 = require("@itwin/components-react"); const core_bentley_1 = require("@itwin/core-bentley"); const core_react_1 = require("@itwin/core-react"); const presentation_common_1 = require("@itwin/presentation-common"); const presentation_frontend_1 = require("@itwin/presentation-frontend"); const PresentationTreeNodeItem_js_1 = require("../PresentationTreeNodeItem.js"); const Utils_js_1 = require("../Utils.js"); /** * Tree event handler that handles unified selection. * Extends wrapped tree event handler's functionality by adding, removing or replacing nodes in * unified selection. It also reacts to unified selection changes and selects/deselects tree nodes * according changes. * * **Note:** conditions used to determine if node is selected and nodes that should be added to * unified selection can be controlled by overriding 'shouldSelectNode' and 'createKeysForSelection' methods. * * @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). */ class UnifiedSelectionTreeEventHandler extends components_react_1.TreeEventHandler { #dataProvider; #selectionSourceName; #listeners = []; #cancelled = new rxjs_1.Subject(); constructor(params) { super({ ...params, modelSource: params.nodeLoader.modelSource, }); this.#dataProvider = params.nodeLoader.dataProvider; this.#selectionSourceName = params.name ?? `Tree_${this.#dataProvider.rulesetId}_${core_bentley_1.Guid.createValue()}`; this.#listeners.push(presentation_frontend_1.Presentation.selection.selectionChange.addListener((args) => this.onSelectionChanged(args))); this.#listeners.push(this.modelSource.onModelChanged.addListener((args) => this.selectNodes(args[1]))); this.selectNodes(); } #dispose() { super.dispose(); this.#cancelled.next(); this.#listeners.forEach((unregister) => unregister()); } /** Disposes this event handler */ [Symbol.dispose]() { this.#dispose(); } /** @deprecated in 5.7. Use `[Symbol.dispose]` instead. */ dispose() { this.#dispose(); } onSelectionModified({ modifications }) { const withUnifiedSelection = (0, Utils_js_1.toRxjsObservable)(modifications).pipe((0, rxjs_1.takeUntil)(this.#cancelled), (0, rxjs_1.tap)({ next: ({ selectedNodeItems, deselectedNodeItems }) => { if (selectedNodeItems.length !== 0) { this.addToSelection(selectedNodeItems); } if (deselectedNodeItems.length !== 0) { this.removeFromSelection(deselectedNodeItems); } }, })); return super.onSelectionModified({ modifications: withUnifiedSelection }); } onSelectionReplaced({ replacements }) { this.#cancelled.next(); let firstEmission = true; const withUnifiedSelection = (0, Utils_js_1.toRxjsObservable)(replacements).pipe((0, rxjs_1.takeUntil)(this.#cancelled), (0, rxjs_1.tap)({ next: ({ selectedNodeItems }) => { if (selectedNodeItems.length === 0) { return; } if (firstEmission) { firstEmission = false; this.replaceSelection(selectedNodeItems); return; } this.addToSelection(selectedNodeItems); }, })); return super.onSelectionReplaced({ replacements: withUnifiedSelection }); } selectNodes(modelChange) { // when handling model change event only need to update newly added nodes if (modelChange) { this.updateAffectedNodes(modelChange); } else { this.updateAllNodes(); } } /** @deprecated in 4.0. Use [[isPresentationTreeNodeItem]] and [[PresentationTreeNodeItem.key]] to get [NodeKey]($presentation-common). */ /* c8 ignore start */ getNodeKey(node) { return this.#dataProvider.getNodeKey(node); } /* c8 ignore end */ /** * Determines if node should be selected. * Default implementation returns true if node key is in selection * or node is ECInstance node and instance key is in selection. */ shouldSelectNode(node, selection) { /* c8 ignore next 3 */ if (!(0, PresentationTreeNodeItem_js_1.isPresentationTreeNodeItem)(node)) { return false; } // consider node selected if it's key is in selection if (selection.has(node.key)) { return true; } // ... or if it's an ECInstances node and any of instance keys is in selection if (presentation_common_1.NodeKey.isInstancesNodeKey(node.key) && node.key.instanceKeys.some((instanceKey) => selection.has(instanceKey))) { return true; } return false; } /** * Returns node keys that should be added, removed or used to replace unified selection. * Default implementation returns keys of supplied nodes. */ createKeysForSelection(nodes, _selectionType) { return this.getKeys(nodes); } getKeys(nodes) { const nodeKeys = nodes .map((node) => ((0, PresentationTreeNodeItem_js_1.isPresentationTreeNodeItem)(node) ? node.key : /* c8 ignore next */ undefined)) .filter((key) => key !== undefined); return presentation_frontend_1.SelectionHelper.getKeysForSelection(nodeKeys); } addToSelection(nodes) { presentation_frontend_1.Presentation.selection.addToSelection(this.#selectionSourceName, this.#dataProvider.imodel, this.createKeysForSelection(nodes, presentation_frontend_1.SelectionChangeType.Add), 0, this.#dataProvider.rulesetId); } removeFromSelection(nodes) { presentation_frontend_1.Presentation.selection.removeFromSelection(this.#selectionSourceName, this.#dataProvider.imodel, this.createKeysForSelection(nodes, presentation_frontend_1.SelectionChangeType.Remove), 0, this.#dataProvider.rulesetId); } replaceSelection(nodes) { presentation_frontend_1.Presentation.selection.replaceSelection(this.#selectionSourceName, this.#dataProvider.imodel, this.createKeysForSelection(nodes, presentation_frontend_1.SelectionChangeType.Replace), 0, this.#dataProvider.rulesetId); } onSelectionChanged(evt) { if (evt.imodel !== this.#dataProvider.imodel) { return; } if (evt.source !== this.#selectionSourceName && (evt.changeType === presentation_frontend_1.SelectionChangeType.Clear || evt.changeType === presentation_frontend_1.SelectionChangeType.Replace)) { this.#cancelled.next(); } this.selectNodes(); } updateAllNodes() { const selection = presentation_frontend_1.Presentation.selection.getSelection(this.#dataProvider.imodel); this.modelSource.modifyModel((model) => { for (const node of model.iterateTreeModelNodes()) { this.updateNodeSelectionState(node, selection); } }); } updateAffectedNodes(modelChange) { const affectedNodeIds = [...modelChange.addedNodeIds, ...modelChange.modifiedNodeIds]; if (affectedNodeIds.length === 0) { return; } const selection = presentation_frontend_1.Presentation.selection.getSelection(this.#dataProvider.imodel); this.modelSource.modifyModel((model) => { for (const nodeId of affectedNodeIds) { const node = model.getNode(nodeId); /* c8 ignore next 3 */ if (!node) { continue; } this.updateNodeSelectionState(node, selection); } }); } updateNodeSelectionState(node, selection) { const shouldBeSelected = this.shouldSelectNode(node.item, selection); if (!node.isSelected && shouldBeSelected) { node.isSelected = true; } else if (node.isSelected && !shouldBeSelected) { node.isSelected = false; } } } exports.UnifiedSelectionTreeEventHandler = UnifiedSelectionTreeEventHandler; /** * A custom hook which creates and disposes [[UnifiedSelectionTreeEventHandler]] * @public * @deprecated in 4.x. This hook is not compatible with React 18 `StrictMode`. Use [[usePresentationTreeState]] and * [[UsePresentationTreeProps.eventHandlerFactory]] instead or manually create and dispose [[UnifiedSelectionTreeEventHandler]]. */ function useUnifiedSelectionTreeEventHandler(props) { return (0, core_react_1.useDisposable)((0, react_1.useCallback)(() => new UnifiedSelectionTreeEventHandler(props), Object.values(props) /* eslint-disable-line react-hooks/exhaustive-deps */ /* want to re-create the handler whenever any prop changes */)); } //# sourceMappingURL=UseUnifiedSelection.js.map