UNPKG

azure-devops-ui

Version:

React components for building web UI in Azure DevOps

192 lines (191 loc) 10.1 kB
import "../../CommonImports"; import "../../Core/core.css"; import "./Table.css"; import * as React from "react"; import { ObservableValue } from '../../Core/Observable'; import { announce } from '../../Core/Util/Accessibility'; import { Checkbox, TriStateCheckbox } from '../../Checkbox'; import { Observer } from '../../Observer'; import * as Resources from '../../Resources.Widgets'; import { css, KeyCode, preventDefault } from '../../Util'; import { IMeasurementStyle, TableColumnLayout } from "./Table.Props"; /** * ColumnSelect is used to render additional selection ui for a given row. * * This renders a fixed width column that contains a checkbox in the header * as well as each row that represents the selection state of the row. It * also allows the user to change the selection state. The header checkbox * is used to set the state of all rows in the table to the same state. * */ export class ColumnSelect { constructor(props) { this.isListbox = false; this.columnSelectBehavior = { initialize: (props) => { this.ariaHidden = props.tableProps.role === "menu"; this.itemProvider = props.tableProps.itemProvider; this.selection = props.tableProps.selection; this.onSelect = props.tableProps.onSelect; this.isListbox = props.tableProps.role === "listbox"; }, componentDidMount: (props) => { this.componentDidMount(props); }, componentDidUpdate: (props) => { this.componentDidUpdate(props); }, componentWillUnmount: () => { this.componentWillUnmount(); } }; this.allSelected = new ObservableValue(false); this.columnLayout = TableColumnLayout.none; this.id = "_select"; this.width = 2.5; this.widthStyle = IMeasurementStyle.REM; this.behaviors = [this.columnSelectBehavior]; this.renderCell = (rowIndex, columnIndex, listColumn) => { var _a, _b, _c, _d; const { selection } = this; const selected = selection && selection.selected(rowIndex); const selectable = selection && selection.selectable(rowIndex); return (this.isListbox ? (React.createElement("div", { "aria-hidden": this.ariaHidden, className: css("bolt-table-cell-select bolt-table-cell bolt-list-cell flex-noshrink", "col-" + columnIndex), "data-column-index": columnIndex, key: "col-select", onClick: preventDefault, onDoubleClick: preventDefault, onMouseDown: event => { this.updateSelection(event, rowIndex); event.preventDefault(); }, onKeyDown: event => { if (event.which === KeyCode.space) { this.updateSelection(event, rowIndex); event.preventDefault(); } } }, React.createElement("div", { className: "flex-row justify-center" }, React.createElement("span", { className: "flex-row-inline" }, React.createElement(Checkbox, { ariaLabel: ((_a = this.props) === null || _a === void 0 ? void 0 : _a.role) === "presentation" ? undefined : Resources.SelectRowLabel, checked: !!selected, excludeFocusZone: (_b = this.props) === null || _b === void 0 ? void 0 : _b.excludeFocusZone, excludeTabStop: true, disabled: !selectable }))))) : (React.createElement("td", { "aria-colindex": columnIndex + 1, "aria-hidden": this.ariaHidden, className: css("bolt-table-cell-select bolt-table-cell bolt-list-cell", "col-" + columnIndex), "data-column-index": columnIndex, key: "col-select", onClick: preventDefault, onDoubleClick: preventDefault, onMouseDown: event => { this.updateSelection(event, rowIndex); event.preventDefault(); }, onKeyDown: event => { if (event.which === KeyCode.space) { this.updateSelection(event, rowIndex); event.preventDefault(); } } }, React.createElement("div", { className: "flex-row justify-center" }, React.createElement("span", { className: "flex-row-inline" }, React.createElement(Checkbox, { ariaLabel: ((_c = this.props) === null || _c === void 0 ? void 0 : _c.role) === "presentation" ? undefined : Resources.SelectRowLabel, checked: !!selected, excludeFocusZone: (_d = this.props) === null || _d === void 0 ? void 0 : _d.excludeFocusZone, excludeTabStop: true, disabled: !selectable })))))); }; this.renderHeaderCell = (columnIndex, listColumn, focuszoneId) => { return (React.createElement("th", { "aria-colindex": columnIndex + 1, className: css("bolt-table-cell-select bolt-table-header-cell", "col-header-" + columnIndex), "data-column-index": columnIndex, key: "col-select" }, React.createElement("div", { className: "flex-row" }, React.createElement(Observer, { allSelected: this.allSelected }, (props) => { var _a, _b; const { itemProvider, selection } = this; // Get the total number of items within the list. const itemCount = itemProvider && itemProvider.length; return selection && selection.multiSelect && itemCount !== -1 ? (React.createElement("div", { className: "flex-row flex-grow justify-center" }, React.createElement(TriStateCheckbox, { ariaLabel: (_a = listColumn.ariaLabel) !== null && _a !== void 0 ? _a : Resources.SelectAllRowsLabel, checked: props.allSelected, focuszoneId: focuszoneId, onChange: this.onChangeHeader }))) : (React.createElement("div", { className: "visually-hidden" }, (_b = listColumn.ariaLabel) !== null && _b !== void 0 ? _b : Resources.SelectionColumnLabel)); })))); }; this.onChangeHeader = (event) => { const { itemProvider, onSelect, selection } = this; // toggle select all if (selection) { if (this.allSelected.value !== false) { selection.clear(); announce(Resources.AllRowsUnselectedMessage, true); } else { selection.select(0, itemProvider && itemProvider.length); announce(Resources.AllRowsSelectedMessage, true); } } if (onSelect && itemProvider) { for (let i = 0; i < itemProvider.length; i++) { onSelect(event, this.getListRow(i)); } } }; this.onSelectionChange = () => { const { itemProvider, selection } = this; if (selection) { const selectedCount = selection.selectedCount; const itemCount = itemProvider && itemProvider.length - selection.unselectableCount; if (selectedCount > 0) { if (selectedCount === itemCount) { this.allSelected.value = true; } else { this.allSelected.value = undefined; } } else { this.allSelected.value = false; } } }; this.updateSelection = (event, rowIndex) => { const { onSelect, selection } = this; if (selection) { if (selection.selected(rowIndex)) { selection.unselect(rowIndex); } else { selection.select(rowIndex, 1, true); } } if (onSelect) { const listRow = this.getListRow(rowIndex); onSelect(event, listRow); } }; this.getListRow = (rowIndex) => { return { data: this.itemProvider ? this.itemProvider.value[rowIndex] : {}, index: rowIndex }; }; this.props = props; } componentDidMount(props) { const { itemProvider, selection } = this; // We need to know about changes to the selection to manage the selectAll state. if (selection) { selection.subscribe(this.onSelectionChange); this.onSelectionChange(); } if (itemProvider && itemProvider.subscribe) { itemProvider.subscribe(this.onSelectionChange); } } componentDidUpdate(props) { let { selection } = this; if (selection !== props.tableProps.selection) { if (selection) { selection.unsubscribe(this.onSelectionChange); } selection = props.tableProps.selection; this.selection = selection; if (selection) { selection.subscribe(this.onSelectionChange); } } if (selection) { this.onSelectionChange(); } if (this.itemProvider !== props.tableProps.itemProvider) { if (this.itemProvider && this.itemProvider.unsubscribe) { this.itemProvider.unsubscribe(this.onSelectionChange); } this.itemProvider = props.tableProps.itemProvider; if (this.itemProvider && this.itemProvider.subscribe) { this.itemProvider.subscribe(this.onSelectionChange); } } } componentWillUnmount() { const { selection } = this; if (selection) { selection.unsubscribe(this.onSelectionChange); } if (this.itemProvider && this.itemProvider.unsubscribe) { this.itemProvider.unsubscribe(this.onSelectionChange); } } }