@retailmenot/anchor
Version:
A React UI Library by RetailMeNot
558 lines (477 loc) • 18.5 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var __chunk_1 = require('./anchor-chunk-24f232e7.js');
var __chunk_2 = require('./anchor-chunk-9d9a5df6.js');
var theme = require('./theme.js');
var tsDebounce = require('ts-debounce');
var Responsive = _interopDefault(require('react-responsive'));
var React = require('react');
var classNames = _interopDefault(require('classnames'));
var styled = require('@xstyled/styled-components');
var styled__default = _interopDefault(styled);
var system = require('@xstyled/system');
require('./anchor-chunk-925bd1f9.js');
require('./skeleton.js');
require('polished');
require('./anchor-chunk-eb382a51.js');
require('./anchor-chunk-1efd6395.js');
require('./anchor-chunk-598e53e1.js');
var GridContext = React.createContext({
debug: false
});
var FLOW;
(function (FLOW) {
FLOW["column"] = "column";
FLOW["row"] = "row";
})(FLOW || (FLOW = {}));
var debugColor = 'rgba(255, 0, 0, 0.4)';
/*
Returns an array of objects sorted by their value, descending. Ex:
const obj: { xs: 500: md: 800: sm: 650 };
sortBreakpoints(obj); // [{xs: 500}, {sm: 650}, {md: 800}]
*/
function sortBreakpoints(unsortedBreakpoints) {
return Object.keys(unsortedBreakpoints).reduce(function (acc, next) {
acc.push(__chunk_1._defineProperty({}, next, unsortedBreakpoints[next]));
return acc;
}, []).sort(function (a, b) {
return Object.values(a)[0] - Object.values(b)[0];
});
}
/*
Returns the breakpoint key for the specified window's innerWidth. Ex:
const innerWidth = 920;
const sortedBreakpoints = [{ xs: 500, sm: 750, md: 1000 }];
getBreakpointKey(innerWidth, sortedBreakpoints); // sm
*/
function getBreakpointKey(innerWidth, sortedBreakpoints) {
var breakpoint = sortedBreakpoints // Get only breakpoints that are above the window's width
.filter(function (bp) {
return innerWidth >= Object.values(bp)[0];
}) // Sort those breakpoints, putting the largest breakpoint first
.sort(function (a, b) {
return Object.values(b)[0] - Object.values(a)[0];
}) // Get the largest breakpoint from the array
.shift(); // Gets the key based on the breakpoint (i.e. xs, sm, etc)
return __chunk_1._typeof(breakpoint) === 'object' ? Object.keys(breakpoint)[0] : '';
}
/*
Small helper object for the generateBreakpointCSS() function to render the correct CSS for each
grid setting.
*/
var ops = {
// If width is 0, don't show the cell. If middle is true, add in the middle CSS.
width: function width(_width, middle) {
return _width > 0 ? "grid-column-end: span ".concat(_width, "; display: block;") : 'display: none;';
},
height: function height(_height) {
return "grid-row-end: span ".concat(_height, ";");
},
left: function left(_left) {
return "grid-column-start: ".concat(_left, ";");
},
top: function top(_top) {
return "grid-row-start: ".concat(_top, ";");
}
};
/*
Takes the gridSettings object and parses the data to generate sorted css breakpoints. It groups
css properties based on the breakpoint size so that a single breakpoint declaration for 'xs' can
have css for left, top, height & width if necessary.
NOTE: This function uses older loop structures as they are tremendously more performant.
*/
function generateBreakpointCSS(gridSettings, sortedBreakpoints) {
var responsiveCSS = {};
var sortedResponsiveCSS = [];
var generalSettings = {};
for (var gridSettingKey in gridSettings) {
// forin requires an 'if' guard
if (gridSettings[gridSettingKey]) {
var gridSettingValue = gridSettings[gridSettingKey]; // Put non-responsive settings into the generalSettings object
if (typeof gridSettingValue === 'number' || typeof gridSettingValue === 'undefined') {
generalSettings[gridSettingKey] = gridSettingValue;
} else if (__chunk_1._typeof(gridSettingValue) === 'object') {
for (var breakpointKey in gridSettingValue) {
if (gridSettingValue[breakpointKey] >= 0) {
// 0 is a valid value, no truthiness
var responsiveValue = gridSettingValue[breakpointKey];
if (!responsiveCSS[breakpointKey]) {
responsiveCSS[breakpointKey] = '';
}
responsiveCSS[breakpointKey] += ops[gridSettingKey](responsiveValue);
}
}
}
}
} // eslint-disable-next-line: prefer-for-of
for (var i = 0; i < sortedBreakpoints.length; i++) {
for (var _breakpointKey in sortedBreakpoints[i]) {
if (responsiveCSS[_breakpointKey] !== undefined) {
sortedResponsiveCSS.push(__chunk_1._defineProperty({}, _breakpointKey, responsiveCSS[_breakpointKey]));
}
}
}
/*
sortedResponsiveCSS is an array of breakpoint css associated to a breakpoint key, i.e.
[
{xs: 'grid-column-end: span 2; display: block; grid-row-end: span 3;'},
{md: 'grid-column-end: span 10;'}
]
generalSettings is the returned values which were not responsive objects, i.e.
{
left: 1,
top: undefined,
height: 1,
width: 3
}
*/
return {
sortedResponsiveCSS: sortedResponsiveCSS,
generalSettings: generalSettings
};
}
function _templateObject() {
var data = __chunk_1._taggedTemplateLiteral(["\n padding: 1rem 2rem;\n z-index: 1000000;\n background: black;\n color: white;\n position: fixed;\n bottom: 1rem;\n right: 1rem;\n font-family: mono;\n"]);
_templateObject = function _templateObject() {
return data;
};
return data;
}
var StyledDebug = styled__default('div')(_templateObject());
StyledDebug.displayName = 'StyledDebug';
var ResponsiveContext = React.createContext({
breakpoints: [],
current: '',
innerWidth: 0
});
var BasicResponsiveProvider = /*#__PURE__*/function (_React$PureComponent) {
__chunk_1._inherits(BasicResponsiveProvider, _React$PureComponent);
var _super = __chunk_1._createSuper(BasicResponsiveProvider);
function BasicResponsiveProvider(props) {
var _this;
__chunk_1._classCallCheck(this, BasicResponsiveProvider);
_this = _super.call(this, props);
var hasWindow = props.windowDep === false ? false : typeof window !== 'undefined';
var breakpoints; // Priority is props > ThemeProvider > RootTheme
if (props.breakpoints !== undefined) {
breakpoints = props.breakpoints;
} else if (props.theme !== undefined) {
breakpoints = props.theme.breakpoints;
} else {
breakpoints = theme.RootTheme.breakpoints;
}
var sortedBreakpoints = sortBreakpoints(breakpoints);
var innerWidth = hasWindow ? window.innerWidth : 0;
_this.state = {
breakpoints: sortedBreakpoints,
current: getBreakpointKey(innerWidth, sortedBreakpoints),
innerWidth: innerWidth
};
_this.handleResize = tsDebounce.debounce(_this.handleResize.bind(__chunk_1._assertThisInitialized(_this)), 100);
_this.hasWindow = hasWindow;
return _this;
}
__chunk_1._createClass(BasicResponsiveProvider, [{
key: "handleResize",
value: function handleResize() {
if (this.hasWindow) {
this.setState({
current: getBreakpointKey(window.innerWidth, this.state.breakpoints),
innerWidth: window.innerWidth
});
}
}
}, {
key: "componentDidMount",
value: function componentDidMount() {
if (this.hasWindow) {
window.addEventListener('resize', this.handleResize);
}
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
if (this.hasWindow) {
window.removeEventListener('resize', this.handleResize);
}
}
}, {
key: "render",
value: function render() {
var _this$state = this.state,
breakpoints = _this$state.breakpoints,
current = _this$state.current,
innerWidth = _this$state.innerWidth;
var debug = this.props.debug;
return React.createElement(ResponsiveContext.Provider, {
value: {
breakpoints: breakpoints,
current: current,
innerWidth: innerWidth
}
}, debug && React.createElement(StyledDebug, null, current, " | w:", innerWidth, "px"), this.props.children);
}
}]);
return BasicResponsiveProvider;
}(React.PureComponent);
var ResponsiveProvider = styled.withTheme(BasicResponsiveProvider);
function _templateObject2() {
var data = __chunk_1._taggedTemplateLiteral(["\n box-sizing: border-box;\n\n ", "\n\n ", "\n"]);
_templateObject2 = function _templateObject2() {
return data;
};
return data;
}
function _templateObject$1() {
var data = __chunk_1._taggedTemplateLiteral(["\n height: 100%;\n min-width: 0;\n\n // The order in which the media queries are generated is very important, hence breakpoints() is\n // called multiple times as opposed to just once with a single object.\n ", "\n\n ", ";\n ", ";\n ", ";\n ", ";\n\n ", ";\n ", ";\n"]);
_templateObject$1 = function _templateObject() {
return data;
};
return data;
}
var StyledCell = styled__default.div(_templateObject$1(), function (_ref) {
var responsiveCSS = _ref.responsiveCSS;
return responsiveCSS && responsiveCSS.map(function (k) {
return system.breakpoints(k);
});
}, function (_ref2) {
var left = _ref2.left;
return left && "grid-column-start: ".concat(left);
}, function (_ref3) {
var width = _ref3.width;
return width && "grid-column-end: span ".concat(width);
}, function (_ref4) {
var top = _ref4.top;
return top && "grid-row-start: ".concat(top);
}, function (_ref5) {
var height = _ref5.height;
return height && "grid-row-end: span ".concat(height);
}, function (_ref6) {
var area = _ref6.area;
return area && "grid-area: ".concat(area);
}, function (_ref7) {
var debug = _ref7.debug;
return debug && styled.css({
backgroundColor: debugColor
});
});
/* Used these flex styles rather than xstyled 'flexboxes' system prop to limit the props the user
would have to use for the same effect. May rethink this if users ask for even more flex control. */
var Box = styled__default('div')(_templateObject2(), system.space, function (_ref8) {
var align = _ref8.align,
center = _ref8.center,
middle = _ref8.middle,
valign = _ref8.valign;
var styles = {}; // This is to keep the API from breaking from v1.3.3 and below.
// The middle and center props should be deprecated.
var tmpValign = middle ? 'middle' : valign;
var tmpAlign = center ? 'center' : align;
if (tmpAlign || tmpValign) {
styles.display = 'flex';
if (tmpValign) {
styles.height = '100%';
}
}
switch (tmpAlign) {
case 'left':
styles.justifyContent = 'flex-start';
break;
case 'center':
styles.justifyContent = 'center';
break;
case 'right':
styles.justifyContent = 'flex-end';
break;
}
switch (tmpValign) {
case 'top':
styles.alignItems = 'flex-start';
break;
case 'middle':
styles.alignItems = 'center';
break;
case 'bottom':
styles.alignItems = 'flex-end';
break;
}
return styled.css(styles);
});
Box.displayName = 'Box';
var Cell = /*#__PURE__*/function (_React$PureComponent) {
__chunk_1._inherits(Cell, _React$PureComponent);
var _super = __chunk_1._createSuper(Cell);
function Cell(props, context) {
var _this;
__chunk_1._classCallCheck(this, Cell);
_this = _super.call(this, props, context); // Generates css data for xstyle'd media queries in the constructor so as to only
// fire a single time and before render. Width and height have a default of 1.
var _generateBreakpointCS = generateBreakpointCSS({
left: props.left,
height: props.height || 1,
top: props.top,
width: props.width || 1
}, context.breakpoints),
sortedResponsiveCSS = _generateBreakpointCS.sortedResponsiveCSS,
generalSettings = _generateBreakpointCS.generalSettings;
_this.state = {
generalSettings: generalSettings,
sortedResponsiveCSS: sortedResponsiveCSS
};
return _this;
}
__chunk_1._createClass(Cell, [{
key: "render",
value: function render() {
var _this2 = this;
var _this$props = this.props,
align = _this$props.align,
center = _this$props.center,
children = _this$props.children,
className = _this$props.className,
debug = _this$props.debug,
middle = _this$props.middle,
valign = _this$props.valign;
var _this$state = this.state,
generalSettings = _this$state.generalSettings,
sortedResponsiveCSS = _this$state.sortedResponsiveCSS;
return React.createElement(GridContext.Consumer, null, function (_ref9) {
var contextDebug = _ref9.debug;
return React.createElement(StyledCell, {
className: classNames('anchor-cell', className),
debug: contextDebug || debug,
responsiveCSS: sortedResponsiveCSS,
left: generalSettings.left || undefined,
height: generalSettings.height || undefined,
top: generalSettings.top || undefined,
width: generalSettings.width || undefined
}, React.createElement(Box, Object.assign({}, _this2.props, {
align: align,
center: center,
className: "anchor-cell-box",
valign: valign,
middle: middle
}), children));
});
}
}]);
return Cell;
}(React.PureComponent);
Cell.contextType = ResponsiveContext;
function _templateObject2$1() {
var data = __chunk_1._taggedTemplateLiteral(["\n height: ", ";\n grid-auto-flow: ", ";\n grid-auto-rows: minmax(", ", auto);\n ", ";\n grid-template-columns: ", ";\n grid-gap: ", ";\n ", ";\n ", ";\n ", ";\n ", ";\n ", ";\n ", ";\n "]);
_templateObject2$1 = function _templateObject2() {
return data;
};
return data;
}
function _templateObject$2() {
var data = __chunk_1._taggedTemplateLiteral(["\n display: grid;\n ", "\n\n ", "\n"]);
_templateObject$2 = function _templateObject() {
return data;
};
return data;
}
var frGetter = function frGetter(value) {
return typeof value === 'number' ? "repeat(".concat(value, ", 1fr)") : value;
};
var formatAreas = function formatAreas(areas) {
return areas.map(function (area) {
return "'".concat(area, "'");
}).join(' ');
};
var StyledGrid = styled__default('div')(_templateObject$2(), function (_ref) {
var alignContent = _ref.alignContent,
areas = _ref.areas,
columnGap = _ref.columnGap,
_ref$columns = _ref.columns,
columns = _ref$columns === void 0 ? 12 : _ref$columns,
debug = _ref.debug,
_ref$flow = _ref.flow,
flow = _ref$flow === void 0 ? FLOW.row : _ref$flow,
_ref$gap = _ref.gap,
gap = _ref$gap === void 0 ? '0.5rem' : _ref$gap,
_ref$height = _ref.height,
height = _ref$height === void 0 ? 'auto' : _ref$height,
justifyContent = _ref.justifyContent,
_ref$minRowHeight = _ref.minRowHeight,
minRowHeight = _ref$minRowHeight === void 0 ? '1.25rem' : _ref$minRowHeight,
rowGap = _ref.rowGap,
rows = _ref.rows;
return styled.css(_templateObject2$1(), height, flow, minRowHeight, rows && "grid-template-rows: ".concat(frGetter(rows)), frGetter(columns), gap, columnGap && "column-gap: ".concat(columnGap), rowGap && "row-gap: ".concat(rowGap), areas && "grid-template-areas: ".concat(formatAreas(areas)), justifyContent && "justify-content: ".concat(justifyContent), alignContent && "align-content: ".concat(alignContent), debug && "background-color: ".concat(debugColor));
}, system.space);
var Grid = function Grid(_a) {
var alignContent = _a.alignContent,
areas = _a.areas,
children = _a.children,
className = _a.className,
columns = _a.columns,
_a$debug = _a.debug,
debug = _a$debug === void 0 ? false : _a$debug,
flow = _a.flow,
gap = _a.gap,
rowGap = _a.rowGap,
columnGap = _a.columnGap,
justifyContent = _a.justifyContent,
rows = _a.rows,
props = __chunk_2.__rest(_a, ["alignContent", "areas", "children", "className", "columns", "debug", "flow", "gap", "rowGap", "columnGap", "justifyContent", "rows"]);
return React.createElement(StyledGrid, Object.assign({
areas: areas,
className: classNames('anchor-grid', className),
columns: columns,
debug: debug,
flow: flow,
gap: gap,
rowGap: rowGap,
columnGap: columnGap,
justifyContent: justifyContent,
rows: rows
}, props), React.createElement(GridContext.Provider, {
value: {
debug: debug
}
}, children));
};
Grid.Cell = Cell;
var Adaptor = function Adaptor(_a) {
var from = _a.from,
to = _a.to,
props = __chunk_2.__rest(_a, ["from", "to"]);
var _React$useContext = React.useContext(ResponsiveContext),
breakpoints = _React$useContext.breakpoints;
var breakpointValues = {
minWidth: undefined,
maxWidth: undefined
};
if ((from !== undefined || to !== undefined) && !breakpoints.length) {
/* eslint-disable-next-line */
console.warn("When using the 'from' and/or 'to' props, the ResponsiveProvider must also be used.");
return null;
}
if (from === undefined && to !== undefined) {
/* eslint-disable-next-line */
console.warn("Although the 'from' prop can be used by itself, the 'to' prop requires 'from' to also exist");
return null;
}
if (from) {
var min = breakpoints.find(function (bp) {
return Object.keys(bp)[0] === from;
});
breakpointValues.minWidth = __chunk_1._typeof(min) === 'object' ? Object.values(min)[0] : undefined;
}
if (from && to) {
var max = breakpoints.find(function (bp) {
return Object.keys(bp)[0] === to;
});
breakpointValues.maxWidth = __chunk_1._typeof(max) === 'object' ? Object.values(max)[0] : undefined;
}
return React.createElement(Responsive, Object.assign({
className: "anchor-adaptor"
}, breakpointValues, props));
};
exports.ResponsiveContext = ResponsiveContext;
exports.ResponsiveProvider = ResponsiveProvider;
exports.Cell = Cell;
exports.Grid = Grid;
exports.Adaptor = Adaptor;
//# sourceMappingURL=grid.js.map