Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@uifabric/experiments",
"comment": "Sets up an example of Shimmer used with DetailsList Component.",
"type": "minor"
}
],
"packageName": "@uifabric/experiments",
"email": "v-vibr@microsoft.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "office-ui-fabric-react",
"comment": "Brings changes to DetailsList, DetailsRow and DetailsRowFields to enable use of a basic Shimmer.",
"type": "minor"
}
],
"packageName": "office-ui-fabric-react",
"email": "v-vibr@microsoft.com"
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class ShimmerPage extends React.Component<IComponentDemoPageProps, {}> {
<ShimmerLoadDataExample />
</ExampleCard>
<ExampleCard
title='Details List with 1000 items loading in async way.'
title='Details List with 500 items loading in async way and having enabled Shimmer.'
code={ ShimmerApplicationExampleCode }
>
<ShimmerApplicationExample />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import {
IExpandingCardProps
} from 'office-ui-fabric-react/lib/HoverCard';
import { createListItems } from '@uifabric/example-app-base';
import './Shimmer.Example.scss';
import {
Shimmer,
} from 'experiments/lib/Shimmer';
import { IColumn, DetailsList, buildColumns } from 'office-ui-fabric-react/lib/DetailsList';

const PAGING_DELAY = 3000;
const ITEMS_COUNT = 1000;
const PAGING_SIZE = 10;
IColumn,
DetailsList,
buildColumns,
SelectionMode,
Toggle
} from 'office-ui-fabric-react';
import { Shimmer } from 'experiments/lib/Shimmer';
import './Shimmer.Example.scss';

export interface IItem {
[index: string]: string | number;
Expand All @@ -30,13 +30,6 @@ export interface IItem {
height: number;
}

export interface IShimmerElem {
[index: string]: HTMLElement;
}

// tslint:disable-next-line:no-any
let _items: any[];

const fileIcons: { name: string; }[] = [
{ 'name': 'accdb' },
{ 'name': 'csv' },
Expand All @@ -63,9 +56,19 @@ const fileIcons: { name: string; }[] = [
{ 'name': 'xsn' }
];

const ITEMS_COUNT = 500;
const ITEMS_BATCH_SIZE = 10;
const PAGING_DELAY = 2500;

// tslint:disable-next-line:no-any
let _items: any[];

export interface IShimmerApplicationExampleState {
items?: IItem[];
columns?: IColumn[];
isDataLoaded?: boolean;
isModalSelection?: boolean;
isCompactMode?: boolean;
}

export class ShimmerApplicationExample extends BaseComponent<{}, IShimmerApplicationExampleState> {
Expand All @@ -74,64 +77,121 @@ export class ShimmerApplicationExample extends BaseComponent<{}, IShimmerApplica
constructor(props: {}) {
super(props);

if (!_items) {
_items = createListItems(ITEMS_COUNT);
_items.map((item: IItem) => {
const randomFileType = this._randomFileIcon();
item.thumbnail = randomFileType.url;
});
}

this.state = {
items: _items.slice(0, PAGING_SIZE).concat(new Array(ITEMS_COUNT - PAGING_SIZE)),
columns: _buildColumns()
items: new Array(),
columns: _buildColumns(),
isDataLoaded: false,
isModalSelection: false,
isCompactMode: false
};
}

public render(): JSX.Element {
const { items, columns } = this.state;
const {
items,
columns,
isDataLoaded,
isModalSelection,
isCompactMode
} = this.state;

return (
<div className='shimmerExample-application'>
<p> Hover over location of a row item to see the card </p>
<DetailsList
setKey='items'
items={ items! }
columns={ columns }
onRenderItemColumn={ this._onRenderItemColumn }
onRenderMissingItem={ this._onRenderMissingItem }
/>
<div>
<div className='shimmerExample-toggleButtons'>
<Toggle
label='Enable Modal Selection'
checked={ isModalSelection }
onChanged={ this._onChangeModalSelection }
onText='Modal'
offText='Normal'
/>
<Toggle
label='Enable Compact Mode'
checked={ isCompactMode }
onChanged={ this._onChangeCompactMode }
onText='Compact'
offText='Normal'
/>
<p>Toggle the Load data switch to start async simulation.</p>
<Toggle
label='Load data switch'
checked={ isDataLoaded }
onChanged={ this._onLoadData }
onText='Loaded'
offText='Loading...'
/>
</div>
<div className='shimmerExample-application'>
<DetailsList
setKey='items'
items={ items! }
columns={ columns }
compact={ isCompactMode }
selectionMode={ this.state.isModalSelection ? SelectionMode.multiple : SelectionMode.none }
onRenderItemColumn={ this._onRenderItemColumn }
onRenderMissingItem={ this._onRenderMissingItem }
listProps={ { renderedWindowsAhead: 0, renderedWindowsBehind: 0 } }
/>
</div>
</div>
);
}

private _onRenderMissingItem = (index: number): JSX.Element => {
this._onDataMiss(index as number);
private _onRenderMissingItem = (index: number): React.ReactNode => {
const { isDataLoaded } = this.state;
isDataLoaded && this._onDataMiss(index as number);

return (
<Shimmer />
);
}

private _onDataMiss(index: number): void {
index = Math.floor(index / PAGING_SIZE) * PAGING_SIZE;

// Simulating asynchronus data loading each 2.5 sec
private _onDataMiss = (index: number): void => {
index = Math.floor(index / ITEMS_BATCH_SIZE) * ITEMS_BATCH_SIZE;
if (!this._isFetchingItems) {

this._isFetchingItems = true;

setTimeout(() => {
this._isFetchingItems = false;
// tslint:disable-next-line:no-any
const itemsCopy = ([] as any[]).concat(this.state.items);
itemsCopy.splice.apply(itemsCopy, [index, PAGING_SIZE].concat(_items.slice(index, index + PAGING_SIZE)));

itemsCopy.splice.apply(itemsCopy, [index, ITEMS_BATCH_SIZE].concat(_items.slice(index, index + ITEMS_BATCH_SIZE)));
this.setState({
items: itemsCopy
});
}, PAGING_DELAY);
}
}

private _onLoadData = (checked: boolean): void => {
if (!_items) {
_items = createListItems(ITEMS_COUNT);
_items.map((item: IItem) => {
const randomFileType = this._randomFileIcon();
item.thumbnail = randomFileType.url;
});
}
let { isDataLoaded, items } = this.state;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whats the point in getting isDataLoaded and items state if we are just going to re-assign them

Copy link
Copy Markdown
Contributor Author

@Vitalius1 Vitalius1 Mar 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That one is used for simulating asynchronous loading which is triggered by the toggle switch in this particular example. So basically it is used for the toggle switch.

isDataLoaded = checked;
if (isDataLoaded) {
items = _items.slice(0, ITEMS_BATCH_SIZE).concat(new Array(ITEMS_COUNT - ITEMS_BATCH_SIZE));
} else {
items = new Array();
}
this.setState({
isDataLoaded: isDataLoaded,
items: items
});
}

private _onChangeModalSelection = (checked: boolean): void => {
this.setState({ isModalSelection: checked });
}

private _onChangeCompactMode = (checked: boolean): void => {
this.setState({ isCompactMode: checked });
}

private _onRenderItemColumn = (item: IItem, index: number, column: IColumn): JSX.Element | string | number => {
const expandingCardProps: IExpandingCardProps = {
onRenderCompactCard: this._onRenderCompactCard,
Expand Down Expand Up @@ -194,7 +254,8 @@ export class ShimmerApplicationExample extends BaseComponent<{}, IShimmerApplica
}

function _buildColumns(): IColumn[] {
const columns: IColumn[] = buildColumns(_items);
const _item = createListItems(1);
const columns: IColumn[] = buildColumns(_item);

columns.forEach((column: IColumn) => {
if (column.key === 'thumbnail') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,4 @@
text-decoration: underline;
cursor: pointer;
}

.shimmerExample-application .ms-Shimmer-container{
margin-left: 42px;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,18 @@ const ISPADDED_WIDTH = 24;
const DEFAULT_RENDERED_WINDOWS_AHEAD = 2;
const DEFAULT_RENDERED_WINDOWS_BEHIND = 2;

const SHIMMER_INITIAL_ITEMS = 10;
const SHIMMER_ITEMS = new Array(SHIMMER_INITIAL_ITEMS);

@withViewport
export class DetailsList extends BaseComponent<IDetailsListProps, IDetailsListState> implements IDetailsList {
public static defaultProps = {
layoutMode: DetailsListLayoutMode.justified,
selectionMode: SelectionMode.multiple,
constrainMode: ConstrainMode.horizontalConstrained,
checkboxVisibility: CheckboxVisibility.onHover,
isHeaderVisible: true
isHeaderVisible: true,
enableShimmer: false
};

// References
Expand Down Expand Up @@ -273,7 +277,8 @@ export class DetailsList extends BaseComponent<IDetailsListProps, IDetailsListSt
getKey,
listProps,
usePageCache,
onShouldVirtualize
onShouldVirtualize,
enableShimmer
} = this.props;
const {
adjustedColumns,
Expand Down Expand Up @@ -402,7 +407,7 @@ export class DetailsList extends BaseComponent<IDetailsListProps, IDetailsListSt
<List
ref={ this._list }
role='presentation'
items={ items }
items={ enableShimmer && !items.length ? SHIMMER_ITEMS : items }
onRenderCell={ this._onRenderListCell(0) }
usePageCache={ usePageCache }
onShouldVirtualize={ onShouldVirtualize }
Expand Down Expand Up @@ -462,15 +467,7 @@ export class DetailsList extends BaseComponent<IDetailsListProps, IDetailsListSt
adjustedColumns: columns
} = this.state;

if (!item) {
if (onRenderMissingItem) {
return onRenderMissingItem(index);
}

return null;
}

return onRenderRow({
const rowProps: IDetailsRowProps = {
item: item,
itemIndex: index,
compact: compact,
Expand All @@ -491,7 +488,17 @@ export class DetailsList extends BaseComponent<IDetailsListProps, IDetailsListSt
getRowAriaDescribedBy: getRowAriaDescribedBy,
checkButtonAriaLabel: checkButtonAriaLabel,
checkboxCellClassName: checkboxCellClassName,
}, this._onRenderRow);
};

if (!item) {
if (onRenderMissingItem) {
return onRenderMissingItem(index, rowProps);
}

return null;
}

return onRenderRow(rowProps, this._onRenderRow);
}

private _onGroupExpandStateChanged(isSomeGroupExpanded: boolean) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,13 @@ export interface IDetailsListProps extends React.Props<DetailsList>, IWithViewpo
dragDropEvents?: IDragDropEvents;

/** Callback for what to render when the item is missing. */
onRenderMissingItem?: (index?: number) => React.ReactNode;
onRenderMissingItem?: (index?: number, rowProps?: IDetailsRowProps) => React.ReactNode;

/**
* If set to true and we provide an empty array, it will render 10 lines of whatever provided in onRenderMissingItem.
* @default false
*/
enableShimmer?: boolean;

/**
* An override to render the details header.
Expand Down
Loading