azure-devops-ui
Version:
React components for building web UI in Azure DevOps
150 lines (149 loc) • 8.43 kB
JavaScript
import "../../CommonImports";
import "../../Core/core.css";
import "./Dropdown.css";
import * as React from "react";
import { ObservableLike } from '../../Core/Observable';
import * as Utils_Accessibility from '../../Core/Util/Accessibility';
import { ScreenSize } from '../../Core/Util/Screen';
import { format } from '../../Core/Util/String';
import { FilterBarItem } from '../../FilterBarItem';
import { ListSelection } from '../../List';
import { getListBoxItemsValue, ListBoxItemType, wrapListBoxItems } from '../../ListBox';
import { Observer, SelectionObserver } from '../../Observer';
import * as Resources from '../../Resources.Dropdown';
import { css } from '../../Util';
import { updateFilterToSelection } from '../../Utilities/DropdownFilter';
import { DropdownSelection } from '../../Utilities/DropdownSelection';
import { ScreenSizeObserver } from '../../Utilities/ScreenSize';
import { compareSelectionRanges } from '../../Utilities/Selection';
import { Dropdown } from "./Dropdown";
import { DropdownExpandableButton } from "./DropdownExpandableButton";
const DropdownFilterBarItemWidth = 256;
export class DropdownFilterBarItem extends FilterBarItem {
constructor(props) {
super(props);
this.dropdown = React.createRef();
this.componentDidMount = () => {
var _a;
super.componentDidMount();
if (this.props.filter) {
const filterState = (_a = this.props.filter) === null || _a === void 0 ? void 0 : _a.getFilterItemState(this.props.filterItemKey);
this.onFilterChanged(filterState);
}
};
this.selectDefaultFilterItem = () => {
if (this.props.filter) {
const filterState = this.props.filter.getFilterItemState(this.props.filterItemKey);
if (filterState && filterState.value) {
const items = getListBoxItemsValue(this.wrappedItems || this.props.items);
const newSelection = new ListSelection(this.selection.multiSelect);
for (let i = 0; i < filterState.value.length; i++) {
const index = items.findIndex(item => item.id === filterState.value[i] ||
item.data === filterState.value[i] ||
JSON.stringify(item.data) === JSON.stringify(filterState.value[i]));
if (index > -1) {
newSelection.select(index, 1, true);
}
}
this.selection.value = newSelection.value;
}
}
};
this.onFilterChanged = (filterState) => {
super.onFilterChanged(filterState);
const items = getListBoxItemsValue(this.wrappedItems || this.props.items);
if (filterState && filterState.value) {
const newSelection = new ListSelection(this.selection.multiSelect);
for (let i = 0; i < filterState.value.length; i++) {
const index = items.findIndex(item => item.id === filterState.value[i] ||
item.data === filterState.value[i] ||
JSON.stringify(item.data) === JSON.stringify(filterState.value[i]));
if (index > -1) {
newSelection.select(index, 1, true);
}
}
const selectionDifference = compareSelectionRanges(this.selection.value, newSelection.value);
if (selectionDifference.length) {
this.selection.value = newSelection.value;
}
if (!this.selection.value.length) {
this.selectedText = undefined;
}
}
else {
this.selection.clear();
this.selectedText = undefined;
}
};
this.onSelectionChanged = (values) => {
const items = getListBoxItemsValue(this.wrappedItems || this.props.items);
const hasMultipleItems = items.length > 1;
const hasSingleNonLoadingItem = items.length === 1 && items[0].type !== ListBoxItemType.Loading;
if (this.props.filter && (hasMultipleItems || hasSingleNonLoadingItem)) {
updateFilterToSelection(values, items, this.props.filter, this.props.filterItemKey);
}
return true;
};
this.renderExpandableButton = (expandableProps) => {
const { className, renderExpandable, tooltipProps } = this.props;
const expandableButtonProps = Object.assign(Object.assign({}, expandableProps), { className: css(className, "bolt-dropdown-filter-bar-item"), subtle: true, renderSelectedItems: this.renderSelectedItems, tooltipProps });
if (renderExpandable) {
return renderExpandable(expandableButtonProps);
}
return React.createElement(DropdownExpandableButton, Object.assign({}, expandableButtonProps));
};
this.onClearClick = () => {
this.selection.clear();
this.selectedText = undefined;
this.props.toggleFilterBar && this.props.toggleFilterBar();
Utils_Accessibility.announce(Resources.AnnounceFilterCleared);
};
this.renderSelectedItems = (selection, items) => {
let selectedText = items[selection.value[0].beginIndex].text || "";
if (selection.selectedCount > 1) {
selectedText = `${selectedText} (+${selection.selectedCount - 1})`;
}
this.selectedText = selectedText;
const selectedTextSpan = React.createElement("span", { className: "bolt-dropdown-filter-bar-item-selected-text" }, selectedText);
return this.props.showPlaceholderAsLabel ? (React.createElement(React.Fragment, null,
React.createElement("span", { className: "bolt-dropdown-filter-bar-item-placeholder" }, `${this.props.placeholder}: `),
selectedTextSpan)) : (selectedTextSpan);
};
this.getAriaLabel = () => {
if (this.selectedText) {
return this.props.placeholder ? format(Resources.FilterAriaLabel, this.props.placeholder, this.selectedText) : this.selectedText;
}
return this.props.placeholder;
};
// string items are wrapped once here. Only use a string array in the simple case where the items are not changing.
this.wrappedItems = wrapListBoxItems(props.items);
this.selection = props.selection || new DropdownSelection();
// Select the default items from the filter.
this.selectDefaultFilterItem();
}
focus() {
if (this.dropdown.current) {
this.dropdown.current.focus();
}
}
render() {
return (React.createElement(SelectionObserver, { selection: this.selection, onSelectionChanged: this.onSelectionChanged }, () => {
const actionsFromProps = ObservableLike.getValue(this.props.actions || []);
const actions = [...actionsFromProps];
if (!this.props.hideClearAction) {
actions.push({
className: "bolt-dropdown-action-right-button",
disabled: this.selection.selectedCount === 0,
iconProps: { iconName: "Clear" },
text: Resources.DropdownClearActionText,
onClick: this.onClearClick
});
}
return (React.createElement(Observer, { dropdownItems: { observableValue: this.props.items, filter: this.selectDefaultFilterItem } }, () => (React.createElement(ScreenSizeObserver, null, (screenSizeProps) => {
var _a;
const isXsmall = screenSizeProps.screenSize <= ScreenSize.xsmall;
return (React.createElement(Dropdown, Object.assign({ ariaLabel: (_a = this.props.ariaLabel) !== null && _a !== void 0 ? _a : this.getAriaLabel(), width: isXsmall ? undefined : DropdownFilterBarItemWidth, renderExpandable: this.renderExpandableButton }, this.props, { actions: actions, selection: this.selection, ref: this.dropdown })));
}))));
}));
}
}