office-ui-fabric-react
Version:
Reusable React components for building experiences for Office 365.
1 lines • 18.9 kB
JavaScript
module.exports = "import * as React from 'react';\r\nimport {\r\n CheckboxVisibility,\r\n ColumnActionsMode,\r\n CommandBar,\r\n ConstrainMode,\r\n ContextualMenu,\r\n DetailsList,\r\n DetailsListLayoutMode as LayoutMode,\r\n DirectionalHint,\r\n IColumn,\r\n IContextualMenuItem,\r\n IContextualMenuProps,\r\n IGroup,\r\n Link,\r\n Selection,\r\n TextField,\r\n autobind,\r\n buildColumns\r\n} from '../../../../index';\r\nimport { SelectionMode } from '../../../../utilities/selection/interfaces';\r\nimport { createListItems, isGroupable } from '../../../utilities/data';\r\nimport './DetailsList.Advanced.Example.scss';\r\n\r\nconst DEFAULT_ITEM_LIMIT = 5;\r\nconst PAGING_SIZE = 10;\r\nconst PAGING_DELAY = 5000;\r\nconst ITEMS_COUNT = 5000;\r\n\r\nlet _items;\r\n\r\nexport interface IDetailsListAdvancedExampleState {\r\n canResizeColumns?: boolean;\r\n checkboxVisibility?: CheckboxVisibility;\r\n columns?: IColumn[];\r\n constrainMode?: ConstrainMode;\r\n contextualMenuProps?: IContextualMenuProps;\r\n groupItemLimit?: number;\r\n groups?: IGroup[];\r\n isHeaderVisible?: boolean;\r\n isLazyLoaded?: boolean;\r\n isSortedDescending?: boolean;\r\n items?: any[];\r\n layoutMode?: LayoutMode;\r\n selectionMode?: SelectionMode;\r\n sortedColumnKey?: string;\r\n}\r\n\r\nexport class DetailsListAdvancedExample extends React.Component<any, IDetailsListAdvancedExampleState> {\r\n public refs: {\r\n [key: string]: React.ReactInstance;\r\n list: DetailsList\r\n };\r\n\r\n private _isFetchingItems: boolean;\r\n private _selection: Selection;\r\n\r\n constructor() {\r\n super();\r\n\r\n if (!_items) {\r\n _items = createListItems(ITEMS_COUNT);\r\n }\r\n\r\n this._selection = new Selection();\r\n this._selection.setItems(_items, false);\r\n\r\n this.state = {\r\n items: _items,\r\n groups: null,\r\n groupItemLimit: DEFAULT_ITEM_LIMIT,\r\n layoutMode: LayoutMode.justified,\r\n constrainMode: ConstrainMode.horizontalConstrained,\r\n selectionMode: SelectionMode.multiple,\r\n canResizeColumns: true,\r\n checkboxVisibility: CheckboxVisibility.onHover,\r\n columns: this._buildColumns(_items, true, this._onColumnClick, ''),\r\n contextualMenuProps: null,\r\n sortedColumnKey: 'name',\r\n isSortedDescending: false,\r\n isLazyLoaded: false,\r\n isHeaderVisible: true\r\n };\r\n }\r\n\r\n public render() {\r\n let {\r\n checkboxVisibility,\r\n columns,\r\n constrainMode,\r\n contextualMenuProps,\r\n groupItemLimit,\r\n groups,\r\n isHeaderVisible,\r\n items,\r\n layoutMode,\r\n selectionMode\r\n } = this.state;\r\n\r\n let isGrouped = groups && groups.length > 0;\r\n let groupProps = {\r\n getGroupItemLimit: (group: IGroup) => {\r\n if (group) {\r\n return group.isShowingAll ? group.count : Math.min(group.count, groupItemLimit);\r\n } else {\r\n return items.length;\r\n }\r\n },\r\n footerProps: {\r\n showAllLinkText: 'Show all'\r\n }\r\n };\r\n\r\n return (\r\n <div className='ms-DetailsListAdvancedExample'>\r\n <CommandBar items={ this._getCommandItems() } />\r\n\r\n {\r\n (isGrouped) ?\r\n <TextField label='Group Item Limit' onChanged={ this._onItemLimitChanged } /> :\r\n (null)\r\n }\r\n\r\n <DetailsList\r\n ref='list'\r\n setKey='items'\r\n items={ items }\r\n groups={ groups }\r\n columns={ columns }\r\n checkboxVisibility={ checkboxVisibility }\r\n layoutMode={ layoutMode }\r\n isHeaderVisible={ isHeaderVisible }\r\n selectionMode={ selectionMode }\r\n constrainMode={ constrainMode }\r\n groupProps={ groupProps }\r\n onItemInvoked={ this._onItemInvoked }\r\n ariaLabelForListHeader='Column headers. Use menus to perform column operations like sort and filter'\r\n ariaLabelForSelectAllCheckbox='Toggle selection for all items'\r\n onRenderMissingItem={ (index) => {\r\n this._onDataMiss(index);\r\n return null;\r\n } }\r\n />\r\n\r\n { contextualMenuProps && (\r\n <ContextualMenu { ...contextualMenuProps } />\r\n ) }\r\n </div>\r\n );\r\n }\r\n\r\n private _onDataMiss(index) {\r\n index = Math.floor(index / PAGING_SIZE) * PAGING_SIZE;\r\n\r\n if (!this._isFetchingItems) {\r\n\r\n this._isFetchingItems = true;\r\n\r\n setTimeout(() => {\r\n this._isFetchingItems = false;\r\n let itemsCopy = [].concat(this.state.items);\r\n\r\n itemsCopy.splice.apply(itemsCopy, [index, PAGING_SIZE].concat(_items.slice(index, index + PAGING_SIZE)));\r\n\r\n this.setState({\r\n items: itemsCopy\r\n });\r\n }, PAGING_DELAY);\r\n }\r\n }\r\n\r\n @autobind\r\n private _onToggleLazyLoad() {\r\n let { isLazyLoaded } = this.state;\r\n\r\n isLazyLoaded = !isLazyLoaded;\r\n\r\n this.setState({\r\n isLazyLoaded: isLazyLoaded,\r\n items: isLazyLoaded ? _items.slice(0, PAGING_SIZE).concat(new Array(ITEMS_COUNT - PAGING_SIZE)) : _items\r\n });\r\n }\r\n\r\n @autobind\r\n private _onToggleResizing() {\r\n let { items, canResizeColumns, sortedColumnKey, isSortedDescending } = this.state;\r\n\r\n canResizeColumns = !canResizeColumns;\r\n\r\n this.setState({\r\n canResizeColumns: canResizeColumns,\r\n columns: this._buildColumns(items, canResizeColumns, this._onColumnClick, sortedColumnKey, isSortedDescending)\r\n });\r\n }\r\n\r\n @autobind\r\n private _onLayoutChanged(ev: React.MouseEvent<HTMLElement>, menuItem: IContextualMenuItem) {\r\n this.setState({\r\n layoutMode: menuItem.data\r\n });\r\n }\r\n\r\n @autobind\r\n private _onConstrainModeChanged(ev: React.MouseEvent<HTMLElement>, menuItem: IContextualMenuItem) {\r\n this.setState({\r\n constrainMode: menuItem.data\r\n });\r\n }\r\n\r\n @autobind\r\n private _onSelectionChanged(ev: React.MouseEvent<HTMLElement>, menuItem: IContextualMenuItem) {\r\n this.setState({\r\n selectionMode: menuItem.data\r\n });\r\n }\r\n\r\n @autobind\r\n private _onItemLimitChanged(value: string) {\r\n let newValue = parseInt(value, 10);\r\n if (isNaN(newValue)) {\r\n newValue = DEFAULT_ITEM_LIMIT;\r\n }\r\n this.setState({\r\n groupItemLimit: newValue\r\n });\r\n }\r\n\r\n private _getCommandItems(): IContextualMenuItem[] {\r\n let {\r\n canResizeColumns,\r\n checkboxVisibility,\r\n constrainMode,\r\n isHeaderVisible,\r\n isLazyLoaded,\r\n layoutMode,\r\n selectionMode\r\n } = this.state;\r\n\r\n return [\r\n {\r\n key: 'addRow',\r\n name: 'Insert row',\r\n icon: 'Add',\r\n onClick: this._onAddRow\r\n },\r\n {\r\n key: 'deleteRow',\r\n name: 'Delete row',\r\n icon: 'Delete',\r\n onClick: this._onDeleteRow\r\n },\r\n {\r\n key: 'configure',\r\n name: 'Configure',\r\n icon: 'Settings',\r\n items: [\r\n {\r\n key: 'resizing',\r\n name: 'Allow column resizing',\r\n canCheck: true,\r\n checked: canResizeColumns,\r\n onClick: this._onToggleResizing\r\n },\r\n {\r\n key: 'headerVisible',\r\n name: 'Is header visible',\r\n canCheck: true,\r\n checked: isHeaderVisible,\r\n onClick: () => this.setState({ isHeaderVisible: !isHeaderVisible })\r\n },\r\n {\r\n key: 'lazyload',\r\n name: 'Simulate async loading',\r\n canCheck: true,\r\n checked: isLazyLoaded,\r\n onClick: this._onToggleLazyLoad\r\n },\r\n {\r\n key: 'dash',\r\n name: '-'\r\n },\r\n {\r\n key: 'checkboxVisibility',\r\n name: 'Checkbox visibility',\r\n items: [\r\n {\r\n key: 'checkboxVisibility.always',\r\n name: 'Always',\r\n canCheck: true,\r\n isChecked: checkboxVisibility === CheckboxVisibility.always,\r\n onClick: () => this.setState({ checkboxVisibility: CheckboxVisibility.always })\r\n },\r\n {\r\n key: 'checkboxVisibility.onHover',\r\n name: 'On hover',\r\n canCheck: true,\r\n isChecked: checkboxVisibility === CheckboxVisibility.onHover,\r\n onClick: () => this.setState({ checkboxVisibility: CheckboxVisibility.onHover })\r\n },\r\n {\r\n key: 'checkboxVisibility.hidden',\r\n name: 'Hidden',\r\n canCheck: true,\r\n isChecked: checkboxVisibility === CheckboxVisibility.hidden,\r\n onClick: () => this.setState({ checkboxVisibility: CheckboxVisibility.hidden })\r\n },\r\n ]\r\n },\r\n {\r\n key: 'layoutMode',\r\n name: 'Layout mode',\r\n items: [\r\n {\r\n key: LayoutMode[LayoutMode.fixedColumns],\r\n name: 'Fixed columns',\r\n canCheck: true,\r\n checked: layoutMode === LayoutMode.fixedColumns,\r\n onClick: this._onLayoutChanged,\r\n data: LayoutMode.fixedColumns\r\n },\r\n {\r\n key: LayoutMode[LayoutMode.justified],\r\n name: 'Justified columns',\r\n canCheck: true,\r\n checked: layoutMode === LayoutMode.justified,\r\n onClick: this._onLayoutChanged,\r\n data: LayoutMode.justified\r\n }\r\n ]\r\n },\r\n {\r\n key: 'selectionMode',\r\n name: 'Selection mode',\r\n items: [\r\n {\r\n key: SelectionMode[SelectionMode.none],\r\n name: 'None',\r\n canCheck: true,\r\n checked: selectionMode === SelectionMode.none,\r\n onClick: this._onSelectionChanged,\r\n data: SelectionMode.none\r\n\r\n },\r\n {\r\n key: SelectionMode[SelectionMode.single],\r\n name: 'Single select',\r\n canCheck: true,\r\n checked: selectionMode === SelectionMode.single,\r\n onClick: this._onSelectionChanged,\r\n data: SelectionMode.single\r\n },\r\n {\r\n key: SelectionMode[SelectionMode.multiple],\r\n name: 'Multi select',\r\n canCheck: true,\r\n checked: selectionMode === SelectionMode.multiple,\r\n onClick: this._onSelectionChanged,\r\n data: SelectionMode.multiple\r\n },\r\n ]\r\n },\r\n {\r\n key: 'constrainMode',\r\n name: 'Constrain mode',\r\n items: [\r\n {\r\n key: ConstrainMode[ConstrainMode.unconstrained],\r\n name: 'Unconstrained',\r\n canCheck: true,\r\n checked: constrainMode === ConstrainMode.unconstrained,\r\n onClick: this._onConstrainModeChanged,\r\n data: ConstrainMode.unconstrained\r\n },\r\n {\r\n key: ConstrainMode[ConstrainMode.horizontalConstrained],\r\n name: 'Horizontal constrained',\r\n canCheck: true,\r\n checked: constrainMode === ConstrainMode.horizontalConstrained,\r\n onClick: this._onConstrainModeChanged,\r\n data: ConstrainMode.horizontalConstrained\r\n }\r\n ]\r\n }\r\n ]\r\n }\r\n ];\r\n }\r\n\r\n private _getContextualMenuProps(ev: React.MouseEvent<HTMLElement>, column: IColumn): IContextualMenuProps {\r\n let items = [\r\n {\r\n key: 'aToZ',\r\n name: 'A to Z',\r\n icon: 'SortUp',\r\n canCheck: true,\r\n checked: column.isSorted && !column.isSortedDescending,\r\n onClick: () => this._onSortColumn(column.key, false)\r\n },\r\n {\r\n key: 'zToA',\r\n name: 'Z to A',\r\n icon: 'SortDown',\r\n canCheck: true,\r\n checked: column.isSorted && column.isSortedDescending,\r\n onClick: () => this._onSortColumn(column.key, true)\r\n }\r\n ];\r\n if (isGroupable(column.key)) {\r\n items.push({\r\n key: 'groupBy',\r\n name: 'Group By ' + column.name,\r\n icon: 'GroupedDescending',\r\n canCheck: true,\r\n checked: column.isGrouped,\r\n onClick: () => this._onGroupByColumn(column)\r\n });\r\n }\r\n return {\r\n items: items,\r\n targetElement: ev.currentTarget as HTMLElement,\r\n directionalHint: DirectionalHint.bottomLeftEdge,\r\n gapSpace: 10,\r\n isBeakVisible: true,\r\n onDismiss: this._onContextualMenuDismissed\r\n };\r\n }\r\n\r\n @autobind\r\n private _onItemInvoked(item: any, index: number) {\r\n console.log('Item invoked', item, index);\r\n }\r\n\r\n @autobind\r\n private _onColumnClick(ev: React.MouseEvent<HTMLElement>, column: IColumn) {\r\n this.setState({\r\n contextualMenuProps: this._getContextualMenuProps(ev, column)\r\n });\r\n }\r\n\r\n @autobind\r\n private _onContextualMenuDismissed() {\r\n this.setState({\r\n contextualMenuProps: null\r\n });\r\n }\r\n\r\n @autobind\r\n private _onSortColumn(key: string, isSortedDescending: boolean) {\r\n let sortedItems = _items.slice(0).sort((a, b) => (isSortedDescending ? a[key] < b[key] : a[key] > b[key]) ? 1 : -1);\r\n\r\n this.setState({\r\n items: sortedItems,\r\n groups: null,\r\n columns: this._buildColumns(sortedItems, true, this._onColumnClick, key, isSortedDescending),\r\n isSortedDescending: isSortedDescending,\r\n sortedColumnKey: key\r\n });\r\n }\r\n\r\n @autobind\r\n private _onGroupByColumn(column: IColumn) {\r\n let { key, isGrouped } = column;\r\n let { sortedColumnKey, isSortedDescending, groups, items, columns } = this.state;\r\n\r\n if (isGrouped) { // ungroup\r\n this._onSortColumn(sortedColumnKey, isSortedDescending);\r\n } else {\r\n let groupedItems = [];\r\n let newGroups = null;\r\n if (groups) {\r\n newGroups = groups.concat([]);\r\n groupedItems = this._groupByKey(newGroups, items, key);\r\n } else {\r\n groupedItems = this._groupItems(items, key);\r\n newGroups = this._getGroups(groupedItems, key);\r\n }\r\n\r\n let newColumns = columns;\r\n newColumns.filter(matchColumn => matchColumn.key === key).forEach((groupedColumn: IColumn) => {\r\n groupedColumn.isGrouped = true;\r\n });\r\n this.setState({\r\n items: groupedItems,\r\n columns: newColumns,\r\n groups: newGroups\r\n });\r\n }\r\n }\r\n\r\n private _groupByKey(groups: IGroup[], items: any[], key: string): any[] {\r\n let groupedItems = [];\r\n if (groups) {\r\n groups.forEach((group: IGroup) => {\r\n if (group.children && group.children.length > 0) {\r\n let childGroupedItems = this._groupByKey(group.children, items, key);\r\n groupedItems = groupedItems.concat(childGroupedItems);\r\n } else {\r\n let itemsInGroup = items.slice(group.startIndex, group.startIndex + group.count);\r\n let nextLevelGroupedItems = this._groupItems(itemsInGroup, key);\r\n groupedItems = groupedItems.concat(nextLevelGroupedItems);\r\n group.children = this._getGroups(nextLevelGroupedItems, key, group);\r\n }\r\n });\r\n }\r\n return groupedItems;\r\n }\r\n\r\n private _groupItems(items: any[], columnKey: string): any[] {\r\n return items.slice(0).sort((a, b) => ((a[columnKey] < b[columnKey]) ? -1 : 1));\r\n }\r\n\r\n private _getGroups(groupedItems: any[], key: string, parentGroup?: IGroup): IGroup[] {\r\n let separator = '-';\r\n let groups = groupedItems.reduce((current, item, index) => {\r\n let currentGroup = current[current.length - 1];\r\n\r\n if (!currentGroup || (this._getLeafGroupKey(currentGroup.key, separator) !== item[key])) {\r\n current.push({\r\n key: (parentGroup ? parentGroup.key + separator : '') + item[key],\r\n name: key + ': ' + item[key],\r\n startIndex: parentGroup ? parentGroup.startIndex + index : index,\r\n count: 1,\r\n level: parentGroup ? parentGroup.level + 1 : 0\r\n });\r\n } else {\r\n currentGroup.count++;\r\n }\r\n return current;\r\n }, []);\r\n\r\n return groups;\r\n }\r\n\r\n private _getLeafGroupKey(key: string, separator: string): string {\r\n let leafKey = key;\r\n if (key.indexOf(separator) !== -1) {\r\n let arrKeys = key.split(separator);\r\n leafKey = arrKeys[arrKeys.length - 1];\r\n }\r\n return leafKey;\r\n }\r\n\r\n @autobind\r\n private _onAddRow() {\r\n this.setState({\r\n items: createListItems(1).concat(this.state.items)\r\n });\r\n }\r\n\r\n @autobind\r\n private _onDeleteRow() {\r\n this.setState({\r\n items: this.state.items.slice(1)\r\n });\r\n }\r\n\r\n private _buildColumns(\r\n items: any[],\r\n canResizeColumns?: boolean,\r\n onColumnClick?: (ev: React.MouseEvent<HTMLElement>, column: IColumn) => any,\r\n sortedColumnKey?: string,\r\n isSortedDescending?: boolean,\r\n groupedColumnKey?: string) {\r\n let columns = buildColumns(items, canResizeColumns, onColumnClick, sortedColumnKey, isSortedDescending, groupedColumnKey);\r\n\r\n columns.forEach(column => {\r\n if (column.key === 'description') {\r\n column.isMultiline = true;\r\n column.minWidth = 200;\r\n } else if (column.key === 'name') {\r\n column.onRender = (item) => (\r\n <Link>{ item.name }</Link>\r\n );\r\n } else if (column.key === 'key') {\r\n column.columnActionsMode = ColumnActionsMode.disabled;\r\n column.onRender = (item) => (\r\n <Link href='#'>{ item.key }</Link>\r\n );\r\n column.minWidth = 90;\r\n column.maxWidth = 90;\r\n }\r\n });\r\n\r\n return columns;\r\n }\r\n}\r\n";