1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795 |
- import { S as SelectionModel } from './selection-model-CeeHVIcP.mjs';
- import { isObservable, Subject, BehaviorSubject, of, combineLatest, EMPTY, concat } from 'rxjs';
- import { take, filter, takeUntil, startWith, tap, switchMap, map, reduce, concatMap, distinctUntilChanged } from 'rxjs/operators';
- import * as i0 from '@angular/core';
- import { InjectionToken, inject, ViewContainerRef, Directive, TemplateRef, IterableDiffers, ChangeDetectorRef, ElementRef, Component, ViewEncapsulation, ChangeDetectionStrategy, Input, ViewChild, ContentChildren, EventEmitter, booleanAttribute, Output, numberAttribute, NgModule } from '@angular/core';
- import { T as TREE_KEY_MANAGER } from './tree-key-manager-KnCoIkIC.mjs';
- import { D as Directionality } from './directionality-CBXD4hga.mjs';
- import { i as isDataSource } from './data-source-D34wiQZj.mjs';
- import { coerceObservable } from './coercion/private.mjs';
- import './typeahead-9ZW4Dtsf.mjs';
- import './keycodes-CpHkExLC.mjs';
- import '@angular/common';
- /**
- * Base tree control. It has basic toggle/expand/collapse operations on a single data node.
- *
- * @deprecated Use one of levelAccessor or childrenAccessor. To be removed in a future version.
- * @breaking-change 21.0.0
- */
- class BaseTreeControl {
- /** Saved data node for `expandAll` action. */
- dataNodes;
- /** A selection model with multi-selection to track expansion status. */
- expansionModel = new SelectionModel(true);
- /**
- * Returns the identifier by which a dataNode should be tracked, should its
- * reference change.
- *
- * Similar to trackBy for *ngFor
- */
- trackBy;
- /** Get depth of a given data node, return the level number. This is for flat tree node. */
- getLevel;
- /**
- * Whether the data node is expandable. Returns true if expandable.
- * This is for flat tree node.
- */
- isExpandable;
- /** Gets a stream that emits whenever the given data node's children change. */
- getChildren;
- /** Toggles one single data node's expanded/collapsed state. */
- toggle(dataNode) {
- this.expansionModel.toggle(this._trackByValue(dataNode));
- }
- /** Expands one single data node. */
- expand(dataNode) {
- this.expansionModel.select(this._trackByValue(dataNode));
- }
- /** Collapses one single data node. */
- collapse(dataNode) {
- this.expansionModel.deselect(this._trackByValue(dataNode));
- }
- /** Whether a given data node is expanded or not. Returns true if the data node is expanded. */
- isExpanded(dataNode) {
- return this.expansionModel.isSelected(this._trackByValue(dataNode));
- }
- /** Toggles a subtree rooted at `node` recursively. */
- toggleDescendants(dataNode) {
- this.expansionModel.isSelected(this._trackByValue(dataNode))
- ? this.collapseDescendants(dataNode)
- : this.expandDescendants(dataNode);
- }
- /** Collapse all dataNodes in the tree. */
- collapseAll() {
- this.expansionModel.clear();
- }
- /** Expands a subtree rooted at given data node recursively. */
- expandDescendants(dataNode) {
- let toBeProcessed = [dataNode];
- toBeProcessed.push(...this.getDescendants(dataNode));
- this.expansionModel.select(...toBeProcessed.map(value => this._trackByValue(value)));
- }
- /** Collapses a subtree rooted at given data node recursively. */
- collapseDescendants(dataNode) {
- let toBeProcessed = [dataNode];
- toBeProcessed.push(...this.getDescendants(dataNode));
- this.expansionModel.deselect(...toBeProcessed.map(value => this._trackByValue(value)));
- }
- _trackByValue(value) {
- return this.trackBy ? this.trackBy(value) : value;
- }
- }
- /**
- * Flat tree control. Able to expand/collapse a subtree recursively for flattened tree.
- *
- * @deprecated Use one of levelAccessor or childrenAccessor instead. To be removed in a future
- * version.
- * @breaking-change 21.0.0
- */
- class FlatTreeControl extends BaseTreeControl {
- getLevel;
- isExpandable;
- options;
- /** Construct with flat tree data node functions getLevel and isExpandable. */
- constructor(getLevel, isExpandable, options) {
- super();
- this.getLevel = getLevel;
- this.isExpandable = isExpandable;
- this.options = options;
- if (this.options) {
- this.trackBy = this.options.trackBy;
- }
- }
- /**
- * Gets a list of the data node's subtree of descendent data nodes.
- *
- * To make this working, the `dataNodes` of the TreeControl must be flattened tree nodes
- * with correct levels.
- */
- getDescendants(dataNode) {
- const startIndex = this.dataNodes.indexOf(dataNode);
- const results = [];
- // Goes through flattened tree nodes in the `dataNodes` array, and get all descendants.
- // The level of descendants of a tree node must be greater than the level of the given
- // tree node.
- // If we reach a node whose level is equal to the level of the tree node, we hit a sibling.
- // If we reach a node whose level is greater than the level of the tree node, we hit a
- // sibling of an ancestor.
- for (let i = startIndex + 1; i < this.dataNodes.length && this.getLevel(dataNode) < this.getLevel(this.dataNodes[i]); i++) {
- results.push(this.dataNodes[i]);
- }
- return results;
- }
- /**
- * Expands all data nodes in the tree.
- *
- * To make this working, the `dataNodes` variable of the TreeControl must be set to all flattened
- * data nodes of the tree.
- */
- expandAll() {
- this.expansionModel.select(...this.dataNodes.map(node => this._trackByValue(node)));
- }
- }
- /**
- * Nested tree control. Able to expand/collapse a subtree recursively for NestedNode type.
- *
- * @deprecated Use one of levelAccessor or childrenAccessor instead. To be removed in a future
- * version.
- * @breaking-change 21.0.0
- */
- class NestedTreeControl extends BaseTreeControl {
- getChildren;
- options;
- /** Construct with nested tree function getChildren. */
- constructor(getChildren, options) {
- super();
- this.getChildren = getChildren;
- this.options = options;
- if (this.options) {
- this.trackBy = this.options.trackBy;
- }
- if (this.options?.isExpandable) {
- this.isExpandable = this.options.isExpandable;
- }
- }
- /**
- * Expands all dataNodes in the tree.
- *
- * To make this working, the `dataNodes` variable of the TreeControl must be set to all root level
- * data nodes of the tree.
- */
- expandAll() {
- this.expansionModel.clear();
- const allNodes = this.dataNodes.reduce((accumulator, dataNode) => [...accumulator, ...this.getDescendants(dataNode), dataNode], []);
- this.expansionModel.select(...allNodes.map(node => this._trackByValue(node)));
- }
- /** Gets a list of descendant dataNodes of a subtree rooted at given data node recursively. */
- getDescendants(dataNode) {
- const descendants = [];
- this._getDescendants(descendants, dataNode);
- // Remove the node itself
- return descendants.splice(1);
- }
- /** A helper function to get descendants recursively. */
- _getDescendants(descendants, dataNode) {
- descendants.push(dataNode);
- const childrenNodes = this.getChildren(dataNode);
- if (Array.isArray(childrenNodes)) {
- childrenNodes.forEach((child) => this._getDescendants(descendants, child));
- }
- else if (isObservable(childrenNodes)) {
- // TypeScript as of version 3.5 doesn't seem to treat `Boolean` like a function that
- // returns a `boolean` specifically in the context of `filter`, so we manually clarify that.
- childrenNodes.pipe(take(1), filter(Boolean)).subscribe(children => {
- for (const child of children) {
- this._getDescendants(descendants, child);
- }
- });
- }
- }
- }
- /**
- * Injection token used to provide a `CdkTreeNode` to its outlet.
- * Used primarily to avoid circular imports.
- * @docs-private
- */
- const CDK_TREE_NODE_OUTLET_NODE = new InjectionToken('CDK_TREE_NODE_OUTLET_NODE');
- /**
- * Outlet for nested CdkNode. Put `[cdkTreeNodeOutlet]` on a tag to place children dataNodes
- * inside the outlet.
- */
- class CdkTreeNodeOutlet {
- viewContainer = inject(ViewContainerRef);
- _node = inject(CDK_TREE_NODE_OUTLET_NODE, { optional: true });
- constructor() { }
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CdkTreeNodeOutlet, deps: [], target: i0.ɵɵFactoryTarget.Directive });
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.6", type: CdkTreeNodeOutlet, isStandalone: true, selector: "[cdkTreeNodeOutlet]", ngImport: i0 });
- }
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CdkTreeNodeOutlet, decorators: [{
- type: Directive,
- args: [{
- selector: '[cdkTreeNodeOutlet]',
- }]
- }], ctorParameters: () => [] });
- /** Context provided to the tree node component. */
- class CdkTreeNodeOutletContext {
- /** Data for the node. */
- $implicit;
- /** Depth of the node. */
- level;
- /** Index location of the node. */
- index;
- /** Length of the number of total dataNodes. */
- count;
- constructor(data) {
- this.$implicit = data;
- }
- }
- /**
- * Data node definition for the CdkTree.
- * Captures the node's template and a when predicate that describes when this node should be used.
- */
- class CdkTreeNodeDef {
- /** @docs-private */
- template = inject(TemplateRef);
- /**
- * Function that should return true if this node template should be used for the provided node
- * data and index. If left undefined, this node will be considered the default node template to
- * use when no other when functions return true for the data.
- * For every node, there must be at least one when function that passes or an undefined to
- * default.
- */
- when;
- constructor() { }
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CdkTreeNodeDef, deps: [], target: i0.ɵɵFactoryTarget.Directive });
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.6", type: CdkTreeNodeDef, isStandalone: true, selector: "[cdkTreeNodeDef]", inputs: { when: ["cdkTreeNodeDefWhen", "when"] }, ngImport: i0 });
- }
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CdkTreeNodeDef, decorators: [{
- type: Directive,
- args: [{
- selector: '[cdkTreeNodeDef]',
- inputs: [{ name: 'when', alias: 'cdkTreeNodeDefWhen' }],
- }]
- }], ctorParameters: () => [] });
- /**
- * Returns an error to be thrown when there is no usable data.
- * @docs-private
- */
- function getTreeNoValidDataSourceError() {
- return Error(`A valid data source must be provided.`);
- }
- /**
- * Returns an error to be thrown when there are multiple nodes that are missing a when function.
- * @docs-private
- */
- function getTreeMultipleDefaultNodeDefsError() {
- return Error(`There can only be one default row without a when predicate function.`);
- }
- /**
- * Returns an error to be thrown when there are no matching node defs for a particular set of data.
- * @docs-private
- */
- function getTreeMissingMatchingNodeDefError() {
- return Error(`Could not find a matching node definition for the provided node data.`);
- }
- /**
- * Returns an error to be thrown when there is no tree control.
- * @docs-private
- */
- function getTreeControlMissingError() {
- return Error(`Could not find a tree control, levelAccessor, or childrenAccessor for the tree.`);
- }
- /**
- * Returns an error to be thrown when there are multiple ways of specifying children or level
- * provided to the tree.
- * @docs-private
- */
- function getMultipleTreeControlsError() {
- return Error(`More than one of tree control, levelAccessor, or childrenAccessor were provided.`);
- }
- /**
- * CDK tree component that connects with a data source to retrieve data of type `T` and renders
- * dataNodes with hierarchy. Updates the dataNodes when new data is provided by the data source.
- */
- class CdkTree {
- _differs = inject(IterableDiffers);
- _changeDetectorRef = inject(ChangeDetectorRef);
- _elementRef = inject(ElementRef);
- _dir = inject(Directionality);
- /** Subject that emits when the component has been destroyed. */
- _onDestroy = new Subject();
- /** Differ used to find the changes in the data provided by the data source. */
- _dataDiffer;
- /** Stores the node definition that does not have a when predicate. */
- _defaultNodeDef;
- /** Data subscription */
- _dataSubscription;
- /** Level of nodes */
- _levels = new Map();
- /** The immediate parents for a node. This is `null` if there is no parent. */
- _parents = new Map();
- /**
- * Nodes grouped into each set, which is a list of nodes displayed together in the DOM.
- *
- * Lookup key is the parent of a set. Root nodes have key of null.
- *
- * Values is a 'set' of tree nodes. Each tree node maps to a treeitem element. Sets are in the
- * order that it is rendered. Each set maps directly to aria-posinset and aria-setsize attributes.
- */
- _ariaSets = new Map();
- /**
- * Provides a stream containing the latest data array to render. Influenced by the tree's
- * stream of view window (what dataNodes are currently on screen).
- * Data source can be an observable of data array, or a data array to render.
- */
- get dataSource() {
- return this._dataSource;
- }
- set dataSource(dataSource) {
- if (this._dataSource !== dataSource) {
- this._switchDataSource(dataSource);
- }
- }
- _dataSource;
- /**
- * The tree controller
- *
- * @deprecated Use one of `levelAccessor` or `childrenAccessor` instead. To be removed in a
- * future version.
- * @breaking-change 21.0.0
- */
- treeControl;
- /**
- * Given a data node, determines what tree level the node is at.
- *
- * One of levelAccessor or childrenAccessor must be specified, not both.
- * This is enforced at run-time.
- */
- levelAccessor;
- /**
- * Given a data node, determines what the children of that node are.
- *
- * One of levelAccessor or childrenAccessor must be specified, not both.
- * This is enforced at run-time.
- */
- childrenAccessor;
- /**
- * Tracking function that will be used to check the differences in data changes. Used similarly
- * to `ngFor` `trackBy` function. Optimize node operations by identifying a node based on its data
- * relative to the function to know if a node should be added/removed/moved.
- * Accepts a function that takes two parameters, `index` and `item`.
- */
- trackBy;
- /**
- * Given a data node, determines the key by which we determine whether or not this node is expanded.
- */
- expansionKey;
- // Outlets within the tree's template where the dataNodes will be inserted.
- _nodeOutlet;
- /** The tree node template for the tree */
- _nodeDefs;
- // TODO(tinayuangao): Setup a listener for scrolling, emit the calculated view to viewChange.
- // Remove the MAX_VALUE in viewChange
- /**
- * Stream containing the latest information on what rows are being displayed on screen.
- * Can be used by the data source to as a heuristic of what data should be provided.
- */
- viewChange = new BehaviorSubject({
- start: 0,
- end: Number.MAX_VALUE,
- });
- /** Keep track of which nodes are expanded. */
- _expansionModel;
- /**
- * Maintain a synchronous cache of flattened data nodes. This will only be
- * populated after initial render, and in certain cases, will be delayed due to
- * relying on Observable `getChildren` calls.
- */
- _flattenedNodes = new BehaviorSubject([]);
- /** The automatically determined node type for the tree. */
- _nodeType = new BehaviorSubject(null);
- /** The mapping between data and the node that is rendered. */
- _nodes = new BehaviorSubject(new Map());
- /**
- * Synchronous cache of nodes for the `TreeKeyManager`. This is separate
- * from `_flattenedNodes` so they can be independently updated at different
- * times.
- */
- _keyManagerNodes = new BehaviorSubject([]);
- _keyManagerFactory = inject(TREE_KEY_MANAGER);
- /** The key manager for this tree. Handles focus and activation based on user keyboard input. */
- _keyManager;
- _viewInit = false;
- constructor() { }
- ngAfterContentInit() {
- this._initializeKeyManager();
- }
- ngAfterContentChecked() {
- this._updateDefaultNodeDefinition();
- this._subscribeToDataChanges();
- }
- ngOnDestroy() {
- this._nodeOutlet.viewContainer.clear();
- this.viewChange.complete();
- this._onDestroy.next();
- this._onDestroy.complete();
- if (this._dataSource && typeof this._dataSource.disconnect === 'function') {
- this.dataSource.disconnect(this);
- }
- if (this._dataSubscription) {
- this._dataSubscription.unsubscribe();
- this._dataSubscription = null;
- }
- // In certain tests, the tree might be destroyed before this is initialized
- // in `ngAfterContentInit`.
- this._keyManager?.destroy();
- }
- ngOnInit() {
- this._checkTreeControlUsage();
- this._initializeDataDiffer();
- }
- ngAfterViewInit() {
- this._viewInit = true;
- }
- _updateDefaultNodeDefinition() {
- const defaultNodeDefs = this._nodeDefs.filter(def => !def.when);
- if (defaultNodeDefs.length > 1 && (typeof ngDevMode === 'undefined' || ngDevMode)) {
- throw getTreeMultipleDefaultNodeDefsError();
- }
- this._defaultNodeDef = defaultNodeDefs[0];
- }
- /**
- * Sets the node type for the tree, if it hasn't been set yet.
- *
- * This will be called by the first node that's rendered in order for the tree
- * to determine what data transformations are required.
- */
- _setNodeTypeIfUnset(newType) {
- const currentType = this._nodeType.value;
- if (currentType === null) {
- this._nodeType.next(newType);
- }
- else if ((typeof ngDevMode === 'undefined' || ngDevMode) && currentType !== newType) {
- console.warn(`Tree is using conflicting node types which can cause unexpected behavior. ` +
- `Please use tree nodes of the same type (e.g. only flat or only nested). ` +
- `Current node type: "${currentType}", new node type "${newType}".`);
- }
- }
- /**
- * Switch to the provided data source by resetting the data and unsubscribing from the current
- * render change subscription if one exists. If the data source is null, interpret this by
- * clearing the node outlet. Otherwise start listening for new data.
- */
- _switchDataSource(dataSource) {
- if (this._dataSource && typeof this._dataSource.disconnect === 'function') {
- this.dataSource.disconnect(this);
- }
- if (this._dataSubscription) {
- this._dataSubscription.unsubscribe();
- this._dataSubscription = null;
- }
- // Remove the all dataNodes if there is now no data source
- if (!dataSource) {
- this._nodeOutlet.viewContainer.clear();
- }
- this._dataSource = dataSource;
- if (this._nodeDefs) {
- this._subscribeToDataChanges();
- }
- }
- _getExpansionModel() {
- if (!this.treeControl) {
- this._expansionModel ??= new SelectionModel(true);
- return this._expansionModel;
- }
- return this.treeControl.expansionModel;
- }
- /** Set up a subscription for the data provided by the data source. */
- _subscribeToDataChanges() {
- if (this._dataSubscription) {
- return;
- }
- let dataStream;
- if (isDataSource(this._dataSource)) {
- dataStream = this._dataSource.connect(this);
- }
- else if (isObservable(this._dataSource)) {
- dataStream = this._dataSource;
- }
- else if (Array.isArray(this._dataSource)) {
- dataStream = of(this._dataSource);
- }
- if (!dataStream) {
- if (typeof ngDevMode === 'undefined' || ngDevMode) {
- throw getTreeNoValidDataSourceError();
- }
- return;
- }
- this._dataSubscription = this._getRenderData(dataStream)
- .pipe(takeUntil(this._onDestroy))
- .subscribe(renderingData => {
- this._renderDataChanges(renderingData);
- });
- }
- /** Given an Observable containing a stream of the raw data, returns an Observable containing the RenderingData */
- _getRenderData(dataStream) {
- const expansionModel = this._getExpansionModel();
- return combineLatest([
- dataStream,
- this._nodeType,
- // We don't use the expansion data directly, however we add it here to essentially
- // trigger data rendering when expansion changes occur.
- expansionModel.changed.pipe(startWith(null), tap(expansionChanges => {
- this._emitExpansionChanges(expansionChanges);
- })),
- ]).pipe(switchMap(([data, nodeType]) => {
- if (nodeType === null) {
- return of({ renderNodes: data, flattenedNodes: null, nodeType });
- }
- // If we're here, then we know what our node type is, and therefore can
- // perform our usual rendering pipeline, which necessitates converting the data
- return this._computeRenderingData(data, nodeType).pipe(map(convertedData => ({ ...convertedData, nodeType })));
- }));
- }
- _renderDataChanges(data) {
- if (data.nodeType === null) {
- this.renderNodeChanges(data.renderNodes);
- return;
- }
- // If we're here, then we know what our node type is, and therefore can
- // perform our usual rendering pipeline.
- this._updateCachedData(data.flattenedNodes);
- this.renderNodeChanges(data.renderNodes);
- this._updateKeyManagerItems(data.flattenedNodes);
- }
- _emitExpansionChanges(expansionChanges) {
- if (!expansionChanges) {
- return;
- }
- const nodes = this._nodes.value;
- for (const added of expansionChanges.added) {
- const node = nodes.get(added);
- node?._emitExpansionState(true);
- }
- for (const removed of expansionChanges.removed) {
- const node = nodes.get(removed);
- node?._emitExpansionState(false);
- }
- }
- _initializeKeyManager() {
- const items = combineLatest([this._keyManagerNodes, this._nodes]).pipe(map(([keyManagerNodes, renderNodes]) => keyManagerNodes.reduce((items, data) => {
- const node = renderNodes.get(this._getExpansionKey(data));
- if (node) {
- items.push(node);
- }
- return items;
- }, [])));
- const keyManagerOptions = {
- trackBy: node => this._getExpansionKey(node.data),
- skipPredicate: node => !!node.isDisabled,
- typeAheadDebounceInterval: true,
- horizontalOrientation: this._dir.value,
- };
- this._keyManager = this._keyManagerFactory(items, keyManagerOptions);
- }
- _initializeDataDiffer() {
- // Provide a default trackBy based on `_getExpansionKey` if one isn't provided.
- const trackBy = this.trackBy ?? ((_index, item) => this._getExpansionKey(item));
- this._dataDiffer = this._differs.find([]).create(trackBy);
- }
- _checkTreeControlUsage() {
- if (typeof ngDevMode === 'undefined' || ngDevMode) {
- // Verify that Tree follows API contract of using one of TreeControl, levelAccessor or
- // childrenAccessor. Throw an appropriate error if contract is not met.
- let numTreeControls = 0;
- if (this.treeControl) {
- numTreeControls++;
- }
- if (this.levelAccessor) {
- numTreeControls++;
- }
- if (this.childrenAccessor) {
- numTreeControls++;
- }
- if (!numTreeControls) {
- throw getTreeControlMissingError();
- }
- else if (numTreeControls > 1) {
- throw getMultipleTreeControlsError();
- }
- }
- }
- /** Check for changes made in the data and render each change (node added/removed/moved). */
- renderNodeChanges(data, dataDiffer = this._dataDiffer, viewContainer = this._nodeOutlet.viewContainer, parentData) {
- const changes = dataDiffer.diff(data);
- // Some tree consumers expect change detection to propagate to nodes
- // even when the array itself hasn't changed; we explicitly detect changes
- // anyways in order for nodes to update their data.
- //
- // However, if change detection is called while the component's view is
- // still initing, then the order of child views initing will be incorrect;
- // to prevent this, we only exit early if the view hasn't initialized yet.
- if (!changes && !this._viewInit) {
- return;
- }
- changes?.forEachOperation((item, adjustedPreviousIndex, currentIndex) => {
- if (item.previousIndex == null) {
- this.insertNode(data[currentIndex], currentIndex, viewContainer, parentData);
- }
- else if (currentIndex == null) {
- viewContainer.remove(adjustedPreviousIndex);
- }
- else {
- const view = viewContainer.get(adjustedPreviousIndex);
- viewContainer.move(view, currentIndex);
- }
- });
- // If the data itself changes, but keeps the same trackBy, we need to update the templates'
- // context to reflect the new object.
- changes?.forEachIdentityChange((record) => {
- const newData = record.item;
- if (record.currentIndex != undefined) {
- const view = viewContainer.get(record.currentIndex);
- view.context.$implicit = newData;
- }
- });
- // Note: we only `detectChanges` from a top-level call, otherwise we risk overflowing
- // the call stack since this method is called recursively (see #29733.)
- // TODO: change to `this._changeDetectorRef.markForCheck()`,
- // or just switch this component to use signals.
- if (parentData) {
- this._changeDetectorRef.markForCheck();
- }
- else {
- this._changeDetectorRef.detectChanges();
- }
- }
- /**
- * Finds the matching node definition that should be used for this node data. If there is only
- * one node definition, it is returned. Otherwise, find the node definition that has a when
- * predicate that returns true with the data. If none return true, return the default node
- * definition.
- */
- _getNodeDef(data, i) {
- if (this._nodeDefs.length === 1) {
- return this._nodeDefs.first;
- }
- const nodeDef = this._nodeDefs.find(def => def.when && def.when(i, data)) || this._defaultNodeDef;
- if (!nodeDef && (typeof ngDevMode === 'undefined' || ngDevMode)) {
- throw getTreeMissingMatchingNodeDefError();
- }
- return nodeDef;
- }
- /**
- * Create the embedded view for the data node template and place it in the correct index location
- * within the data node view container.
- */
- insertNode(nodeData, index, viewContainer, parentData) {
- const levelAccessor = this._getLevelAccessor();
- const node = this._getNodeDef(nodeData, index);
- const key = this._getExpansionKey(nodeData);
- // Node context that will be provided to created embedded view
- const context = new CdkTreeNodeOutletContext(nodeData);
- parentData ??= this._parents.get(key) ?? undefined;
- // If the tree is flat tree, then use the `getLevel` function in flat tree control
- // Otherwise, use the level of parent node.
- if (levelAccessor) {
- context.level = levelAccessor(nodeData);
- }
- else if (parentData !== undefined && this._levels.has(this._getExpansionKey(parentData))) {
- context.level = this._levels.get(this._getExpansionKey(parentData)) + 1;
- }
- else {
- context.level = 0;
- }
- this._levels.set(key, context.level);
- // Use default tree nodeOutlet, or nested node's nodeOutlet
- const container = viewContainer ? viewContainer : this._nodeOutlet.viewContainer;
- container.createEmbeddedView(node.template, context, index);
- // Set the data to just created `CdkTreeNode`.
- // The `CdkTreeNode` created from `createEmbeddedView` will be saved in static variable
- // `mostRecentTreeNode`. We get it from static variable and pass the node data to it.
- if (CdkTreeNode.mostRecentTreeNode) {
- CdkTreeNode.mostRecentTreeNode.data = nodeData;
- }
- }
- /** Whether the data node is expanded or collapsed. Returns true if it's expanded. */
- isExpanded(dataNode) {
- return !!(this.treeControl?.isExpanded(dataNode) ||
- this._expansionModel?.isSelected(this._getExpansionKey(dataNode)));
- }
- /** If the data node is currently expanded, collapse it. Otherwise, expand it. */
- toggle(dataNode) {
- if (this.treeControl) {
- this.treeControl.toggle(dataNode);
- }
- else if (this._expansionModel) {
- this._expansionModel.toggle(this._getExpansionKey(dataNode));
- }
- }
- /** Expand the data node. If it is already expanded, does nothing. */
- expand(dataNode) {
- if (this.treeControl) {
- this.treeControl.expand(dataNode);
- }
- else if (this._expansionModel) {
- this._expansionModel.select(this._getExpansionKey(dataNode));
- }
- }
- /** Collapse the data node. If it is already collapsed, does nothing. */
- collapse(dataNode) {
- if (this.treeControl) {
- this.treeControl.collapse(dataNode);
- }
- else if (this._expansionModel) {
- this._expansionModel.deselect(this._getExpansionKey(dataNode));
- }
- }
- /**
- * If the data node is currently expanded, collapse it and all its descendants.
- * Otherwise, expand it and all its descendants.
- */
- toggleDescendants(dataNode) {
- if (this.treeControl) {
- this.treeControl.toggleDescendants(dataNode);
- }
- else if (this._expansionModel) {
- if (this.isExpanded(dataNode)) {
- this.collapseDescendants(dataNode);
- }
- else {
- this.expandDescendants(dataNode);
- }
- }
- }
- /**
- * Expand the data node and all its descendants. If they are already expanded, does nothing.
- */
- expandDescendants(dataNode) {
- if (this.treeControl) {
- this.treeControl.expandDescendants(dataNode);
- }
- else if (this._expansionModel) {
- const expansionModel = this._expansionModel;
- expansionModel.select(this._getExpansionKey(dataNode));
- this._getDescendants(dataNode)
- .pipe(take(1), takeUntil(this._onDestroy))
- .subscribe(children => {
- expansionModel.select(...children.map(child => this._getExpansionKey(child)));
- });
- }
- }
- /** Collapse the data node and all its descendants. If it is already collapsed, does nothing. */
- collapseDescendants(dataNode) {
- if (this.treeControl) {
- this.treeControl.collapseDescendants(dataNode);
- }
- else if (this._expansionModel) {
- const expansionModel = this._expansionModel;
- expansionModel.deselect(this._getExpansionKey(dataNode));
- this._getDescendants(dataNode)
- .pipe(take(1), takeUntil(this._onDestroy))
- .subscribe(children => {
- expansionModel.deselect(...children.map(child => this._getExpansionKey(child)));
- });
- }
- }
- /** Expands all data nodes in the tree. */
- expandAll() {
- if (this.treeControl) {
- this.treeControl.expandAll();
- }
- else if (this._expansionModel) {
- this._forEachExpansionKey(keys => this._expansionModel?.select(...keys));
- }
- }
- /** Collapse all data nodes in the tree. */
- collapseAll() {
- if (this.treeControl) {
- this.treeControl.collapseAll();
- }
- else if (this._expansionModel) {
- this._forEachExpansionKey(keys => this._expansionModel?.deselect(...keys));
- }
- }
- /** Level accessor, used for compatibility between the old Tree and new Tree */
- _getLevelAccessor() {
- return this.treeControl?.getLevel?.bind(this.treeControl) ?? this.levelAccessor;
- }
- /** Children accessor, used for compatibility between the old Tree and new Tree */
- _getChildrenAccessor() {
- return this.treeControl?.getChildren?.bind(this.treeControl) ?? this.childrenAccessor;
- }
- /**
- * Gets the direct children of a node; used for compatibility between the old tree and the
- * new tree.
- */
- _getDirectChildren(dataNode) {
- const levelAccessor = this._getLevelAccessor();
- const expansionModel = this._expansionModel ?? this.treeControl?.expansionModel;
- if (!expansionModel) {
- return of([]);
- }
- const key = this._getExpansionKey(dataNode);
- const isExpanded = expansionModel.changed.pipe(switchMap(changes => {
- if (changes.added.includes(key)) {
- return of(true);
- }
- else if (changes.removed.includes(key)) {
- return of(false);
- }
- return EMPTY;
- }), startWith(this.isExpanded(dataNode)));
- if (levelAccessor) {
- return combineLatest([isExpanded, this._flattenedNodes]).pipe(map(([expanded, flattenedNodes]) => {
- if (!expanded) {
- return [];
- }
- return this._findChildrenByLevel(levelAccessor, flattenedNodes, dataNode, 1);
- }));
- }
- const childrenAccessor = this._getChildrenAccessor();
- if (childrenAccessor) {
- return coerceObservable(childrenAccessor(dataNode) ?? []);
- }
- throw getTreeControlMissingError();
- }
- /**
- * Given the list of flattened nodes, the level accessor, and the level range within
- * which to consider children, finds the children for a given node.
- *
- * For example, for direct children, `levelDelta` would be 1. For all descendants,
- * `levelDelta` would be Infinity.
- */
- _findChildrenByLevel(levelAccessor, flattenedNodes, dataNode, levelDelta) {
- const key = this._getExpansionKey(dataNode);
- const startIndex = flattenedNodes.findIndex(node => this._getExpansionKey(node) === key);
- const dataNodeLevel = levelAccessor(dataNode);
- const expectedLevel = dataNodeLevel + levelDelta;
- const results = [];
- // Goes through flattened tree nodes in the `flattenedNodes` array, and get all
- // descendants within a certain level range.
- //
- // If we reach a node whose level is equal to or less than the level of the tree node,
- // we hit a sibling or parent's sibling, and should stop.
- for (let i = startIndex + 1; i < flattenedNodes.length; i++) {
- const currentLevel = levelAccessor(flattenedNodes[i]);
- if (currentLevel <= dataNodeLevel) {
- break;
- }
- if (currentLevel <= expectedLevel) {
- results.push(flattenedNodes[i]);
- }
- }
- return results;
- }
- /**
- * Adds the specified node component to the tree's internal registry.
- *
- * This primarily facilitates keyboard navigation.
- */
- _registerNode(node) {
- this._nodes.value.set(this._getExpansionKey(node.data), node);
- this._nodes.next(this._nodes.value);
- }
- /** Removes the specified node component from the tree's internal registry. */
- _unregisterNode(node) {
- this._nodes.value.delete(this._getExpansionKey(node.data));
- this._nodes.next(this._nodes.value);
- }
- /**
- * For the given node, determine the level where this node appears in the tree.
- *
- * This is intended to be used for `aria-level` but is 0-indexed.
- */
- _getLevel(node) {
- return this._levels.get(this._getExpansionKey(node));
- }
- /**
- * For the given node, determine the size of the parent's child set.
- *
- * This is intended to be used for `aria-setsize`.
- */
- _getSetSize(dataNode) {
- const set = this._getAriaSet(dataNode);
- return set.length;
- }
- /**
- * For the given node, determine the index (starting from 1) of the node in its parent's child set.
- *
- * This is intended to be used for `aria-posinset`.
- */
- _getPositionInSet(dataNode) {
- const set = this._getAriaSet(dataNode);
- const key = this._getExpansionKey(dataNode);
- return set.findIndex(node => this._getExpansionKey(node) === key) + 1;
- }
- /** Given a CdkTreeNode, gets the node that renders that node's parent's data. */
- _getNodeParent(node) {
- const parent = this._parents.get(this._getExpansionKey(node.data));
- return parent && this._nodes.value.get(this._getExpansionKey(parent));
- }
- /** Given a CdkTreeNode, gets the nodes that renders that node's child data. */
- _getNodeChildren(node) {
- return this._getDirectChildren(node.data).pipe(map(children => children.reduce((nodes, child) => {
- const value = this._nodes.value.get(this._getExpansionKey(child));
- if (value) {
- nodes.push(value);
- }
- return nodes;
- }, [])));
- }
- /** `keydown` event handler; this just passes the event to the `TreeKeyManager`. */
- _sendKeydownToKeyManager(event) {
- // Only handle events directly on the tree or directly on one of the nodes, otherwise
- // we risk interfering with events in the projected content (see #29828).
- if (event.target === this._elementRef.nativeElement) {
- this._keyManager.onKeydown(event);
- }
- else {
- const nodes = this._nodes.getValue();
- for (const [, node] of nodes) {
- if (event.target === node._elementRef.nativeElement) {
- this._keyManager.onKeydown(event);
- break;
- }
- }
- }
- }
- /** Gets all nested descendants of a given node. */
- _getDescendants(dataNode) {
- if (this.treeControl) {
- return of(this.treeControl.getDescendants(dataNode));
- }
- if (this.levelAccessor) {
- const results = this._findChildrenByLevel(this.levelAccessor, this._flattenedNodes.value, dataNode, Infinity);
- return of(results);
- }
- if (this.childrenAccessor) {
- return this._getAllChildrenRecursively(dataNode).pipe(reduce((allChildren, nextChildren) => {
- allChildren.push(...nextChildren);
- return allChildren;
- }, []));
- }
- throw getTreeControlMissingError();
- }
- /**
- * Gets all children and sub-children of the provided node.
- *
- * This will emit multiple times, in the order that the children will appear
- * in the tree, and can be combined with a `reduce` operator.
- */
- _getAllChildrenRecursively(dataNode) {
- if (!this.childrenAccessor) {
- return of([]);
- }
- return coerceObservable(this.childrenAccessor(dataNode)).pipe(take(1), switchMap(children => {
- // Here, we cache the parents of a particular child so that we can compute the levels.
- for (const child of children) {
- this._parents.set(this._getExpansionKey(child), dataNode);
- }
- return of(...children).pipe(concatMap(child => concat(of([child]), this._getAllChildrenRecursively(child))));
- }));
- }
- _getExpansionKey(dataNode) {
- // In the case that a key accessor function was not provided by the
- // tree user, we'll default to using the node object itself as the key.
- //
- // This cast is safe since:
- // - if an expansionKey is provided, TS will infer the type of K to be
- // the return type.
- // - if it's not, then K will be defaulted to T.
- return this.expansionKey?.(dataNode) ?? dataNode;
- }
- _getAriaSet(node) {
- const key = this._getExpansionKey(node);
- const parent = this._parents.get(key);
- const parentKey = parent ? this._getExpansionKey(parent) : null;
- const set = this._ariaSets.get(parentKey);
- return set ?? [node];
- }
- /**
- * Finds the parent for the given node. If this is a root node, this
- * returns null. If we're unable to determine the parent, for example,
- * if we don't have cached node data, this returns undefined.
- */
- _findParentForNode(node, index, cachedNodes) {
- // In all cases, we have a mapping from node to level; all we need to do here is backtrack in
- // our flattened list of nodes to determine the first node that's of a level lower than the
- // provided node.
- if (!cachedNodes.length) {
- return null;
- }
- const currentLevel = this._levels.get(this._getExpansionKey(node)) ?? 0;
- for (let parentIndex = index - 1; parentIndex >= 0; parentIndex--) {
- const parentNode = cachedNodes[parentIndex];
- const parentLevel = this._levels.get(this._getExpansionKey(parentNode)) ?? 0;
- if (parentLevel < currentLevel) {
- return parentNode;
- }
- }
- return null;
- }
- /**
- * Given a set of root nodes and the current node level, flattens any nested
- * nodes into a single array.
- *
- * If any nodes are not expanded, then their children will not be added into the array.
- * This will still traverse all nested children in order to build up our internal data
- * models, but will not include them in the returned array.
- */
- _flattenNestedNodesWithExpansion(nodes, level = 0) {
- const childrenAccessor = this._getChildrenAccessor();
- // If we're using a level accessor, we don't need to flatten anything.
- if (!childrenAccessor) {
- return of([...nodes]);
- }
- return of(...nodes).pipe(concatMap(node => {
- const parentKey = this._getExpansionKey(node);
- if (!this._parents.has(parentKey)) {
- this._parents.set(parentKey, null);
- }
- this._levels.set(parentKey, level);
- const children = coerceObservable(childrenAccessor(node));
- return concat(of([node]), children.pipe(take(1), tap(childNodes => {
- this._ariaSets.set(parentKey, [...(childNodes ?? [])]);
- for (const child of childNodes ?? []) {
- const childKey = this._getExpansionKey(child);
- this._parents.set(childKey, node);
- this._levels.set(childKey, level + 1);
- }
- }), switchMap(childNodes => {
- if (!childNodes) {
- return of([]);
- }
- return this._flattenNestedNodesWithExpansion(childNodes, level + 1).pipe(map(nestedNodes => (this.isExpanded(node) ? nestedNodes : [])));
- })));
- }), reduce((results, children) => {
- results.push(...children);
- return results;
- }, []));
- }
- /**
- * Converts children for certain tree configurations.
- *
- * This also computes parent, level, and group data.
- */
- _computeRenderingData(nodes, nodeType) {
- // The only situations where we have to convert children types is when
- // they're mismatched; i.e. if the tree is using a childrenAccessor and the
- // nodes are flat, or if the tree is using a levelAccessor and the nodes are
- // nested.
- if (this.childrenAccessor && nodeType === 'flat') {
- // clear previously generated data so we don't keep end up retaining data overtime causing
- // memory leaks.
- this._clearPreviousCache();
- // This flattens children into a single array.
- this._ariaSets.set(null, [...nodes]);
- return this._flattenNestedNodesWithExpansion(nodes).pipe(map(flattenedNodes => ({
- renderNodes: flattenedNodes,
- flattenedNodes,
- })));
- }
- else if (this.levelAccessor && nodeType === 'nested') {
- // In the nested case, we only look for root nodes. The CdkNestedNode
- // itself will handle rendering each individual node's children.
- const levelAccessor = this.levelAccessor;
- return of(nodes.filter(node => levelAccessor(node) === 0)).pipe(map(rootNodes => ({
- renderNodes: rootNodes,
- flattenedNodes: nodes,
- })), tap(({ flattenedNodes }) => {
- this._calculateParents(flattenedNodes);
- }));
- }
- else if (nodeType === 'flat') {
- // In the case of a TreeControl, we know that the node type matches up
- // with the TreeControl, and so no conversions are necessary. Otherwise,
- // we've already confirmed that the data model matches up with the
- // desired node type here.
- return of({ renderNodes: nodes, flattenedNodes: nodes }).pipe(tap(({ flattenedNodes }) => {
- this._calculateParents(flattenedNodes);
- }));
- }
- else {
- // clear previously generated data so we don't keep end up retaining data overtime causing
- // memory leaks.
- this._clearPreviousCache();
- // For nested nodes, we still need to perform the node flattening in order
- // to maintain our caches for various tree operations.
- this._ariaSets.set(null, [...nodes]);
- return this._flattenNestedNodesWithExpansion(nodes).pipe(map(flattenedNodes => ({
- renderNodes: nodes,
- flattenedNodes,
- })));
- }
- }
- _updateCachedData(flattenedNodes) {
- this._flattenedNodes.next(flattenedNodes);
- }
- _updateKeyManagerItems(flattenedNodes) {
- this._keyManagerNodes.next(flattenedNodes);
- }
- /** Traverse the flattened node data and compute parents, levels, and group data. */
- _calculateParents(flattenedNodes) {
- const levelAccessor = this._getLevelAccessor();
- if (!levelAccessor) {
- return;
- }
- // clear previously generated data so we don't keep end up retaining data overtime causing
- // memory leaks.
- this._clearPreviousCache();
- for (let index = 0; index < flattenedNodes.length; index++) {
- const dataNode = flattenedNodes[index];
- const key = this._getExpansionKey(dataNode);
- this._levels.set(key, levelAccessor(dataNode));
- const parent = this._findParentForNode(dataNode, index, flattenedNodes);
- this._parents.set(key, parent);
- const parentKey = parent ? this._getExpansionKey(parent) : null;
- const group = this._ariaSets.get(parentKey) ?? [];
- group.splice(index, 0, dataNode);
- this._ariaSets.set(parentKey, group);
- }
- }
- /** Invokes a callback with all node expansion keys. */
- _forEachExpansionKey(callback) {
- const toToggle = [];
- const observables = [];
- this._nodes.value.forEach(node => {
- toToggle.push(this._getExpansionKey(node.data));
- observables.push(this._getDescendants(node.data));
- });
- if (observables.length > 0) {
- combineLatest(observables)
- .pipe(take(1), takeUntil(this._onDestroy))
- .subscribe(results => {
- results.forEach(inner => inner.forEach(r => toToggle.push(this._getExpansionKey(r))));
- callback(toToggle);
- });
- }
- else {
- callback(toToggle);
- }
- }
- /** Clears the maps we use to store parents, level & aria-sets in. */
- _clearPreviousCache() {
- this._parents.clear();
- this._levels.clear();
- this._ariaSets.clear();
- }
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CdkTree, deps: [], target: i0.ɵɵFactoryTarget.Component });
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.6", type: CdkTree, isStandalone: true, selector: "cdk-tree", inputs: { dataSource: "dataSource", treeControl: "treeControl", levelAccessor: "levelAccessor", childrenAccessor: "childrenAccessor", trackBy: "trackBy", expansionKey: "expansionKey" }, host: { attributes: { "role": "tree" }, listeners: { "keydown": "_sendKeydownToKeyManager($event)" }, classAttribute: "cdk-tree" }, queries: [{ propertyName: "_nodeDefs", predicate: CdkTreeNodeDef, descendants: true }], viewQueries: [{ propertyName: "_nodeOutlet", first: true, predicate: CdkTreeNodeOutlet, descendants: true, static: true }], exportAs: ["cdkTree"], ngImport: i0, template: `<ng-container cdkTreeNodeOutlet></ng-container>`, isInline: true, dependencies: [{ kind: "directive", type: CdkTreeNodeOutlet, selector: "[cdkTreeNodeOutlet]" }], changeDetection: i0.ChangeDetectionStrategy.Default, encapsulation: i0.ViewEncapsulation.None });
- }
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CdkTree, decorators: [{
- type: Component,
- args: [{
- selector: 'cdk-tree',
- exportAs: 'cdkTree',
- template: `<ng-container cdkTreeNodeOutlet></ng-container>`,
- host: {
- 'class': 'cdk-tree',
- 'role': 'tree',
- '(keydown)': '_sendKeydownToKeyManager($event)',
- },
- encapsulation: ViewEncapsulation.None,
- // The "OnPush" status for the `CdkTree` component is effectively a noop, so we are removing it.
- // The view for `CdkTree` consists entirely of templates declared in other views. As they are
- // declared elsewhere, they are checked when their declaration points are checked.
- // tslint:disable-next-line:validate-decorators
- changeDetection: ChangeDetectionStrategy.Default,
- imports: [CdkTreeNodeOutlet],
- }]
- }], ctorParameters: () => [], propDecorators: { dataSource: [{
- type: Input
- }], treeControl: [{
- type: Input
- }], levelAccessor: [{
- type: Input
- }], childrenAccessor: [{
- type: Input
- }], trackBy: [{
- type: Input
- }], expansionKey: [{
- type: Input
- }], _nodeOutlet: [{
- type: ViewChild,
- args: [CdkTreeNodeOutlet, { static: true }]
- }], _nodeDefs: [{
- type: ContentChildren,
- args: [CdkTreeNodeDef, {
- // We need to use `descendants: true`, because Ivy will no longer match
- // indirect descendants if it's left as false.
- descendants: true,
- }]
- }] } });
- /**
- * Tree node for CdkTree. It contains the data in the tree node.
- */
- class CdkTreeNode {
- _elementRef = inject(ElementRef);
- _tree = inject(CdkTree);
- _tabindex = -1;
- _type = 'flat';
- /**
- * The role of the tree node.
- *
- * @deprecated This will be ignored; the tree will automatically determine the appropriate role
- * for tree node. This input will be removed in a future version.
- * @breaking-change 21.0.0
- */
- get role() {
- return 'treeitem';
- }
- set role(_role) {
- // ignore any role setting, we handle this internally.
- }
- /**
- * Whether or not this node is expandable.
- *
- * If not using `FlatTreeControl`, or if `isExpandable` is not provided to
- * `NestedTreeControl`, this should be provided for correct node a11y.
- */
- get isExpandable() {
- return this._isExpandable();
- }
- set isExpandable(isExpandable) {
- this._inputIsExpandable = isExpandable;
- if ((this.data && !this._isExpandable) || !this._inputIsExpandable) {
- return;
- }
- // If the node is being set to expandable, ensure that the status of the
- // node is propagated
- if (this._inputIsExpanded) {
- this.expand();
- }
- else if (this._inputIsExpanded === false) {
- this.collapse();
- }
- }
- get isExpanded() {
- return this._tree.isExpanded(this._data);
- }
- set isExpanded(isExpanded) {
- this._inputIsExpanded = isExpanded;
- if (isExpanded) {
- this.expand();
- }
- else {
- this.collapse();
- }
- }
- /**
- * Whether or not this node is disabled. If it's disabled, then the user won't be able to focus
- * or activate this node.
- */
- isDisabled;
- /**
- * The text used to locate this item during typeahead. If not specified, the `textContent` will
- * will be used.
- */
- typeaheadLabel;
- getLabel() {
- return this.typeaheadLabel || this._elementRef.nativeElement.textContent?.trim() || '';
- }
- /** This emits when the node has been programatically activated or activated by keyboard. */
- activation = new EventEmitter();
- /** This emits when the node's expansion status has been changed. */
- expandedChange = new EventEmitter();
- /**
- * The most recently created `CdkTreeNode`. We save it in static variable so we can retrieve it
- * in `CdkTree` and set the data to it.
- */
- static mostRecentTreeNode = null;
- /** Subject that emits when the component has been destroyed. */
- _destroyed = new Subject();
- /** Emits when the node's data has changed. */
- _dataChanges = new Subject();
- _inputIsExpandable = false;
- _inputIsExpanded = undefined;
- /**
- * Flag used to determine whether or not we should be focusing the actual element based on
- * some user interaction (click or focus). On click, we don't forcibly focus the element
- * since the click could trigger some other component that wants to grab its own focus
- * (e.g. menu, dialog).
- */
- _shouldFocus = true;
- _parentNodeAriaLevel;
- /** The tree node's data. */
- get data() {
- return this._data;
- }
- set data(value) {
- if (value !== this._data) {
- this._data = value;
- this._dataChanges.next();
- }
- }
- _data;
- /* If leaf node, return true to not assign aria-expanded attribute */
- get isLeafNode() {
- // If flat tree node data returns false for expandable property, it's a leaf node
- if (this._tree.treeControl?.isExpandable !== undefined &&
- !this._tree.treeControl.isExpandable(this._data)) {
- return true;
- // If nested tree node data returns 0 descendants, it's a leaf node
- }
- else if (this._tree.treeControl?.isExpandable === undefined &&
- this._tree.treeControl?.getDescendants(this._data).length === 0) {
- return true;
- }
- return false;
- }
- get level() {
- // If the tree has a levelAccessor, use it to get the level. Otherwise read the
- // aria-level off the parent node and use it as the level for this node (note aria-level is
- // 1-indexed, while this property is 0-indexed, so we don't need to increment).
- return this._tree._getLevel(this._data) ?? this._parentNodeAriaLevel;
- }
- /** Determines if the tree node is expandable. */
- _isExpandable() {
- if (this._tree.treeControl) {
- if (this.isLeafNode) {
- return false;
- }
- // For compatibility with trees created using TreeControl before we added
- // CdkTreeNode#isExpandable.
- return true;
- }
- return this._inputIsExpandable;
- }
- /**
- * Determines the value for `aria-expanded`.
- *
- * For non-expandable nodes, this is `null`.
- */
- _getAriaExpanded() {
- if (!this._isExpandable()) {
- return null;
- }
- return String(this.isExpanded);
- }
- /**
- * Determines the size of this node's parent's child set.
- *
- * This is intended to be used for `aria-setsize`.
- */
- _getSetSize() {
- return this._tree._getSetSize(this._data);
- }
- /**
- * Determines the index (starting from 1) of this node in its parent's child set.
- *
- * This is intended to be used for `aria-posinset`.
- */
- _getPositionInSet() {
- return this._tree._getPositionInSet(this._data);
- }
- _changeDetectorRef = inject(ChangeDetectorRef);
- constructor() {
- CdkTreeNode.mostRecentTreeNode = this;
- }
- ngOnInit() {
- this._parentNodeAriaLevel = getParentNodeAriaLevel(this._elementRef.nativeElement);
- this._tree
- ._getExpansionModel()
- .changed.pipe(map(() => this.isExpanded), distinctUntilChanged())
- .subscribe(() => this._changeDetectorRef.markForCheck());
- this._tree._setNodeTypeIfUnset(this._type);
- this._tree._registerNode(this);
- }
- ngOnDestroy() {
- // If this is the last tree node being destroyed,
- // clear out the reference to avoid leaking memory.
- if (CdkTreeNode.mostRecentTreeNode === this) {
- CdkTreeNode.mostRecentTreeNode = null;
- }
- this._dataChanges.complete();
- this._destroyed.next();
- this._destroyed.complete();
- }
- getParent() {
- return this._tree._getNodeParent(this) ?? null;
- }
- getChildren() {
- return this._tree._getNodeChildren(this);
- }
- /** Focuses this data node. Implemented for TreeKeyManagerItem. */
- focus() {
- this._tabindex = 0;
- if (this._shouldFocus) {
- this._elementRef.nativeElement.focus();
- }
- this._changeDetectorRef.markForCheck();
- }
- /** Defocus this data node. */
- unfocus() {
- this._tabindex = -1;
- this._changeDetectorRef.markForCheck();
- }
- /** Emits an activation event. Implemented for TreeKeyManagerItem. */
- activate() {
- if (this.isDisabled) {
- return;
- }
- this.activation.next(this._data);
- }
- /** Collapses this data node. Implemented for TreeKeyManagerItem. */
- collapse() {
- if (this.isExpandable) {
- this._tree.collapse(this._data);
- }
- }
- /** Expands this data node. Implemented for TreeKeyManagerItem. */
- expand() {
- if (this.isExpandable) {
- this._tree.expand(this._data);
- }
- }
- /** Makes the node focusable. Implemented for TreeKeyManagerItem. */
- makeFocusable() {
- this._tabindex = 0;
- this._changeDetectorRef.markForCheck();
- }
- _focusItem() {
- if (this.isDisabled) {
- return;
- }
- this._tree._keyManager.focusItem(this);
- }
- _setActiveItem() {
- if (this.isDisabled) {
- return;
- }
- this._shouldFocus = false;
- this._tree._keyManager.focusItem(this);
- this._shouldFocus = true;
- }
- _emitExpansionState(expanded) {
- this.expandedChange.emit(expanded);
- }
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CdkTreeNode, deps: [], target: i0.ɵɵFactoryTarget.Directive });
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "19.2.6", type: CdkTreeNode, isStandalone: true, selector: "cdk-tree-node", inputs: { role: "role", isExpandable: ["isExpandable", "isExpandable", booleanAttribute], isExpanded: "isExpanded", isDisabled: ["isDisabled", "isDisabled", booleanAttribute], typeaheadLabel: ["cdkTreeNodeTypeaheadLabel", "typeaheadLabel"] }, outputs: { activation: "activation", expandedChange: "expandedChange" }, host: { attributes: { "role": "treeitem" }, listeners: { "click": "_setActiveItem()", "focus": "_focusItem()" }, properties: { "attr.aria-expanded": "_getAriaExpanded()", "attr.aria-level": "level + 1", "attr.aria-posinset": "_getPositionInSet()", "attr.aria-setsize": "_getSetSize()", "tabindex": "_tabindex" }, classAttribute: "cdk-tree-node" }, exportAs: ["cdkTreeNode"], ngImport: i0 });
- }
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CdkTreeNode, decorators: [{
- type: Directive,
- args: [{
- selector: 'cdk-tree-node',
- exportAs: 'cdkTreeNode',
- host: {
- 'class': 'cdk-tree-node',
- '[attr.aria-expanded]': '_getAriaExpanded()',
- '[attr.aria-level]': 'level + 1',
- '[attr.aria-posinset]': '_getPositionInSet()',
- '[attr.aria-setsize]': '_getSetSize()',
- '[tabindex]': '_tabindex',
- 'role': 'treeitem',
- '(click)': '_setActiveItem()',
- '(focus)': '_focusItem()',
- },
- }]
- }], ctorParameters: () => [], propDecorators: { role: [{
- type: Input
- }], isExpandable: [{
- type: Input,
- args: [{ transform: booleanAttribute }]
- }], isExpanded: [{
- type: Input
- }], isDisabled: [{
- type: Input,
- args: [{ transform: booleanAttribute }]
- }], typeaheadLabel: [{
- type: Input,
- args: ['cdkTreeNodeTypeaheadLabel']
- }], activation: [{
- type: Output
- }], expandedChange: [{
- type: Output
- }] } });
- function getParentNodeAriaLevel(nodeElement) {
- let parent = nodeElement.parentElement;
- while (parent && !isNodeElement(parent)) {
- parent = parent.parentElement;
- }
- if (!parent) {
- if (typeof ngDevMode === 'undefined' || ngDevMode) {
- throw Error('Incorrect tree structure containing detached node.');
- }
- else {
- return -1;
- }
- }
- else if (parent.classList.contains('cdk-nested-tree-node')) {
- return numberAttribute(parent.getAttribute('aria-level'));
- }
- else {
- // The ancestor element is the cdk-tree itself
- return 0;
- }
- }
- function isNodeElement(element) {
- const classList = element.classList;
- return !!(classList?.contains('cdk-nested-tree-node') || classList?.contains('cdk-tree'));
- }
- /**
- * Nested node is a child of `<cdk-tree>`. It works with nested tree.
- * By using `cdk-nested-tree-node` component in tree node template, children of the parent node will
- * be added in the `cdkTreeNodeOutlet` in tree node template.
- * The children of node will be automatically added to `cdkTreeNodeOutlet`.
- */
- class CdkNestedTreeNode extends CdkTreeNode {
- _type = 'nested';
- _differs = inject(IterableDiffers);
- /** Differ used to find the changes in the data provided by the data source. */
- _dataDiffer;
- /** The children data dataNodes of current node. They will be placed in `CdkTreeNodeOutlet`. */
- _children;
- /** The children node placeholder. */
- nodeOutlet;
- constructor() {
- super();
- }
- ngAfterContentInit() {
- this._dataDiffer = this._differs.find([]).create(this._tree.trackBy);
- this._tree
- ._getDirectChildren(this.data)
- .pipe(takeUntil(this._destroyed))
- .subscribe(result => this.updateChildrenNodes(result));
- this.nodeOutlet.changes
- .pipe(takeUntil(this._destroyed))
- .subscribe(() => this.updateChildrenNodes());
- }
- ngOnDestroy() {
- this._clear();
- super.ngOnDestroy();
- }
- /** Add children dataNodes to the NodeOutlet */
- updateChildrenNodes(children) {
- const outlet = this._getNodeOutlet();
- if (children) {
- this._children = children;
- }
- if (outlet && this._children) {
- const viewContainer = outlet.viewContainer;
- this._tree.renderNodeChanges(this._children, this._dataDiffer, viewContainer, this._data);
- }
- else {
- // Reset the data differ if there's no children nodes displayed
- this._dataDiffer.diff([]);
- }
- }
- /** Clear the children dataNodes. */
- _clear() {
- const outlet = this._getNodeOutlet();
- if (outlet) {
- outlet.viewContainer.clear();
- this._dataDiffer.diff([]);
- }
- }
- /** Gets the outlet for the current node. */
- _getNodeOutlet() {
- const outlets = this.nodeOutlet;
- // Note that since we use `descendants: true` on the query, we have to ensure
- // that we don't pick up the outlet of a child node by accident.
- return outlets && outlets.find(outlet => !outlet._node || outlet._node === this);
- }
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CdkNestedTreeNode, deps: [], target: i0.ɵɵFactoryTarget.Directive });
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.6", type: CdkNestedTreeNode, isStandalone: true, selector: "cdk-nested-tree-node", host: { classAttribute: "cdk-nested-tree-node" }, providers: [
- { provide: CdkTreeNode, useExisting: CdkNestedTreeNode },
- { provide: CDK_TREE_NODE_OUTLET_NODE, useExisting: CdkNestedTreeNode },
- ], queries: [{ propertyName: "nodeOutlet", predicate: CdkTreeNodeOutlet, descendants: true }], exportAs: ["cdkNestedTreeNode"], usesInheritance: true, ngImport: i0 });
- }
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CdkNestedTreeNode, decorators: [{
- type: Directive,
- args: [{
- selector: 'cdk-nested-tree-node',
- exportAs: 'cdkNestedTreeNode',
- providers: [
- { provide: CdkTreeNode, useExisting: CdkNestedTreeNode },
- { provide: CDK_TREE_NODE_OUTLET_NODE, useExisting: CdkNestedTreeNode },
- ],
- host: {
- 'class': 'cdk-nested-tree-node',
- },
- }]
- }], ctorParameters: () => [], propDecorators: { nodeOutlet: [{
- type: ContentChildren,
- args: [CdkTreeNodeOutlet, {
- // We need to use `descendants: true`, because Ivy will no longer match
- // indirect descendants if it's left as false.
- descendants: true,
- }]
- }] } });
- /** Regex used to split a string on its CSS units. */
- const cssUnitPattern = /([A-Za-z%]+)$/;
- /**
- * Indent for the children tree dataNodes.
- * This directive will add left-padding to the node to show hierarchy.
- */
- class CdkTreeNodePadding {
- _treeNode = inject(CdkTreeNode);
- _tree = inject(CdkTree);
- _element = inject(ElementRef);
- _dir = inject(Directionality, { optional: true });
- /** Current padding value applied to the element. Used to avoid unnecessarily hitting the DOM. */
- _currentPadding;
- /** Subject that emits when the component has been destroyed. */
- _destroyed = new Subject();
- /** CSS units used for the indentation value. */
- indentUnits = 'px';
- /** The level of depth of the tree node. The padding will be `level * indent` pixels. */
- get level() {
- return this._level;
- }
- set level(value) {
- this._setLevelInput(value);
- }
- _level;
- /**
- * The indent for each level. Can be a number or a CSS string.
- * Default number 40px from material design menu sub-menu spec.
- */
- get indent() {
- return this._indent;
- }
- set indent(indent) {
- this._setIndentInput(indent);
- }
- _indent = 40;
- constructor() {
- this._setPadding();
- this._dir?.change.pipe(takeUntil(this._destroyed)).subscribe(() => this._setPadding(true));
- // In Ivy the indentation binding might be set before the tree node's data has been added,
- // which means that we'll miss the first render. We have to subscribe to changes in the
- // data to ensure that everything is up to date.
- this._treeNode._dataChanges.subscribe(() => this._setPadding());
- }
- ngOnDestroy() {
- this._destroyed.next();
- this._destroyed.complete();
- }
- /** The padding indent value for the tree node. Returns a string with px numbers if not null. */
- _paddingIndent() {
- const nodeLevel = (this._treeNode.data && this._tree._getLevel(this._treeNode.data)) ?? null;
- const level = this._level == null ? nodeLevel : this._level;
- return typeof level === 'number' ? `${level * this._indent}${this.indentUnits}` : null;
- }
- _setPadding(forceChange = false) {
- const padding = this._paddingIndent();
- if (padding !== this._currentPadding || forceChange) {
- const element = this._element.nativeElement;
- const paddingProp = this._dir && this._dir.value === 'rtl' ? 'paddingRight' : 'paddingLeft';
- const resetProp = paddingProp === 'paddingLeft' ? 'paddingRight' : 'paddingLeft';
- element.style[paddingProp] = padding || '';
- element.style[resetProp] = '';
- this._currentPadding = padding;
- }
- }
- /**
- * This has been extracted to a util because of TS 4 and VE.
- * View Engine doesn't support property rename inheritance.
- * TS 4.0 doesn't allow properties to override accessors or vice-versa.
- * @docs-private
- */
- _setLevelInput(value) {
- // Set to null as the fallback value so that _setPadding can fall back to the node level if the
- // consumer set the directive as `cdkTreeNodePadding=""`. We still want to take this value if
- // they set 0 explicitly.
- this._level = isNaN(value) ? null : value;
- this._setPadding();
- }
- /**
- * This has been extracted to a util because of TS 4 and VE.
- * View Engine doesn't support property rename inheritance.
- * TS 4.0 doesn't allow properties to override accessors or vice-versa.
- * @docs-private
- */
- _setIndentInput(indent) {
- let value = indent;
- let units = 'px';
- if (typeof indent === 'string') {
- const parts = indent.split(cssUnitPattern);
- value = parts[0];
- units = parts[1] || units;
- }
- this.indentUnits = units;
- this._indent = numberAttribute(value);
- this._setPadding();
- }
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CdkTreeNodePadding, deps: [], target: i0.ɵɵFactoryTarget.Directive });
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "19.2.6", type: CdkTreeNodePadding, isStandalone: true, selector: "[cdkTreeNodePadding]", inputs: { level: ["cdkTreeNodePadding", "level", numberAttribute], indent: ["cdkTreeNodePaddingIndent", "indent"] }, ngImport: i0 });
- }
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CdkTreeNodePadding, decorators: [{
- type: Directive,
- args: [{
- selector: '[cdkTreeNodePadding]',
- }]
- }], ctorParameters: () => [], propDecorators: { level: [{
- type: Input,
- args: [{ alias: 'cdkTreeNodePadding', transform: numberAttribute }]
- }], indent: [{
- type: Input,
- args: ['cdkTreeNodePaddingIndent']
- }] } });
- /**
- * Node toggle to expand and collapse the node.
- */
- class CdkTreeNodeToggle {
- _tree = inject(CdkTree);
- _treeNode = inject(CdkTreeNode);
- /** Whether expand/collapse the node recursively. */
- recursive = false;
- constructor() { }
- // Toggle the expanded or collapsed state of this node.
- //
- // Focus this node with expanding or collapsing it. This ensures that the active node will always
- // be visible when expanding and collapsing.
- _toggle() {
- this.recursive
- ? this._tree.toggleDescendants(this._treeNode.data)
- : this._tree.toggle(this._treeNode.data);
- this._tree._keyManager.focusItem(this._treeNode);
- }
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CdkTreeNodeToggle, deps: [], target: i0.ɵɵFactoryTarget.Directive });
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "19.2.6", type: CdkTreeNodeToggle, isStandalone: true, selector: "[cdkTreeNodeToggle]", inputs: { recursive: ["cdkTreeNodeToggleRecursive", "recursive", booleanAttribute] }, host: { attributes: { "tabindex": "-1" }, listeners: { "click": "_toggle(); $event.stopPropagation();", "keydown.Enter": "_toggle(); $event.preventDefault();", "keydown.Space": "_toggle(); $event.preventDefault();" } }, ngImport: i0 });
- }
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CdkTreeNodeToggle, decorators: [{
- type: Directive,
- args: [{
- selector: '[cdkTreeNodeToggle]',
- host: {
- '(click)': '_toggle(); $event.stopPropagation();',
- '(keydown.Enter)': '_toggle(); $event.preventDefault();',
- '(keydown.Space)': '_toggle(); $event.preventDefault();',
- 'tabindex': '-1',
- },
- }]
- }], ctorParameters: () => [], propDecorators: { recursive: [{
- type: Input,
- args: [{ alias: 'cdkTreeNodeToggleRecursive', transform: booleanAttribute }]
- }] } });
- const EXPORTED_DECLARATIONS = [
- CdkNestedTreeNode,
- CdkTreeNodeDef,
- CdkTreeNodePadding,
- CdkTreeNodeToggle,
- CdkTree,
- CdkTreeNode,
- CdkTreeNodeOutlet,
- ];
- class CdkTreeModule {
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CdkTreeModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.6", ngImport: i0, type: CdkTreeModule, imports: [CdkNestedTreeNode,
- CdkTreeNodeDef,
- CdkTreeNodePadding,
- CdkTreeNodeToggle,
- CdkTree,
- CdkTreeNode,
- CdkTreeNodeOutlet], exports: [CdkNestedTreeNode,
- CdkTreeNodeDef,
- CdkTreeNodePadding,
- CdkTreeNodeToggle,
- CdkTree,
- CdkTreeNode,
- CdkTreeNodeOutlet] });
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CdkTreeModule });
- }
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CdkTreeModule, decorators: [{
- type: NgModule,
- args: [{
- imports: EXPORTED_DECLARATIONS,
- exports: EXPORTED_DECLARATIONS,
- }]
- }] });
- export { BaseTreeControl, CDK_TREE_NODE_OUTLET_NODE, CdkNestedTreeNode, CdkTree, CdkTreeModule, CdkTreeNode, CdkTreeNodeDef, CdkTreeNodeOutlet, CdkTreeNodeOutletContext, CdkTreeNodePadding, CdkTreeNodeToggle, FlatTreeControl, NestedTreeControl, getMultipleTreeControlsError, getTreeControlMissingError, getTreeMissingMatchingNodeDefError, getTreeMultipleDefaultNodeDefsError, getTreeNoValidDataSourceError };
- //# sourceMappingURL=tree.mjs.map
|