@mui/x-tree-view
Version:
The community edition of the MUI X Tree View components.
114 lines (107 loc) • 4.08 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TreeViewFocusPlugin = void 0;
var _expansion = require("../expansion");
var _selectors = require("./selectors");
var _items = require("../items");
class TreeViewFocusPlugin {
// We can't type `store`, otherwise we get the following TS error:
// 'focus' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
constructor(store) {
this.store = store;
// Whenever the items change, we need to ensure the focused item is still present.
this.store.registerStoreEffect(_items.itemsSelectors.itemMetaLookup, () => {
const focusedItemId = _selectors.focusSelectors.focusedItemId(store.state);
if (focusedItemId == null) {
return;
}
const hasItemBeenRemoved = !_items.itemsSelectors.itemMeta(store.state, focusedItemId);
if (!hasItemBeenRemoved) {
return;
}
const defaultFocusableItemId = _selectors.focusSelectors.defaultFocusableItemId(store.state);
if (defaultFocusableItemId == null) {
this.setFocusedItemId(null);
return;
}
this.applyItemFocus(null, defaultFocusableItemId);
});
}
setFocusedItemId = itemId => {
const focusedItemId = _selectors.focusSelectors.focusedItemId(this.store.state);
if (focusedItemId === itemId) {
return;
}
this.store.set('focusedItemId', itemId);
};
applyItemFocus = (event, itemId) => {
this.store.items.getItemDOMElement(itemId)?.focus();
this.setFocusedItemId(itemId);
this.store.parameters.onItemFocus?.(event, itemId);
};
buildPublicAPI = () => {
return {
focusItem: this.focusItem
};
};
/**
* Focus the item with the given id.
*
* If the item is the child of a collapsed item, then this method will do nothing.
* Make sure to expand the ancestors of the item before calling this method if needed.
* @param {React.SyntheticEvent | null} event The DOM event that triggered the change.
* @param {TreeViewItemId} itemId The id of the item to focus.
*/
focusItem = (event, itemId) => {
// If we receive an itemId, and it is visible, the focus will be set to it
const itemMeta = _items.itemsSelectors.itemMeta(this.store.state, itemId);
const isItemVisible = itemMeta && (itemMeta.parentId == null || _expansion.expansionSelectors.isItemExpanded(this.store.state, itemMeta.parentId));
if (isItemVisible) {
this.applyItemFocus(event, itemId);
}
};
/**
* Remove the focus from the currently focused item (both from the internal state and the DOM).
*/
removeFocusedItem = () => {
const focusedItemId = _selectors.focusSelectors.focusedItemId(this.store.state);
if (focusedItemId == null) {
return;
}
const itemMeta = _items.itemsSelectors.itemMeta(this.store.state, focusedItemId);
if (itemMeta) {
const itemElement = this.store.items.getItemDOMElement(focusedItemId);
if (itemElement) {
itemElement.blur();
}
}
this.setFocusedItemId(null);
};
/**
* Event handler to fire when the `root` slot of the Tree View is focused.
* @param {React.MouseEvent} event The DOM event that triggered the change.
*/
handleRootFocus = event => {
if (event.defaultMuiPrevented) {
return;
}
// if the event bubbled (which is React specific) we don't want to steal focus
const defaultFocusableItemId = _selectors.focusSelectors.defaultFocusableItemId(this.store.state);
if (event.target === event.currentTarget && defaultFocusableItemId != null) {
this.applyItemFocus(event, defaultFocusableItemId);
}
};
/**
* Event handler to fire when the `root` slot of the Tree View is blurred.
* @param {React.MouseEvent} event The DOM event that triggered the change.
*/
handleRootBlur = event => {
if (event.defaultMuiPrevented) {
return;
}
this.setFocusedItemId(null);
};
}
exports.TreeViewFocusPlugin = TreeViewFocusPlugin;