@retailmenot/anchor
Version:
A React UI Library by RetailMeNot
107 lines (103 loc) • 4.82 kB
JavaScript
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
// VENDOR
import * as React from 'react';
import classNames from 'classnames';
import styled, { css, keyframes, ThemeContext, } from '@xstyled/styled-components';
import { space as spaceStyles, layout as layoutStyles, borderRadius as borderRadiusStyles, variant as createVariant, fontSize as fontSizeStyles, lineHeight as lineHeightStyles, th, } from '@xstyled/system';
export const SKELETON_KEY = 'skeleton';
export const SKELETON_THEME = {
variants: {
base: {
colorStart: '#E7E7E7',
colorEnd: '#D3D3D3',
},
},
};
const colorVariant = createVariant({
key: `${SKELETON_KEY}.variants`,
prop: 'variant',
default: 'base',
variants: SKELETON_THEME.variants,
});
const colorKeyframe = (start, end) => keyframes `
0% { color: ${start}; }
50% { color: ${end}; }
100% { color: ${start}; }
`;
const bgKeyframe = (start, end) => keyframes `
0% { background: ${start}; }
50% { background: ${end}; }
100% { background: ${start}; }
`;
const StyledSkeleton = styled('span') `
box-sizing: border-box;
${borderRadiusStyles}
${spaceStyles}
${layoutStyles}
${fontSizeStyles}
${lineHeightStyles}
${({ textOnly, colorStart, colorEnd }) => textOnly
? css `
// its all one word technically, so we want to make sure
// it can be broken up into multiple lines
word-break: break-all;
white-space: normal;
// smoothing can make it appear as though theres
// a gap between the block characters
-webkit-font-smoothing: none;
-moz-osx-font-smoothing: auto;
color: ${colorStart};
animation: ${colorKeyframe(colorStart, colorEnd)} 2s
ease-in-out infinite;
`
: css `
pointer-events: none;
background: ${colorStart};
animation: ${bgKeyframe(colorStart, colorEnd)} 2s ease-in-out
infinite;
// hide all children
&& * {
visibility: hidden;
opacity: 0;
}
`}
`;
export const Skeleton = (_a) => {
var { className, children, display, textLength,
// This is the unicode block character that put together looks like one
// long bar. There are shorter and taller characters that could be used
// or a fatter or thinner bar.
textChar = '▆',
// This is the conversion from block width to the average width of
// a normal distribution of letters. We came up with it by eyeballing it
// for the Avenir Next font. We should probably make it themeable in the future.
blockRatio = 1 / 2.15, loading = true, colorStart, colorEnd } = _a, props = __rest(_a, ["className", "children", "display", "textLength", "textChar", "blockRatio", "loading", "colorStart", "colorEnd"]);
if (!loading) {
return typeof children === 'undefined' ? null : children;
}
const theme = React.useContext(ThemeContext);
const { colorStart: themeStart, colorEnd: themeEnd } = colorVariant(Object.assign(Object.assign({}, props), { theme }));
// Keyframes don't play nice with prop functions, so we're manually
// calculating the raw color value from the theme before plugging it in
const startValue = th.color(colorStart || themeStart)({ theme });
const endValue = th.color(colorEnd || themeEnd)({ theme });
const onlyChild = React.Children.count(children) === 1 &&
React.Children.toArray(children)[0];
// We're removing duplicate white space because they don't show up in html
const childText = typeof onlyChild === 'string' && onlyChild.replace(/\s\s+/g, ' ');
const length = textLength || (childText && childText.length);
const blockText = length && Array(Math.ceil(length * blockRatio) + 1).join(textChar);
const textOnly = !!blockText;
return (React.createElement(StyledSkeleton, Object.assign({ className: classNames('anchor-skeleton', className), display: display || (textOnly ? 'inherit' : 'inline-block'), textOnly: textOnly, colorStart: startValue, colorEnd: endValue }, props), blockText || children));
};
//# sourceMappingURL=Skeleton.component.js.map