office-ui-fabric-react
Version:
Reusable React components for building experiences for Office 365.
334 lines • 22.2 kB
JavaScript
define(["require", "exports", "tslib", "react", "react-dom", "../../Utilities", "./DetailsList.types", "../../FocusZone", "../../Icon", "../../Layer", "../GroupedList/GroupSpacer", "../../GroupedList", "./DetailsRowCheck", "./DetailsRowCheck.scss", "../../utilities/selection/interfaces", "./DetailsHeader.scss"], function (require, exports, tslib_1, React, ReactDOM, Utilities_1, DetailsList_types_1, FocusZone_1, Icon_1, Layer_1, GroupSpacer_1, GroupedList_1, DetailsRowCheck_1, checkStylesModule, interfaces_1, stylesImport) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var styles = stylesImport;
var checkStyles = checkStylesModule;
var MOUSEDOWN_PRIMARY_BUTTON = 0; // for mouse down event we are using ev.button property, 0 means left button
var MOUSEMOVE_PRIMARY_BUTTON = 1; // for mouse move event we are using ev.buttons property, 1 means left button
var INNER_PADDING = 16;
var ISPADDED_WIDTH = 24;
var SelectAllVisibility;
(function (SelectAllVisibility) {
SelectAllVisibility[SelectAllVisibility["none"] = 0] = "none";
SelectAllVisibility[SelectAllVisibility["hidden"] = 1] = "hidden";
SelectAllVisibility[SelectAllVisibility["visible"] = 2] = "visible";
})(SelectAllVisibility = exports.SelectAllVisibility || (exports.SelectAllVisibility = {}));
var DetailsHeader = /** @class */ (function (_super) {
tslib_1.__extends(DetailsHeader, _super);
function DetailsHeader(props) {
var _this = _super.call(this, props) || this;
_this.state = {
columnResizeDetails: undefined,
groupNestingDepth: _this.props.groupNestingDepth,
isAllCollapsed: _this.props.isAllCollapsed
};
_this._onToggleCollapseAll = _this._onToggleCollapseAll.bind(_this);
_this._onSelectAllClicked = _this._onSelectAllClicked.bind(_this);
_this._id = Utilities_1.getId('header');
return _this;
}
DetailsHeader.prototype.componentDidMount = function () {
var selection = this.props.selection;
this._events.on(selection, interfaces_1.SELECTION_CHANGE, this._onSelectionChanged);
var rootElement = ReactDOM.findDOMNode(this._root);
// We need to use native on this to avoid MarqueeSelection from handling the event before us.
this._events.on(rootElement, 'mousedown', this._onRootMouseDown);
this._events.on(rootElement, 'keydown', this._onRootKeyDown);
};
DetailsHeader.prototype.componentWillReceiveProps = function (newProps) {
var groupNestingDepth = this.state.groupNestingDepth;
if (newProps.groupNestingDepth !== groupNestingDepth) {
this.setState({ groupNestingDepth: newProps.groupNestingDepth });
}
};
DetailsHeader.prototype.render = function () {
var _this = this;
var _a = this.props, columns = _a.columns, ariaLabel = _a.ariaLabel, ariaLabelForSelectAllCheckbox = _a.ariaLabelForSelectAllCheckbox, selectAllVisibility = _a.selectAllVisibility, ariaLabelForSelectionColumn = _a.ariaLabelForSelectionColumn;
var _b = this.state, isAllSelected = _b.isAllSelected, columnResizeDetails = _b.columnResizeDetails, isSizing = _b.isSizing, groupNestingDepth = _b.groupNestingDepth, isAllCollapsed = _b.isAllCollapsed;
var showCheckbox = selectAllVisibility !== SelectAllVisibility.none;
var _c = this.props.onRenderColumnHeaderTooltip, onRenderColumnHeaderTooltip = _c === void 0 ? this._onRenderColumnHeaderTooltip : _c;
return (React.createElement(FocusZone_1.FocusZone, { role: 'row', "aria-label": ariaLabel, className: Utilities_1.css('ms-DetailsHeader', styles.root, isAllSelected && ('is-allSelected ' + styles.rootIsAllSelected), (selectAllVisibility === SelectAllVisibility.hidden) && ('is-selectAllHidden ' + styles.rootIsSelectAllHidden), (!!columnResizeDetails && isSizing) && 'is-resizingColumn'), ref: this._resolveRef('_root'), onMouseMove: this._onRootMouseMove, "data-automationid": 'DetailsHeader', direction: FocusZone_1.FocusZoneDirection.horizontal },
showCheckbox ? ([
React.createElement("div", { key: '__checkbox', className: Utilities_1.css('ms-DetailsHeader-cell', 'ms-DetailsHeader-cellIsCheck', styles.cell, styles.cellIsCheck, checkStyles.owner, isAllSelected && checkStyles.isSelected), "aria-labelledby": this._id + "-check", onClick: this._onSelectAllClicked, "aria-colindex": 0, role: 'columnheader' }, onRenderColumnHeaderTooltip({
hostClassName: Utilities_1.css(styles.checkTooltip),
id: this._id + "-checkTooltip",
setAriaDescribedBy: false,
content: ariaLabelForSelectAllCheckbox,
children: (React.createElement(DetailsRowCheck_1.DetailsRowCheck, { id: this._id + "-check", "aria-label": ariaLabelForSelectionColumn, "aria-describedby": this._id + "-checkTooltip", "data-is-focusable": true, isHeader: true, selected: isAllSelected, anySelected: false, canSelect: true }))
}, this._onRenderColumnHeaderTooltip)),
ariaLabelForSelectAllCheckbox && !this.props.onRenderColumnHeaderTooltip ? (React.createElement("label", { key: '__checkboxLabel', id: this._id + "-checkTooltip", className: styles.accessibleLabel }, ariaLabelForSelectAllCheckbox)) : null
]) : null,
groupNestingDepth > 0 && this.props.collapseAllVisibility === GroupedList_1.CollapseAllVisibility.visible ? (React.createElement("div", { className: Utilities_1.css('ms-DetailsHeader-cell', styles.cell), onClick: this._onToggleCollapseAll, "data-is-focusable": true },
React.createElement(Icon_1.Icon, { className: Utilities_1.css('ms-DetailsHeader-collapseButton', styles.collapseButton, isAllCollapsed && ('is-collapsed ' + styles.collapseButtonIsCollapsed)), iconName: 'ChevronDown' }))) : (null),
GroupSpacer_1.GroupSpacer({ count: groupNestingDepth - 1 }),
columns.map(function (column, columnIndex) {
return ([
React.createElement("div", { key: column.key, role: 'columnheader', "aria-sort": column.isSorted ? (column.isSortedDescending ? 'descending' : 'ascending') : 'none', "aria-disabled": column.columnActionsMode === DetailsList_types_1.ColumnActionsMode.disabled, "aria-colindex": (showCheckbox ? 1 : 0) + columnIndex, className: Utilities_1.css('ms-DetailsHeader-cell', styles.cell, column.headerClassName, (column.columnActionsMode !== DetailsList_types_1.ColumnActionsMode.disabled) && ('is-actionable ' + styles.cellIsActionable), !column.name && ('is-empty ' + styles.cellIsEmpty), (column.isSorted || column.isGrouped || column.isFiltered) && 'is-icon-visible', column.isPadded && styles.cellWrapperPadded), style: { width: column.calculatedWidth + INNER_PADDING + (column.isPadded ? ISPADDED_WIDTH : 0) }, "data-automationid": 'ColumnsHeaderColumn', "data-item-key": column.key }, onRenderColumnHeaderTooltip({
hostClassName: Utilities_1.css(styles.cellTooltip),
id: _this._id + "-" + column.key + "-tooltip",
setAriaDescribedBy: false,
content: column.columnActionsMode !== DetailsList_types_1.ColumnActionsMode.disabled ? column.ariaLabel : '',
children: (React.createElement("span", { id: _this._id + "-" + column.key, "aria-label": column.isIconOnly ? column.name : undefined, "aria-labelledby": column.isIconOnly ? undefined : _this._id + "-" + column.key + "-name ", className: Utilities_1.css('ms-DetailsHeader-cellTitle', styles.cellTitle), "data-is-focusable": column.columnActionsMode !== DetailsList_types_1.ColumnActionsMode.disabled, role: column.columnActionsMode !== DetailsList_types_1.ColumnActionsMode.disabled ? 'button' : undefined, "aria-describedby": _this._id + "-" + column.key + "-tooltip", onContextMenu: _this._onColumnContextMenu.bind(_this, column), onClick: _this._onColumnClick.bind(_this, column), "aria-haspopup": column.columnActionsMode === DetailsList_types_1.ColumnActionsMode.hasDropdown },
React.createElement("span", { id: _this._id + "-" + column.key + "-name", className: Utilities_1.css('ms-DetailsHeader-cellName', styles.cellName, (_a = {},
_a[styles.iconOnlyHeader] = column.isIconOnly,
_a)) },
(column.iconName || column.iconClassName) && (React.createElement(Icon_1.Icon, { className: Utilities_1.css(styles.nearIcon, column.iconClassName), iconName: column.iconName })),
!column.isIconOnly ? column.name : undefined),
column.isFiltered && (React.createElement(Icon_1.Icon, { className: styles.nearIcon, iconName: 'Filter' })),
column.isSorted && (React.createElement(Icon_1.Icon, { className: Utilities_1.css(styles.nearIcon, styles.sortIcon), iconName: column.isSortedDescending ? 'SortDown' : 'SortUp' })),
column.isGrouped && (React.createElement(Icon_1.Icon, { className: styles.nearIcon, iconName: 'GroupedDescending' })),
column.columnActionsMode === DetailsList_types_1.ColumnActionsMode.hasDropdown && !column.isIconOnly && (React.createElement(Icon_1.Icon, { className: Utilities_1.css('ms-DetailsHeader-filterChevron', styles.filterChevron), iconName: 'ChevronDown' }))))
}, _this._onRenderColumnHeaderTooltip)),
column.ariaLabel && !_this.props.onRenderColumnHeaderTooltip ? (React.createElement("label", { key: column.key + "_label", id: _this._id + "-" + column.key + "-tooltip", className: styles.accessibleLabel }, column.ariaLabel)) : null,
(column.isResizable) && _this._renderColumnSizer(columnIndex)
]);
var _a;
}),
isSizing && (React.createElement(Layer_1.Layer, null,
React.createElement("div", { className: Utilities_1.css(isSizing && styles.sizingOverlay), onMouseMove: this._onSizerMouseMove, onMouseUp: this._onSizerMouseUp })))));
};
/** Set focus to the active thing in the focus area. */
DetailsHeader.prototype.focus = function () {
return this._root.focus();
};
DetailsHeader.prototype._renderColumnSizer = function (columnIndex) {
var columns = this.props.columns;
var column = this.props.columns[columnIndex];
var columnResizeDetails = this.state.columnResizeDetails;
return (React.createElement("div", { key: column.key + "_sizer", "aria-hidden": true, role: 'button', "data-is-focusable": false, onClick: stopPropagation, "data-sizer-index": columnIndex, onBlur: this._onSizerBlur, className: Utilities_1.css('ms-DetailsHeader-cellSizer', styles.cellSizer, columnIndex < columns.length - 1 ? styles.cellSizerStart : styles.cellSizerEnd, (_a = {},
_a['is-resizing ' + styles.cellIsResizing] = columnResizeDetails && columnResizeDetails.columnIndex === columnIndex,
_a)), onDoubleClick: this._onSizerDoubleClick.bind(this, columnIndex) }));
var _a;
};
DetailsHeader.prototype._onRenderColumnHeaderTooltip = function (tooltipHostProps, defaultRender) {
return (React.createElement("span", { className: tooltipHostProps.hostClassName }, tooltipHostProps.children));
};
/**
* double click on the column sizer will auto ajust column width
* to fit the longest content among current rendered rows.
*
* @private
* @param {number} columnIndex (index of the column user double clicked)
* @param {React.MouseEvent} ev (mouse double click event)
*/
DetailsHeader.prototype._onSizerDoubleClick = function (columnIndex, ev) {
var _a = this.props, onColumnAutoResized = _a.onColumnAutoResized, columns = _a.columns;
if (onColumnAutoResized) {
onColumnAutoResized(columns[columnIndex], columnIndex);
}
};
/**
* Called when the select all toggle is clicked.
*/
DetailsHeader.prototype._onSelectAllClicked = function () {
var selection = this.props.selection;
selection.toggleAllSelected();
};
DetailsHeader.prototype._onRootMouseDown = function (ev) {
var columnIndexAttr = ev.target.getAttribute('data-sizer-index');
var columnIndex = Number(columnIndexAttr);
var columns = this.props.columns;
if (columnIndexAttr === null || ev.button !== MOUSEDOWN_PRIMARY_BUTTON) {
// Ignore anything except the primary button.
return;
}
this.setState({
columnResizeDetails: {
columnIndex: columnIndex,
columnMinWidth: columns[columnIndex].calculatedWidth,
originX: ev.clientX
}
});
ev.preventDefault();
ev.stopPropagation();
};
DetailsHeader.prototype._onRootMouseMove = function (ev) {
var _a = this.state, columnResizeDetails = _a.columnResizeDetails, isSizing = _a.isSizing;
if (columnResizeDetails && !isSizing && ev.clientX !== columnResizeDetails.originX) {
this.setState({ isSizing: true });
}
};
DetailsHeader.prototype._onRootKeyDown = function (ev) {
var _a = this.state, columnResizeDetails = _a.columnResizeDetails, isSizing = _a.isSizing;
var _b = this.props, columns = _b.columns, onColumnResized = _b.onColumnResized;
var columnIndexAttr = ev.target.getAttribute('data-sizer-index');
if (!columnIndexAttr || isSizing) {
return;
}
var columnIndex = Number(columnIndexAttr);
if (!columnResizeDetails) {
if (ev.which === 13 /* enter */) {
this.setState({
columnResizeDetails: {
columnIndex: columnIndex,
columnMinWidth: columns[columnIndex].calculatedWidth
}
});
ev.preventDefault();
ev.stopPropagation();
}
}
else {
var increment = void 0;
if (ev.which === 13 /* enter */) {
this.setState({
columnResizeDetails: undefined
});
ev.preventDefault();
ev.stopPropagation();
}
else if (ev.which === 37 /* left */) {
increment = Utilities_1.getRTL() ? 1 : -1;
}
else if (ev.which === 39 /* right */) {
increment = Utilities_1.getRTL() ? -1 : 1;
}
if (increment) {
if (!ev.shiftKey) {
increment *= 10;
}
this.setState({
columnResizeDetails: tslib_1.__assign({}, columnResizeDetails, { columnMinWidth: columnResizeDetails.columnMinWidth + increment })
});
if (onColumnResized) {
onColumnResized(columns[columnIndex], columnResizeDetails.columnMinWidth + increment, columnIndex);
}
ev.preventDefault();
ev.stopPropagation();
}
}
};
/**
* mouse move event handler in the header
* it will set isSizing state to true when user clicked on the sizer and move the mouse.
*
* @private
* @param {React.MouseEvent} ev (mouse move event)
*/
DetailsHeader.prototype._onSizerMouseMove = function (ev) {
var
// use buttons property here since ev.button in some edge case is not upding well during the move.
// but firefox doesn't support it, so we set the default value when it is not defined.
buttons = ev.buttons;
var _a = this.props, onColumnIsSizingChanged = _a.onColumnIsSizingChanged, onColumnResized = _a.onColumnResized, columns = _a.columns;
var columnResizeDetails = this.state.columnResizeDetails;
if (buttons !== undefined && buttons !== MOUSEMOVE_PRIMARY_BUTTON) {
// cancel mouse down event and return early when the primary button is not pressed
this._onSizerMouseUp(ev);
return;
}
if (ev.clientX !== columnResizeDetails.originX) {
if (onColumnIsSizingChanged) {
onColumnIsSizingChanged(columns[columnResizeDetails.columnIndex], true);
}
}
if (onColumnResized) {
var movement = ev.clientX - columnResizeDetails.originX;
if (Utilities_1.getRTL()) {
movement = -movement;
}
onColumnResized(columns[columnResizeDetails.columnIndex], columnResizeDetails.columnMinWidth + movement, columnResizeDetails.columnIndex);
}
};
DetailsHeader.prototype._onSizerBlur = function (ev) {
var columnResizeDetails = this.state.columnResizeDetails;
if (columnResizeDetails) {
this.setState({
columnResizeDetails: undefined,
isSizing: false
});
}
};
/**
* mouse up event handler in the header
* clear the resize related state.
* This is to ensure we can catch double click event
*
* @private
* @param {React.MouseEvent} ev (mouse up event)
*/
DetailsHeader.prototype._onSizerMouseUp = function (ev) {
var _a = this.props, columns = _a.columns, onColumnIsSizingChanged = _a.onColumnIsSizingChanged;
var columnResizeDetails = this.state.columnResizeDetails;
this.setState({
columnResizeDetails: undefined,
isSizing: false
});
if (onColumnIsSizingChanged) {
onColumnIsSizingChanged(columns[columnResizeDetails.columnIndex], false);
}
};
DetailsHeader.prototype._onSelectionChanged = function () {
var isAllSelected = this.props.selection.isAllSelected();
if (this.state.isAllSelected !== isAllSelected) {
this.setState({
isAllSelected: isAllSelected
});
}
};
DetailsHeader.prototype._onColumnClick = function (column, ev) {
var onColumnClick = this.props.onColumnClick;
if (column.onColumnClick) {
column.onColumnClick(ev, column);
}
if (onColumnClick) {
onColumnClick(ev, column);
}
};
DetailsHeader.prototype._onColumnContextMenu = function (column, ev) {
var onColumnContextMenu = this.props.onColumnContextMenu;
if (column.onColumnContextMenu) {
column.onColumnContextMenu(column, ev);
ev.preventDefault();
}
if (onColumnContextMenu) {
onColumnContextMenu(column, ev);
ev.preventDefault();
}
};
DetailsHeader.prototype._onToggleCollapseAll = function () {
var onToggleCollapseAll = this.props.onToggleCollapseAll;
var newCollapsed = !this.state.isAllCollapsed;
this.setState({
isAllCollapsed: newCollapsed
});
if (onToggleCollapseAll) {
onToggleCollapseAll(newCollapsed);
}
};
DetailsHeader.defaultProps = {
selectAllVisibility: SelectAllVisibility.visible,
collapseAllVisibility: GroupedList_1.CollapseAllVisibility.visible
};
tslib_1.__decorate([
Utilities_1.autobind
], DetailsHeader.prototype, "_onRenderColumnHeaderTooltip", null);
tslib_1.__decorate([
Utilities_1.autobind
], DetailsHeader.prototype, "_onSelectAllClicked", null);
tslib_1.__decorate([
Utilities_1.autobind
], DetailsHeader.prototype, "_onRootMouseDown", null);
tslib_1.__decorate([
Utilities_1.autobind
], DetailsHeader.prototype, "_onRootMouseMove", null);
tslib_1.__decorate([
Utilities_1.autobind
], DetailsHeader.prototype, "_onRootKeyDown", null);
tslib_1.__decorate([
Utilities_1.autobind
], DetailsHeader.prototype, "_onSizerMouseMove", null);
tslib_1.__decorate([
Utilities_1.autobind
], DetailsHeader.prototype, "_onSizerBlur", null);
tslib_1.__decorate([
Utilities_1.autobind
], DetailsHeader.prototype, "_onSizerMouseUp", null);
return DetailsHeader;
}(Utilities_1.BaseComponent));
exports.DetailsHeader = DetailsHeader;
function stopPropagation(ev) {
ev.stopPropagation();
}
});
//# sourceMappingURL=DetailsHeader.js.map