UNPKG

azure-devops-ui

Version:

React components for building web UI in Azure DevOps

150 lines (149 loc) 8.43 kB
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 }))); })))); })); } }