Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
31009ae
Setting up an example with shimmer tiles.
Mar 31, 2018
d9180a8
Adds some logic to fake some shimmer tiles.
Apr 2, 2018
3dc8f27
Imports shimmer inside TileList.
Apr 2, 2018
980a70d
Reuse the _getCells function to create fake Shimmer Tiles.
Apr 3, 2018
b8d465b
Break point before changing Tile.
Apr 4, 2018
7d90942
Adds a Shimmer tile to Tile component.
Apr 5, 2018
eb25783
Adds logic to Tile in case the content is not passed.
Apr 5, 2018
02ed97c
Refactors the example helpers and adds new proprietes to GridItem and…
Apr 5, 2018
53fe917
Refactors some logic.
Apr 5, 2018
2375832
Changes the logic for changes in TilesList. Moves getShimmerCell as a…
Apr 5, 2018
fabcaab
Changes Tile 'shimmerPlaceholder' prop name to 'asPlaceholder'. Appli…
Apr 5, 2018
99b6e0d
Renames props and styles in Tile
Apr 5, 2018
99548e8
Break point to test some new things.
Apr 6, 2018
ef0b197
Merging fresh master and resolving conflicts.
Apr 6, 2018
9a8ad26
Exports the TileLayoutValues enum.
Apr 6, 2018
5e09d5f
Duplicate ShimmerLine to put basics for ShimmerGap.
Apr 7, 2018
3f8168f
Removes unnecessary checks and moves functions outside for re-usability.
Apr 7, 2018
08ecdae
Change the name of maxHeight to maxLineHeight for better semantics.
Apr 7, 2018
9fad784
Extracts another function for reusability purposes.
Apr 7, 2018
880c58d
Renames again a prop for semantics reasons.
Apr 8, 2018
7cfe4aa
Cleans up code.
Apr 8, 2018
6d1b5a0
Renames a prop for semantics.
Apr 8, 2018
d13db74
Duplicates a folder as base for ShimmerTile component.
Apr 8, 2018
384780f
Sets up props for ShimmerTile
Apr 8, 2018
1398e9c
Exports a const for reusability.
Apr 8, 2018
19fc899
Creates a new example for ShimmerTile.
Apr 8, 2018
c6d2c78
Removes a file.
Apr 8, 2018
ea63b9a
Changes default width behavior
Apr 8, 2018
ebfbea3
Adds initial elements for testing
Apr 8, 2018
ede7db7
Brings logic in TilesList and sets up an example.
Apr 9, 2018
0f7825b
Updates some styling in the TilesList example.
Apr 9, 2018
7142ef3
Change name of a constant for semantics.
Apr 9, 2018
5942fa5
Sets a checkbox to toggle sizes. Fixes Firefox border rounding decima…
Apr 10, 2018
49301b0
Merge branch 'master' into v-vibr/PlaceholderTile
Apr 10, 2018
971a6ec
Fixes build errors.
Apr 10, 2018
db3c3cc
Rush change log.
Apr 10, 2018
89d64c7
Changes type 'JSX.Element[] | JSX.Elelment' to React.ReactNode.
Apr 10, 2018
d33597b
Merge branch 'master' into v-vibr/PlaceholderTile
Vitalius1 Apr 11, 2018
5a84fed
Removes import.
Apr 11, 2018
4bcdec9
Merge branch 'v-vibr/PlaceholderTile' of https://github.com/Vitalius1…
Apr 11, 2018
1e42457
Removes the import statement.
Apr 11, 2018
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": "Refactoring Shimmer and adding ShimmerTile + Implements Shimmer in TilesList.",
"type": "minor"
}
],
"packageName": "@uifabric/experiments",
"email": "v-vibr@microsoft.com"
}
197 changes: 96 additions & 101 deletions packages/experiments/src/components/Shimmer/Shimmer.base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,80 +18,38 @@ import {
IStyleSet
} from '../../Styling';
import { ShimmerLine } from './ShimmerLine/ShimmerLine';
import { ShimmerGap } from './ShimmerGap/ShimmerGap';
import { ShimmerCircle } from './ShimmerCircle/ShimmerCircle';

const LINE_DEFAULT_HEIGHT = 16;
const GAP_DEFAULT_HEIGHT = 16;
const CIRCLE_DEFAULT_HEIGHT = 24;

const getClassNames = classNamesFunction<IShimmerStyleProps, IShimmerStyles>();

export class ShimmerBase extends BaseComponent<IShimmerProps, {}> {
public static defaultProps: IShimmerProps = {
width: 100,
isDataLoaded: false,
isBaseStyle: false
};
private _classNames: {[key in keyof IShimmerStyles]: string};
private _classNames: { [key in keyof IShimmerStyles]: string };
constructor(props: IShimmerProps) {
super(props);
}

public render(): JSX.Element {
const { getStyles, width, lineElements, children, isDataLoaded, isBaseStyle } = this.props;
const maxHeight: number | undefined = lineElements ? this._findMaxHeight(lineElements) : undefined;
this._classNames = getClassNames(getStyles!, { width, maxHeight, isDataLoaded, isBaseStyle });

const elements: JSX.Element[] | JSX.Element = lineElements ?
lineElements.map((elem: ICircle | ILine | IGap, index: number): JSX.Element => {
switch (elem.type) {
case ShimmerElementType.CIRCLE:
if (!elem.height) {
elem.height = CIRCLE_DEFAULT_HEIGHT;
}
return (
<ShimmerCircle
key={ index }
{ ...elem }
borderAlignStyle={ this._getBorderAlignStyles(maxHeight, elem) }
/>
);
case ShimmerElementType.GAP:
const gapWidth = elem.widthInPercentage || elem.widthInPixel ?
elem.widthInPercentage ? elem.widthInPercentage + '%' : elem.widthInPixel + 'px'
: '5px';
return (
<div
key={ index }
// tslint:disable-next-line:jsx-ban-props
style={ {
width: gapWidth,
height: maxHeight + 'px',
backgroundColor: `${DefaultPalette.white}`
} }
/>
);
case ShimmerElementType.LINE:
if (!elem.height) {
elem.height = LINE_DEFAULT_HEIGHT;
}
return (
<ShimmerLine
key={ index }
{ ...elem }
borderAlignStyle={ this._getBorderAlignStyles(maxHeight, elem) }
/>
);
}
}) : (
<ShimmerLine
height={ LINE_DEFAULT_HEIGHT }
/>
);

const rowHeight: number | undefined = lineElements ? findMaxElementHeight(lineElements) : undefined;

this._classNames = getClassNames(getStyles!, { width, rowHeight, isDataLoaded, isBaseStyle });

const renderedElements: React.ReactNode = getRenderedElements(lineElements, rowHeight);

return (
<div className={ this._classNames.root }>
<div className={ this._classNames.shimmerWrapper }>
{ !!isBaseStyle ? children : elements }
{ !!isBaseStyle ? children : renderedElements }
</div>

{ !!isDataLoaded &&
Expand All @@ -102,60 +60,97 @@ export class ShimmerBase extends BaseComponent<IShimmerProps, {}> {
</div>
);
}
}

private _findMaxHeight(items: Array<ICircle | IGap | ILine>): number {
const itemsDefaulted: Array<ICircle | IGap | ILine> = items.map((item: ICircle | IGap | ILine): ICircle | IGap | ILine => {
switch (item.type) {
export function getRenderedElements(lineElements?: Array<ICircle | IGap | ILine>, rowHeight?: number): React.ReactNode {
const renderedElements: React.ReactNode = lineElements ?
lineElements.map((elem: ICircle | ILine | IGap, index: number): JSX.Element => {
switch (elem.type) {
case ShimmerElementType.CIRCLE:
if (!item.height) {
item.height = CIRCLE_DEFAULT_HEIGHT;
}
return (
<ShimmerCircle
key={ index }
{ ...elem }
borderStyle={ getBorderStyles(elem, rowHeight) }
/>
);
case ShimmerElementType.GAP:
return (
<ShimmerGap
key={ index }
{ ...elem }
borderStyle={ getBorderStyles(elem, rowHeight) }
/>
);
case ShimmerElementType.LINE:
if (!item.height) {
item.height = LINE_DEFAULT_HEIGHT;
}
return (
<ShimmerLine
key={ index }
{ ...elem }
borderStyle={ getBorderStyles(elem, rowHeight) }
/>
);
}
return item;
});

const maxHeight = itemsDefaulted.reduce((acc: number, next: ICircle | IGap | ILine): number => {
return next.height ?
next.height > acc ? next.height : acc
: acc;
}, 0);
return maxHeight;
}) : (
<ShimmerLine
height={ LINE_DEFAULT_HEIGHT }
/>
);

return renderedElements;
}

export function getBorderStyles(elem: ICircle | IGap | ILine, rowHeight?: number): IStyleSet | undefined {
const elemHeight: number | undefined = elem.height;

const dif: number = rowHeight && elemHeight ? rowHeight - elemHeight : 0;

let borderStyle: IStyleSet | undefined;

if (!elem.verticalAlign || elem.verticalAlign === ShimmerElementVerticalAlign.CENTER) {
borderStyle = {
borderBottom: `${dif ? Math.floor(dif / 2) : 0}px solid ${DefaultPalette.white}`,
borderTop: `${dif ? Math.ceil(dif / 2) : 0}px solid ${DefaultPalette.white}`
};
} else if (elem.verticalAlign && elem.verticalAlign === ShimmerElementVerticalAlign.TOP) {
borderStyle = {
borderBottom: `${dif ? dif : 0}px solid ${DefaultPalette.white}`,
borderTop: `0px solid ${DefaultPalette.white}`
};
} else if (elem.verticalAlign && elem.verticalAlign === ShimmerElementVerticalAlign.BOTTOM) {
borderStyle = {
borderBottom: `0px solid ${DefaultPalette.white}`,
borderTop: `${dif ? dif : 0}px solid ${DefaultPalette.white}`
};
}

private _getBorderAlignStyles(maxHeight: number | undefined, elem: ICircle | IGap | ILine): IStyleSet | undefined {
const elemHeight: number | undefined = elem.height;

const dif: number | undefined = maxHeight && elemHeight ?
maxHeight - elemHeight > 0 ?
maxHeight - elemHeight : undefined
: undefined;

let borderStyle: IStyleSet | undefined;
const hasVerticalAlign: boolean = elem.verticalAlign ? true : false;

if (elem.verticalAlign === ShimmerElementVerticalAlign.CENTER || !hasVerticalAlign) {
borderStyle = {
alignSelf: 'center',
borderBottom: `${dif ? dif / 2 : 0}px solid ${DefaultPalette.white}`,
borderTop: `${dif ? dif / 2 : 0}px solid ${DefaultPalette.white}`
};
} else if (elem.verticalAlign === ShimmerElementVerticalAlign.TOP && hasVerticalAlign) {
borderStyle = {
alignSelf: 'top',
borderBottom: `${dif ? dif : 0}px solid ${DefaultPalette.white}`,
borderTop: `0px solid ${DefaultPalette.white}`
};
} else if (elem.verticalAlign === ShimmerElementVerticalAlign.BOTTOM && hasVerticalAlign) {
borderStyle = {
alignSelf: 'bottom',
borderBottom: `0px solid ${DefaultPalette.white}`,
borderTop: `${dif ? dif : 0}px solid ${DefaultPalette.white}`
};
return borderStyle;
}

export function findMaxElementHeight(elements: Array<ICircle | IGap | ILine>): number {
const itemsDefaulted: Array<ICircle | IGap | ILine> = elements.map((elem: ICircle | IGap | ILine): ICircle | IGap | ILine => {
switch (elem.type) {
case ShimmerElementType.CIRCLE:
if (!elem.height) {
elem.height = CIRCLE_DEFAULT_HEIGHT;
}
case ShimmerElementType.LINE:
if (!elem.height) {
elem.height = LINE_DEFAULT_HEIGHT;
}
case ShimmerElementType.GAP:
if (!elem.height) {
elem.height = GAP_DEFAULT_HEIGHT;
}
}
return borderStyle;
}
return elem;
});

const rowHeight = itemsDefaulted.reduce((acc: number, next: ICircle | IGap | ILine): number => {
return next.height ?
next.height > acc ? next.height : acc
: acc;
}, 0);

return rowHeight;
}
11 changes: 7 additions & 4 deletions packages/experiments/src/components/Shimmer/Shimmer.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
export function getStyles(props: IShimmerStyleProps): IShimmerStyles {
const {
width,
maxHeight,
rowHeight,
isDataLoaded,
isBaseStyle
} = props;
Expand All @@ -31,7 +31,7 @@ export function getStyles(props: IShimmerStyleProps): IShimmerStyles {
margin: '10px',
width: 'auto',
boxSizing: 'content-box',
minHeight: maxHeight ? `${maxHeight}px` : '16px'
minHeight: rowHeight ? `${rowHeight}px` : '16px'
},
isBaseStyle && {
margin: '0',
Expand All @@ -46,9 +46,12 @@ export function getStyles(props: IShimmerStyleProps): IShimmerStyles {
display: 'flex',
position: 'absolute',
top: '0',
bottom: '0',
left: '0',
right: '0',
alignItems: 'center',
alignContent: 'space-between',
width: `${width}%`,
width: width ? `${width}%` : '100%',
height: 'auto',
boxSizing: 'border-box',
background: `${DefaultPalette.neutralLighter}
Expand All @@ -73,7 +76,7 @@ export function getStyles(props: IShimmerStyleProps): IShimmerStyles {
},
isBaseStyle && {
position: 'static',
width: 'auto'
width: width ? `${width}px` : 'auto'
}
],
dataWrapper: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,21 +106,26 @@ export interface ICircle extends IShimmerElement {
}

export interface IGap extends IShimmerElement {
/**
* Sets the height of the shimmer gap in pixels.
* @default 16px
*/
height?: number;
/**
* The value will be calculated as '%' relative the to shimmer wrapper.
*/
widthInPercentage?: number;

/**
* Sets the width of the Gap to an exact value in pixels.
* @default 5px
* @default 10px
*/
widthInPixel?: number;
}

export interface IShimmerStyleProps {
width?: number;
maxHeight?: number;
rowHeight?: number;
isDataLoaded?: boolean;
isBaseStyle?: boolean;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ export class ShimmerCircleBase extends BaseComponent<IShimmerCircleProps, {}> {
}

public render(): JSX.Element {
const { height, getStyles, borderAlignStyle } = this.props;
this._classNames = getClassNames(getStyles!, { height, borderAlignStyle });
const { height, getStyles, borderStyle } = this.props;
this._classNames = getClassNames(getStyles!, { height, borderStyle });

return (
<div className={ this._classNames.root }>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import {
export function getStyles(props: IShimmerCircleStyleProps): IShimmerCircleStyles {
const {
height,
borderAlignStyle
borderStyle
} = props;

const styles: IStyleSet = !!borderAlignStyle ? borderAlignStyle : {};
const styles: IStyleSet = !!borderStyle ? borderStyle : {};

return {
root: [
'ms-ShimmerCircle-wrapper',
'ms-ShimmerCircle-root',
{
width: `${height}px`,
height: `${height}px`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export interface IShimmerCircleProps extends React.AllHTMLAttributes<HTMLElement
/**
* Used to
*/
borderAlignStyle?: IStyleSet;
borderStyle?: IStyleSet;

/**
* Call to provide customized styling that will layer on top of the variant rules.
Expand All @@ -38,7 +38,7 @@ export interface IShimmerCircleProps extends React.AllHTMLAttributes<HTMLElement

export interface IShimmerCircleStyleProps {
height?: number;
borderAlignStyle?: IStyleSet;
borderStyle?: IStyleSet;
}

export interface IShimmerCircleStyles {
Expand Down
Loading