UNPKG

office-ui-fabric-react

Version:

Reusable React components for building experiences for Office 365.

713 lines • 40.5 kB
import * as tslib_1 from "tslib"; import * as React from 'react'; import { BaseComponent, assign, elementContains, getRTLSafeKeyCode, createRef, classNamesFunction } from '../../Utilities'; import { CheckboxVisibility, ColumnActionsMode, ConstrainMode, DetailsListLayoutMode, ColumnDragEndLocation } from '../DetailsList/DetailsList.types'; import { DetailsHeader } from '../DetailsList/DetailsHeader'; import { SelectAllVisibility } from '../DetailsList/DetailsHeader.types'; import { DetailsRow } from '../DetailsList/DetailsRow'; import { FocusZone, FocusZoneDirection } from '../../FocusZone'; import { Selection, SelectionMode, SelectionZone } from '../../utilities/selection/index'; import { DragDropHelper } from '../../utilities/dragdrop/DragDropHelper'; import { GroupedList } from '../../GroupedList'; import { List } from '../../List'; import { withViewport } from '../../utilities/decorators/withViewport'; import { GetGroupCount } from '../../utilities/groupedList/GroupedListUtility'; import { DEFAULT_CELL_STYLE_PROPS } from './DetailsRow.styles'; var getClassNames = classNamesFunction(); var MIN_COLUMN_WIDTH = 100; // this is the global min width var CHECKBOX_WIDTH = 40; var GROUP_EXPAND_WIDTH = 36; var DEFAULT_RENDERED_WINDOWS_AHEAD = 2; var DEFAULT_RENDERED_WINDOWS_BEHIND = 2; var SHIMMER_INITIAL_ITEMS = 10; var SHIMMER_ITEMS = new Array(SHIMMER_INITIAL_ITEMS); var DetailsListBase = /** @class */ (function (_super) { tslib_1.__extends(DetailsListBase, _super); function DetailsListBase(props) { var _this = _super.call(this, props) || this; // References _this._root = createRef(); _this._header = createRef(); _this._groupedList = createRef(); _this._list = createRef(); _this._focusZone = createRef(); _this._selectionZone = createRef(); _this._onRenderRow = function (props, defaultRender) { return React.createElement(DetailsRow, tslib_1.__assign({}, props)); }; _this._onRenderDetailsHeader = function (detailsHeaderProps, defaultRender) { return React.createElement(DetailsHeader, tslib_1.__assign({}, detailsHeaderProps)); }; _this._onRenderDetailsFooter = function (detailsFooterProps, defaultRender) { return null; }; _this._onRenderListCell = function (nestingDepth) { return function (item, itemIndex) { return _this._onRenderCell(nestingDepth, item, itemIndex); }; }; _this._activeRows = {}; _this._columnOverrides = {}; _this._onColumnIsSizingChanged = _this._onColumnIsSizingChanged.bind(_this); _this._onColumnResized = _this._onColumnResized.bind(_this); _this._onColumnAutoResized = _this._onColumnAutoResized.bind(_this); _this._onRowDidMount = _this._onRowDidMount.bind(_this); _this._onRowWillUnmount = _this._onRowWillUnmount.bind(_this); _this._onToggleCollapse = _this._onToggleCollapse.bind(_this); _this._onActiveRowChanged = _this._onActiveRowChanged.bind(_this); _this._onBlur = _this._onBlur.bind(_this); _this._onHeaderKeyDown = _this._onHeaderKeyDown.bind(_this); _this._onContentKeyDown = _this._onContentKeyDown.bind(_this); _this._onRenderCell = _this._onRenderCell.bind(_this); _this._onGroupExpandStateChanged = _this._onGroupExpandStateChanged.bind(_this); _this._onColumnDragEnd = _this._onColumnDragEnd.bind(_this); _this.state = { focusedItemIndex: -1, lastWidth: 0, adjustedColumns: _this._getAdjustedColumns(props), isSizing: false, isDropping: false, isCollapsed: props.groupProps && props.groupProps.isAllGroupsCollapsed, isSomeGroupExpanded: props.groupProps && !props.groupProps.isAllGroupsCollapsed }; _this._selection = props.selection || new Selection({ onSelectionChanged: undefined, getKey: props.getKey }); if (!_this.props.disableSelectionZone) { _this._selection.setItems(props.items, false); } _this._dragDropHelper = props.dragDropEvents ? new DragDropHelper({ selection: _this._selection, minimumPixelsForDrag: props.minimumPixelsForDrag }) : null; _this._initialFocusedIndex = props.initialFocusedIndex; return _this; } DetailsListBase.prototype.scrollToIndex = function (index, measureItem, scrollToMode) { this._list.current && this._list.current.scrollToIndex(index, measureItem, scrollToMode); this._groupedList.current && this._groupedList.current.scrollToIndex(index, measureItem, scrollToMode); }; DetailsListBase.prototype.focusIndex = function (index, forceIntoFirstElement, measureItem, scrollToMode) { if (forceIntoFirstElement === void 0) { forceIntoFirstElement = false; } var item = this.props.items[index]; if (item) { this.scrollToIndex(index, measureItem, scrollToMode); var itemKey = this._getItemKey(item, index); var row = this._activeRows[itemKey]; if (row) { this._setFocusToRow(row, forceIntoFirstElement); } } }; DetailsListBase.prototype.getStartItemIndexInView = function () { if (this._list && this._list.current) { return this._list.current.getStartItemIndexInView(); } else if (this._groupedList && this._groupedList.current) { return this._groupedList.current.getStartItemIndexInView(); } return 0; }; DetailsListBase.prototype.componentWillUnmount = function () { if (this._dragDropHelper) { this._dragDropHelper.dispose(); } }; DetailsListBase.prototype.componentDidUpdate = function (prevProps, prevState) { if (this._initialFocusedIndex !== undefined) { var item = this.props.items[this._initialFocusedIndex]; if (item) { var itemKey = this._getItemKey(item, this._initialFocusedIndex); var row = this._activeRows[itemKey]; if (row) { this._setFocusToRowIfPending(row); } } } if (this.props.items !== prevProps.items && this.props.items.length > 0 && this.state.focusedItemIndex !== -1 && !elementContains(this._root.current, document.activeElement, false)) { // Item set has changed and previously-focused item is gone. // Set focus to item at index of previously-focused item if it is in range, // else set focus to the last item. var index = this.state.focusedItemIndex < this.props.items.length ? this.state.focusedItemIndex : this.props.items.length - 1; var item = this.props.items[index]; var itemKey = this._getItemKey(item, this.state.focusedItemIndex); var row = this._activeRows[itemKey]; if (row) { this._setFocusToRow(row); } else { this._initialFocusedIndex = index; } } if (this.props.onDidUpdate) { this.props.onDidUpdate(this); } }; DetailsListBase.prototype.componentWillReceiveProps = function (newProps) { var _a = this.props, checkboxVisibility = _a.checkboxVisibility, items = _a.items, setKey = _a.setKey, _b = _a.selectionMode, selectionMode = _b === void 0 ? this._selection.mode : _b, columns = _a.columns, viewport = _a.viewport, compact = _a.compact; var shouldResetSelection = newProps.setKey !== setKey || newProps.setKey === undefined; var shouldForceUpdates = false; if (newProps.layoutMode !== this.props.layoutMode) { shouldForceUpdates = true; } if (shouldResetSelection) { this._initialFocusedIndex = newProps.initialFocusedIndex; // reset focusedItemIndex when setKey changes this.setState({ focusedItemIndex: this._initialFocusedIndex !== undefined ? this._initialFocusedIndex : -1 }); } if (!this.props.disableSelectionZone && newProps.items !== items) { this._selection.setItems(newProps.items, shouldResetSelection); } if (newProps.checkboxVisibility !== checkboxVisibility || newProps.columns !== columns || newProps.viewport.width !== viewport.width || newProps.compact !== compact) { shouldForceUpdates = true; } this._adjustColumns(newProps, true); if (newProps.selectionMode !== selectionMode) { shouldForceUpdates = true; } if (shouldForceUpdates) { this._pendingForceUpdate = true; } }; DetailsListBase.prototype.componentWillUpdate = function () { if (this._pendingForceUpdate) { this._forceListUpdates(); } }; DetailsListBase.prototype.render = function () { var _a = this.props, ariaLabelForListHeader = _a.ariaLabelForListHeader, ariaLabelForSelectAllCheckbox = _a.ariaLabelForSelectAllCheckbox, ariaLabelForSelectionColumn = _a.ariaLabelForSelectionColumn, className = _a.className, checkboxVisibility = _a.checkboxVisibility, compact = _a.compact, constrainMode = _a.constrainMode, dragDropEvents = _a.dragDropEvents, groups = _a.groups, groupProps = _a.groupProps, indentWidth = _a.indentWidth, items = _a.items, isHeaderVisible = _a.isHeaderVisible, layoutMode = _a.layoutMode, onItemInvoked = _a.onItemInvoked, onItemContextMenu = _a.onItemContextMenu, onColumnHeaderClick = _a.onColumnHeaderClick, onColumnHeaderContextMenu = _a.onColumnHeaderContextMenu, _b = _a.selectionMode, selectionMode = _b === void 0 ? this._selection.mode : _b, selectionPreservedOnEmptyClick = _a.selectionPreservedOnEmptyClick, selectionZoneProps = _a.selectionZoneProps, ariaLabel = _a.ariaLabel, ariaLabelForGrid = _a.ariaLabelForGrid, rowElementEventMap = _a.rowElementEventMap, _c = _a.shouldApplyApplicationRole, shouldApplyApplicationRole = _c === void 0 ? false : _c, getKey = _a.getKey, listProps = _a.listProps, usePageCache = _a.usePageCache, onShouldVirtualize = _a.onShouldVirtualize, enableShimmer = _a.enableShimmer, viewport = _a.viewport, minimumPixelsForDrag = _a.minimumPixelsForDrag, getGroupHeight = _a.getGroupHeight, styles = _a.styles, theme = _a.theme, _d = _a.cellStyleProps, cellStyleProps = _d === void 0 ? DEFAULT_CELL_STYLE_PROPS : _d; var _e = this.state, adjustedColumns = _e.adjustedColumns, isCollapsed = _e.isCollapsed, isSizing = _e.isSizing, isSomeGroupExpanded = _e.isSomeGroupExpanded; var _f = this, selection = _f._selection, dragDropHelper = _f._dragDropHelper; var groupNestingDepth = this._getGroupNestingDepth(); var additionalListProps = tslib_1.__assign({ renderedWindowsAhead: isSizing ? 0 : DEFAULT_RENDERED_WINDOWS_AHEAD, renderedWindowsBehind: isSizing ? 0 : DEFAULT_RENDERED_WINDOWS_BEHIND, getKey: getKey }, listProps); var selectAllVisibility = SelectAllVisibility.none; // for SelectionMode.none if (selectionMode === SelectionMode.single) { selectAllVisibility = SelectAllVisibility.hidden; } if (selectionMode === SelectionMode.multiple) { // if isCollapsedGroupSelectVisible is false, disable select all when the list has all collapsed groups var isCollapsedGroupSelectVisible = groupProps && groupProps.headerProps && groupProps.headerProps.isCollapsedGroupSelectVisible; if (isCollapsedGroupSelectVisible === undefined) { isCollapsedGroupSelectVisible = true; } var isSelectAllVisible = isCollapsedGroupSelectVisible || !groups || isSomeGroupExpanded; selectAllVisibility = isSelectAllVisible ? SelectAllVisibility.visible : SelectAllVisibility.hidden; } if (checkboxVisibility === CheckboxVisibility.hidden) { selectAllVisibility = SelectAllVisibility.none; } var _g = this.props, _h = _g.onRenderDetailsHeader, onRenderDetailsHeader = _h === void 0 ? this._onRenderDetailsHeader : _h, _j = _g.onRenderDetailsFooter, onRenderDetailsFooter = _j === void 0 ? this._onRenderDetailsFooter : _j; var detailsFooterProps = this._getDetailsFooterProps(); var columnReorderProps = this._getColumnReorderProps(); var rowCount = (isHeaderVisible ? 1 : 0) + GetGroupCount(groups) + (items ? items.length : 0); var classNames = getClassNames(styles, { theme: theme, compact: compact, isFixed: layoutMode === DetailsListLayoutMode.fixedColumns, isHorizontalConstrained: constrainMode === ConstrainMode.horizontalConstrained, className: className }); var list = groups ? (React.createElement(GroupedList, { componentRef: this._groupedList, groups: groups, groupProps: groupProps ? this._getGroupProps(groupProps) : undefined, items: items, onRenderCell: this._onRenderCell, selection: selection, selectionMode: checkboxVisibility !== CheckboxVisibility.hidden ? selectionMode : SelectionMode.none, dragDropEvents: dragDropEvents, dragDropHelper: dragDropHelper, eventsToRegister: rowElementEventMap, listProps: additionalListProps, onGroupExpandStateChanged: this._onGroupExpandStateChanged, usePageCache: usePageCache, onShouldVirtualize: onShouldVirtualize, getGroupHeight: getGroupHeight })) : (React.createElement(List, tslib_1.__assign({ ref: this._list, role: "presentation", items: enableShimmer && !items.length ? SHIMMER_ITEMS : items, onRenderCell: this._onRenderListCell(0), usePageCache: usePageCache, onShouldVirtualize: onShouldVirtualize }, additionalListProps))); return ( // If shouldApplyApplicationRole is true, role application will be applied to make arrow keys work // with JAWS. React.createElement("div", tslib_1.__assign({ ref: this._root, className: classNames.root, "data-automationid": "DetailsList", "data-is-scrollable": "false", "aria-label": ariaLabel }, (shouldApplyApplicationRole ? { role: 'application' } : {})), React.createElement("div", { role: "grid", "aria-label": ariaLabelForGrid, "aria-rowcount": rowCount, "aria-colcount": (selectAllVisibility !== SelectAllVisibility.none ? 1 : 0) + (adjustedColumns ? adjustedColumns.length : 0), "aria-readonly": "true" }, React.createElement("div", { onKeyDown: this._onHeaderKeyDown, role: "presentation" }, isHeaderVisible && onRenderDetailsHeader({ componentRef: this._header, selectionMode: selectionMode, layoutMode: layoutMode, selection: selection, columns: adjustedColumns, onColumnClick: onColumnHeaderClick, onColumnContextMenu: onColumnHeaderContextMenu, onColumnResized: this._onColumnResized, onColumnIsSizingChanged: this._onColumnIsSizingChanged, onColumnAutoResized: this._onColumnAutoResized, groupNestingDepth: groupNestingDepth, isAllCollapsed: isCollapsed, onToggleCollapseAll: this._onToggleCollapse, ariaLabel: ariaLabelForListHeader, ariaLabelForSelectAllCheckbox: ariaLabelForSelectAllCheckbox, ariaLabelForSelectionColumn: ariaLabelForSelectionColumn, selectAllVisibility: selectAllVisibility, collapseAllVisibility: groupProps && groupProps.collapseAllVisibility, viewport: viewport, columnReorderProps: columnReorderProps, minimumPixelsForDrag: minimumPixelsForDrag, cellStyleProps: cellStyleProps, checkboxVisibility: checkboxVisibility, indentWidth: indentWidth }, this._onRenderDetailsHeader)), React.createElement("div", { onKeyDown: this._onContentKeyDown, role: "presentation" }, React.createElement(FocusZone, { componentRef: this._focusZone, className: classNames.focusZone, direction: FocusZoneDirection.vertical, isInnerZoneKeystroke: isRightArrow, onActiveElementChanged: this._onActiveRowChanged, onBlur: this._onBlur }, !this.props.disableSelectionZone ? (React.createElement(SelectionZone, tslib_1.__assign({ ref: this._selectionZone, selection: selection, selectionPreservedOnEmptyClick: selectionPreservedOnEmptyClick, selectionMode: selectionMode, onItemInvoked: onItemInvoked, onItemContextMenu: onItemContextMenu, enterModalOnTouch: this.props.enterModalSelectionOnTouch }, selectionZoneProps || {}), list)) : (list))), onRenderDetailsFooter(tslib_1.__assign({}, detailsFooterProps), this._onRenderDetailsFooter)))); }; DetailsListBase.prototype.forceUpdate = function () { _super.prototype.forceUpdate.call(this); this._forceListUpdates(); }; DetailsListBase.prototype._onRenderCell = function (nestingDepth, item, index) { var _a = this.props, compact = _a.compact, dragDropEvents = _a.dragDropEvents, eventsToRegister = _a.rowElementEventMap, onRenderMissingItem = _a.onRenderMissingItem, onRenderItemColumn = _a.onRenderItemColumn, _b = _a.onRenderRow, onRenderRow = _b === void 0 ? this._onRenderRow : _b, _c = _a.selectionMode, selectionMode = _c === void 0 ? this._selection.mode : _c, viewport = _a.viewport, checkboxVisibility = _a.checkboxVisibility, getRowAriaLabel = _a.getRowAriaLabel, getRowAriaDescribedBy = _a.getRowAriaDescribedBy, checkButtonAriaLabel = _a.checkButtonAriaLabel, checkboxCellClassName = _a.checkboxCellClassName, groupProps = _a.groupProps, useReducedRowRenderer = _a.useReducedRowRenderer, indentWidth = _a.indentWidth, _d = _a.cellStyleProps, cellStyleProps = _d === void 0 ? DEFAULT_CELL_STYLE_PROPS : _d; var collapseAllVisibility = groupProps && groupProps.collapseAllVisibility; var selection = this._selection; var dragDropHelper = this._dragDropHelper; var columns = this.state.adjustedColumns; var rowProps = { item: item, itemIndex: index, compact: compact, columns: columns, groupNestingDepth: nestingDepth, selectionMode: selectionMode, selection: selection, onDidMount: this._onRowDidMount, onWillUnmount: this._onRowWillUnmount, onRenderItemColumn: onRenderItemColumn, eventsToRegister: eventsToRegister, dragDropEvents: dragDropEvents, dragDropHelper: dragDropHelper, viewport: viewport, checkboxVisibility: checkboxVisibility, collapseAllVisibility: collapseAllVisibility, getRowAriaLabel: getRowAriaLabel, getRowAriaDescribedBy: getRowAriaDescribedBy, checkButtonAriaLabel: checkButtonAriaLabel, checkboxCellClassName: checkboxCellClassName, useReducedRowRenderer: useReducedRowRenderer, indentWidth: indentWidth, cellStyleProps: cellStyleProps }; if (!item) { if (onRenderMissingItem) { return onRenderMissingItem(index, rowProps); } return null; } return onRenderRow(rowProps, this._onRenderRow); }; DetailsListBase.prototype._onGroupExpandStateChanged = function (isSomeGroupExpanded) { this.setState({ isSomeGroupExpanded: isSomeGroupExpanded }); }; DetailsListBase.prototype._onColumnIsSizingChanged = function (column, isSizing) { this.setState({ isSizing: isSizing }); }; DetailsListBase.prototype._onHeaderKeyDown = function (ev) { if (ev.which === 40 /* down */) { if (this._focusZone.current && this._focusZone.current.focus()) { // select the first item in list after down arrow key event this._selection.setIndexSelected(0, true, false); ev.preventDefault(); ev.stopPropagation(); } } }; DetailsListBase.prototype._onContentKeyDown = function (ev) { if (ev.which === 38 /* up */ && !ev.altKey) { if (this._header.current && this._header.current.focus()) { ev.preventDefault(); ev.stopPropagation(); } } }; DetailsListBase.prototype._getGroupNestingDepth = function () { var groups = this.props.groups; var level = 0; var groupsInLevel = groups; while (groupsInLevel && groupsInLevel.length > 0) { level++; groupsInLevel = groupsInLevel[0].children; } return level; }; DetailsListBase.prototype._onRowDidMount = function (row) { var _a = row.props, item = _a.item, itemIndex = _a.itemIndex; var itemKey = this._getItemKey(item, itemIndex); this._activeRows[itemKey] = row; // this is used for column auto resize this._setFocusToRowIfPending(row); var onRowDidMount = this.props.onRowDidMount; if (onRowDidMount) { onRowDidMount(item, itemIndex); } }; DetailsListBase.prototype._setFocusToRowIfPending = function (row) { var itemIndex = row.props.itemIndex; if (this._initialFocusedIndex !== undefined && itemIndex === this._initialFocusedIndex) { this._setFocusToRow(row); delete this._initialFocusedIndex; } }; DetailsListBase.prototype._setFocusToRow = function (row, forceIntoFirstElement) { if (forceIntoFirstElement === void 0) { forceIntoFirstElement = false; } if (this._selectionZone.current) { this._selectionZone.current.ignoreNextFocus(); } this._async.setTimeout(function () { row.focus(forceIntoFirstElement); }, 0); }; DetailsListBase.prototype._onRowWillUnmount = function (row) { var onRowWillUnmount = this.props.onRowWillUnmount; var _a = row.props, item = _a.item, itemIndex = _a.itemIndex; var itemKey = this._getItemKey(item, itemIndex); delete this._activeRows[itemKey]; if (onRowWillUnmount) { onRowWillUnmount(item, itemIndex); } }; DetailsListBase.prototype._onToggleCollapse = function (collapsed) { this.setState({ isCollapsed: collapsed }); if (this._groupedList.current) { this._groupedList.current.toggleCollapseAll(collapsed); } }; DetailsListBase.prototype._onColumnDragEnd = function (props, event) { var columnReorderOptions = this.props.columnReorderOptions; var finalDropLocation = ColumnDragEndLocation.outside; if (columnReorderOptions && columnReorderOptions.onDragEnd) { if (props.dropLocation && props.dropLocation !== ColumnDragEndLocation.header) { finalDropLocation = props.dropLocation; } else if (this._root.current) { var clientRect = this._root.current.getBoundingClientRect(); if (event.clientX > clientRect.left && event.clientX < clientRect.right && event.clientY > clientRect.top && event.clientY < clientRect.bottom) { finalDropLocation = ColumnDragEndLocation.surface; } } columnReorderOptions.onDragEnd(finalDropLocation); } }; DetailsListBase.prototype._forceListUpdates = function () { this._pendingForceUpdate = false; if (this._groupedList.current) { this._groupedList.current.forceUpdate(); } if (this._list.current) { this._list.current.forceUpdate(); } }; DetailsListBase.prototype._adjustColumns = function (newProps, forceUpdate, resizingColumnIndex) { var adjustedColumns = this._getAdjustedColumns(newProps, forceUpdate, resizingColumnIndex); var viewportWidth = this.props.viewport.width; if (adjustedColumns) { this.setState({ adjustedColumns: adjustedColumns, lastWidth: viewportWidth }); } }; /** Returns adjusted columns, given the viewport size and layout mode. */ DetailsListBase.prototype._getAdjustedColumns = function (newProps, forceUpdate, resizingColumnIndex) { var _this = this; var newItems = newProps.items, layoutMode = newProps.layoutMode, selectionMode = newProps.selectionMode; var newColumns = newProps.columns; var viewportWidth = newProps.viewport.width; var columns = this.props ? this.props.columns : []; var lastWidth = this.state ? this.state.lastWidth : -1; var lastSelectionMode = this.state ? this.state.lastSelectionMode : undefined; if (viewportWidth !== undefined) { if (!forceUpdate && lastWidth === viewportWidth && lastSelectionMode === selectionMode && (!columns || newColumns === columns)) { return []; } } else { viewportWidth = this.props.viewport.width; } newColumns = newColumns || buildColumns(newItems, true); var adjustedColumns; if (layoutMode === DetailsListLayoutMode.fixedColumns) { adjustedColumns = this._getFixedColumns(newColumns); // Preserve adjusted column calculated widths. adjustedColumns.forEach(function (column) { _this._rememberCalculatedWidth(column, column.calculatedWidth); }); } else { if (resizingColumnIndex !== undefined) { adjustedColumns = this._getJustifiedColumnsAfterResize(newColumns, viewportWidth, newProps, resizingColumnIndex); } else { adjustedColumns = this._getJustifiedColumns(newColumns, viewportWidth, newProps, 0); } adjustedColumns.forEach(function (column) { _this._getColumnOverride(column.key).currentWidth = column.calculatedWidth; }); } return adjustedColumns; }; /** Builds a set of columns based on the given columns mixed with the current overrides. */ DetailsListBase.prototype._getFixedColumns = function (newColumns) { var _this = this; return newColumns.map(function (column) { var newColumn = assign({}, column, _this._columnOverrides[column.key]); if (!newColumn.calculatedWidth) { newColumn.calculatedWidth = newColumn.maxWidth || newColumn.minWidth || MIN_COLUMN_WIDTH; } return newColumn; }); }; DetailsListBase.prototype._getJustifiedColumnsAfterResize = function (newColumns, viewportWidth, props, resizingColumnIndex) { var _this = this; var fixedColumns = newColumns.slice(0, resizingColumnIndex); fixedColumns.forEach(function (column) { return (column.calculatedWidth = _this._getColumnOverride(column.key).currentWidth); }); var fixedWidth = fixedColumns.reduce(function (total, column, i) { return total + getPaddedWidth(column, i === 0, props); }, 0); var remainingColumns = newColumns.slice(resizingColumnIndex); var remainingWidth = viewportWidth - fixedWidth; return fixedColumns.concat(this._getJustifiedColumns(remainingColumns, remainingWidth, props, resizingColumnIndex)); }; /** Builds a set of columns to fix within the viewport width. */ DetailsListBase.prototype._getJustifiedColumns = function (newColumns, viewportWidth, props, firstIndex) { var _this = this; var _a = props.selectionMode, selectionMode = _a === void 0 ? this._selection.mode : _a, checkboxVisibility = props.checkboxVisibility; var rowCheckWidth = selectionMode !== SelectionMode.none && checkboxVisibility !== CheckboxVisibility.hidden ? CHECKBOX_WIDTH : 0; var groupExpandWidth = this._getGroupNestingDepth() * GROUP_EXPAND_WIDTH; var totalWidth = 0; // offset because we have one less inner padding. var availableWidth = viewportWidth - (rowCheckWidth + groupExpandWidth); var adjustedColumns = newColumns.map(function (column, i) { var newColumn = tslib_1.__assign({}, column, { calculatedWidth: column.minWidth || MIN_COLUMN_WIDTH }, _this._columnOverrides[column.key]); var isFirst = i + firstIndex === 0; totalWidth += getPaddedWidth(newColumn, isFirst, props); return newColumn; }); var lastIndex = adjustedColumns.length - 1; // Shrink or remove collapsable columns. while (lastIndex > 0 && totalWidth > availableWidth) { var column = adjustedColumns[lastIndex]; var minWidth = column.minWidth || MIN_COLUMN_WIDTH; var overflowWidth = totalWidth - availableWidth; if (column.calculatedWidth - minWidth >= overflowWidth || !column.isCollapsable) { column.calculatedWidth = Math.max(column.calculatedWidth - overflowWidth, minWidth); totalWidth = availableWidth; } else { totalWidth -= getPaddedWidth(column, false, props); adjustedColumns.splice(lastIndex, 1); } lastIndex--; } // Then expand columns starting at the beginning, until we've filled the width. for (var i = 0; i < adjustedColumns.length && totalWidth < availableWidth; i++) { var column = adjustedColumns[i]; var isLast = i === adjustedColumns.length - 1; var overrides = this._columnOverrides[column.key]; if (overrides && overrides.calculatedWidth && !isLast) { continue; } var spaceLeft = availableWidth - totalWidth; var increment = void 0; if (isLast) { increment = spaceLeft; } else { var maxWidth = column.maxWidth; var minWidth = column.minWidth || maxWidth || MIN_COLUMN_WIDTH; increment = maxWidth ? Math.min(spaceLeft, maxWidth - minWidth) : spaceLeft; } column.calculatedWidth = column.calculatedWidth + increment; totalWidth += increment; } return adjustedColumns; }; DetailsListBase.prototype._onColumnResized = function (resizingColumn, newWidth, resizingColumnIndex) { var newCalculatedWidth = Math.max(resizingColumn.minWidth || MIN_COLUMN_WIDTH, newWidth); if (this.props.onColumnResize) { this.props.onColumnResize(resizingColumn, newCalculatedWidth, resizingColumnIndex); } this._rememberCalculatedWidth(resizingColumn, newCalculatedWidth); this._adjustColumns(this.props, true, resizingColumnIndex); this._forceListUpdates(); }; DetailsListBase.prototype._rememberCalculatedWidth = function (column, newCalculatedWidth) { var overrides = this._getColumnOverride(column.key); overrides.calculatedWidth = newCalculatedWidth; overrides.currentWidth = newCalculatedWidth; }; DetailsListBase.prototype._getColumnOverride = function (key) { return (this._columnOverrides[key] = this._columnOverrides[key] || {}); }; /** * Callback function when double clicked on the details header column resizer * which will measure the column cells of all the active rows and resize the * column to the max cell width. * * @private * @param {IColumn} column (double clicked column definition) * @param {number} columnIndex (double clicked column index) * @todo min width 100 should be changed to const value and should be consistent with the value used on _onSizerMove method in DetailsHeader */ DetailsListBase.prototype._onColumnAutoResized = function (column, columnIndex) { var _this = this; var max = 0; var count = 0; var totalCount = Object.keys(this._activeRows).length; for (var key in this._activeRows) { if (this._activeRows.hasOwnProperty(key)) { var currentRow = this._activeRows[key]; currentRow.measureCell(columnIndex, function (width) { max = Math.max(max, width); count++; if (count === totalCount) { _this._onColumnResized(column, max, columnIndex); } }); } } }; /** * Call back function when an element in FocusZone becomes active. It will translate it into item * and call onActiveItemChanged callback if specified. * * @private * @param {el} row element that became active in Focus Zone * @param {ev} focus event from Focus Zone */ DetailsListBase.prototype._onActiveRowChanged = function (el, ev) { var _a = this.props, items = _a.items, onActiveItemChanged = _a.onActiveItemChanged; if (!el) { return; } // Check and assign index only if the event was raised from any DetailsRow element if (el.getAttribute('data-item-index')) { var index = Number(el.getAttribute('data-item-index')); if (index >= 0) { if (onActiveItemChanged) { onActiveItemChanged(items[index], index, ev); } this.setState({ focusedItemIndex: index }); } } }; DetailsListBase.prototype._onBlur = function (event) { this.setState({ focusedItemIndex: -1 }); }; DetailsListBase.prototype._getItemKey = function (item, itemIndex) { var getKey = this.props.getKey; var itemKey = undefined; if (item) { itemKey = item.key; } if (getKey) { itemKey = getKey(item, itemIndex); } if (!itemKey) { itemKey = itemIndex; } return itemKey; }; DetailsListBase.prototype._getDetailsFooterProps = function () { var columns = this.state.adjustedColumns; var _a = this.props, viewport = _a.viewport, checkboxVisibility = _a.checkboxVisibility, indentWidth = _a.indentWidth, _b = _a.cellStyleProps, cellStyleProps = _b === void 0 ? DEFAULT_CELL_STYLE_PROPS : _b, _c = _a.selectionMode, selectionMode = _c === void 0 ? this._selection.mode : _c; return { columns: columns, groupNestingDepth: this._getGroupNestingDepth(), selection: this._selection, selectionMode: selectionMode, viewport: viewport, checkboxVisibility: checkboxVisibility, indentWidth: indentWidth, cellStyleProps: cellStyleProps }; }; DetailsListBase.prototype._getColumnReorderProps = function () { var columnReorderOptions = this.props.columnReorderOptions; if (columnReorderOptions) { return tslib_1.__assign({}, columnReorderOptions, { onColumnDragEnd: this._onColumnDragEnd }); } }; DetailsListBase.prototype._getGroupProps = function (detailsGroupProps) { var _this = this; var onRenderDetailsGroupFooter = detailsGroupProps.onRenderFooter, onRenderDetailsGroupHeader = detailsGroupProps.onRenderHeader; var columns = this.state.adjustedColumns; var _a = this.props, _b = _a.selectionMode, selectionMode = _b === void 0 ? this._selection.mode : _b, viewport = _a.viewport, _c = _a.cellStyleProps, cellStyleProps = _c === void 0 ? DEFAULT_CELL_STYLE_PROPS : _c, checkboxVisibility = _a.checkboxVisibility, indentWidth = _a.indentWidth; var groupNestingDepth = this._getGroupNestingDepth(); var onRenderFooter = onRenderDetailsGroupFooter ? function (props, defaultRender) { return onRenderDetailsGroupFooter(tslib_1.__assign({}, props, { columns: columns, groupNestingDepth: groupNestingDepth, indentWidth: indentWidth, selection: _this._selection, selectionMode: selectionMode, viewport: viewport, checkboxVisibility: checkboxVisibility, cellStyleProps: cellStyleProps }), defaultRender); } : undefined; var onRenderHeader = onRenderDetailsGroupHeader ? function (props, defaultRender) { return onRenderDetailsGroupHeader(tslib_1.__assign({}, props, { columns: columns, groupNestingDepth: groupNestingDepth, indentWidth: indentWidth, selection: _this._selection, selectionMode: selectionMode, viewport: viewport, checkboxVisibility: checkboxVisibility, cellStyleProps: cellStyleProps }), defaultRender); } : undefined; var groupProps = detailsGroupProps; return tslib_1.__assign({}, groupProps, { onRenderFooter: onRenderFooter, onRenderHeader: onRenderHeader }); }; DetailsListBase.defaultProps = { layoutMode: DetailsListLayoutMode.justified, selectionMode: SelectionMode.multiple, constrainMode: ConstrainMode.horizontalConstrained, checkboxVisibility: CheckboxVisibility.onHover, isHeaderVisible: true, enableShimmer: false }; DetailsListBase = tslib_1.__decorate([ withViewport ], DetailsListBase); return DetailsListBase; }(BaseComponent)); export { DetailsListBase }; export function buildColumns(items, canResizeColumns, onColumnClick, sortedColumnKey, isSortedDescending, groupedColumnKey, isMultiline) { var columns = []; if (items && items.length) { var firstItem = items[0]; for (var propName in firstItem) { if (firstItem.hasOwnProperty(propName)) { columns.push({ key: propName, name: propName, fieldName: propName, minWidth: MIN_COLUMN_WIDTH, maxWidth: 300, isCollapsable: !!columns.length, isMultiline: isMultiline === undefined ? false : isMultiline, isSorted: sortedColumnKey === propName, isSortedDescending: !!isSortedDescending, isRowHeader: false, columnActionsMode: ColumnActionsMode.clickable, isResizable: canResizeColumns, onColumnClick: onColumnClick, isGrouped: groupedColumnKey === propName }); } } } return columns; } function isRightArrow(event) { return event.which === getRTLSafeKeyCode(39 /* right */); } function getPaddedWidth(column, isFirst, props) { var _a = props.cellStyleProps, cellStyleProps = _a === void 0 ? DEFAULT_CELL_STYLE_PROPS : _a; return (column.calculatedWidth + cellStyleProps.cellLeftPadding + cellStyleProps.cellRightPadding + (column.isPadded ? cellStyleProps.cellExtraRightPadding : 0)); } //# sourceMappingURL=DetailsList.base.js.map