react-images-lightbox
Version:
A simple, responsive lightbox component for displaying an array of images with React.js
1,405 lines (1,219 loc) • 195 kB
JavaScript
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
'use strict';
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _reactDom = require('react-dom');
var _componentsGallery = require('./components/Gallery');
var _componentsGallery2 = _interopRequireDefault(_componentsGallery);
function makeUnsplashSrc(id) {
return 'https://images.unsplash.com/photo-' + id + '?dpr=2&auto=format&w=1024&h=1024';
}
function makeUnsplashSrcSet(id, size) {
return 'https://images.unsplash.com/photo-' + id + '?dpr=2&auto=format&w=' + size + ' ' + size + 'w';
}
function makeUnsplashThumbnail(id) {
var orientation = arguments.length <= 1 || arguments[1] === undefined ? 'landscape' : arguments[1];
var dimensions = orientation === 'square' ? 'w=300&h=300' : 'w=240&h=159';
return 'https://images.unsplash.com/photo-' + id + '?dpr=2&auto=format&crop=faces&fit=crop&' + dimensions;
}
// Unsplash images from the "Spirit Animals" collection
// https://unsplash.com/collections/158825/spirit-animals
var DEFAULT_IMAGES = [{ id: '1470619549108-b85c56fe5be8', caption: 'Photo by Alan Emery', orientation: 'square', useForDemo: true }, // https://unsplash.com/photos/SYzUF6XcWBY (Flamingo)
{ id: '1471079502516-250c19af6928', caption: 'Photo by Jeremy Bishop', orientation: 'landscape', useForDemo: true }, // https://unsplash.com/photos/GIpGxe2_cT4 (Turtle)
{ id: '1454023492550-5696f8ff10e1', caption: 'Photo by Jessica Weiller', orientation: 'landscape', useForDemo: true }, // https://unsplash.com/photos/LmVSKeDy6EA (Tiger)
{ id: '1470854989922-5be2f7456d78', caption: 'Photo by Piotr Łaskawski', orientation: 'landscape', useForDemo: true }, // https://unsplash.com/photos/GXMr7BadXQo (Hedgehog)
{ id: '1470317596697-cbdeda56f999', caption: 'Photo by Michel Bosma', orientation: 'landscape', useForDemo: true }];
// https://unsplash.com/photos/XgF9e93Tkt0 (Ladybug)
var THEMED_IMAGES = [{ id: '1471101173712-b9884175254e', caption: 'Photo by Pedro Lastra', orientation: 'square', useForDemo: true }, // https://unsplash.com/photos/5oRzZU5uwSM (Dragonfly)
{ id: '1471127432458-65206be149c9', caption: 'Photo by Ernesto Velázquez', orientation: 'landscape', useForDemo: true }, // https://unsplash.com/photos/Kpgt4pl03O0 (Deer)
{ id: '1470777639313-60af88918203', caption: 'Photo by Cris Saur', orientation: 'landscape', useForDemo: true }, // https://unsplash.com/photos/GNUcUx-iObg (Koala)
{ id: '1453550486481-aa4175b013ea', caption: 'Photo by Benjamin Pley', orientation: 'landscape', useForDemo: true }, // https://unsplash.com/photos/WiSeaZ4E6ZI (Elephant)
{ id: '1415904663467-dfdc16cae794', caption: 'Photo by Levi Saunders', orientation: 'landscape', useForDemo: true }];
// https://unsplash.com/photos/NUMlxTPsznM (Coyote)
var THUMBNAIL_IMAGES = [{ id: '1454991727061-be514eae86f7', caption: 'Photo by Thomas Kelley', orientation: 'square', useForDemo: true }, // https://unsplash.com/photos/t20pc32VbrU (Hump Back Whale)
{ id: '1455717974081-0436a066bb96', caption: 'Photo by Teddy Kelley', orientation: 'landscape', useForDemo: true }, // https://unsplash.com/photos/cmKPOUgdmWc (Deer)
{ id: '1460899960812-f6ee1ecaf117', caption: 'Photo by Jay Ruzesky', orientation: 'landscape', useForDemo: true }, // https://unsplash.com/photos/h13Y8vyIXNU (Walrus)
{ id: '1456926631375-92c8ce872def', caption: 'Photo by Gwen Weustink', orientation: 'landscape', useForDemo: true }, // https://unsplash.com/photos/I3C1sSXj1i8 (Leopard)
{ id: '1452274381522-521513015433', caption: 'Photo by Adam Willoughby-Knox', orientation: 'landscape', useForDemo: true }, // https://unsplash.com/photos/_snqARKTgoc (Mother and Cubs)
{ id: '1471145653077-54c6f0aae511', caption: 'Photo by Boris Smokrovic', orientation: 'landscape' }, // https://unsplash.com/photos/n0feC_PWFdk (Dragonfly)
{ id: '1471005197911-88e9d4a7834d', caption: 'Photo by Gaetano Cessati', orientation: 'landscape' }, // https://unsplash.com/photos/YOX8ZMTo7hk (Baby Crocodile)
{ id: '1470583190240-bd6bbde8a569', caption: 'Photo by Alan Emery', orientation: 'landscape' }, // https://unsplash.com/photos/emTCWiq2txk (Beetle)
{ id: '1470688090067-6d429c0b2600', caption: 'Photo by Ján Jakub Naništa', orientation: 'landscape' }, // https://unsplash.com/photos/xqjO-lx39B4 (Scottish Highland Cow)
{ id: '1470742292565-de43c4b02b57', caption: 'Photo by Eric Knoll', orientation: 'landscape' }];
// https://unsplash.com/photos/DmOCkOnx-MQ (Cheetah)
// https://unsplash.com/photos/NUMlxTPsznM coyote?
var theme = {
// container
container: {
background: 'rgba(255, 255, 255, 0.9)'
},
// arrows
arrow: {
backgroundColor: 'rgba(255, 255, 255, 0.8)',
fill: '#222',
opacity: 0.6,
transition: 'opacity 200ms',
':hover': {
opacity: 1
}
},
arrow__size__medium: {
borderRadius: 40,
height: 40,
marginTop: -20,
'@media (min-width: 768px)': {
height: 70,
padding: 15
}
},
arrow__direction__left: { marginLeft: 10 },
arrow__direction__right: { marginRight: 10 },
close: {
fill: '#D40000',
opacity: 0.6,
transition: 'all 200ms',
':hover': {
opacity: 1
}
},
// footer
footer: {
color: 'black'
},
footerCount: {
color: 'rgba(0, 0, 0, 0.6)'
},
// thumbnails
thumbnail: {},
thumbnail__active: {
boxShadow: '0 0 0 2px #00D8FF'
}
};
(0, _reactDom.render)(_react2['default'].createElement(
'div',
null,
_react2['default'].createElement(
'div',
{ style: { marginBottom: 40 } },
_react2['default'].createElement(
'p',
null,
'Photos courtesy of ',
_react2['default'].createElement(
'a',
{ href: 'https://unsplash.com/', target: '_blank' },
'Unsplash'
),
'. Use your keyboard to navigate ',
_react2['default'].createElement(
'kbd',
null,
'left'
),
' ',
_react2['default'].createElement(
'kbd',
null,
'right'
),
' ',
_react2['default'].createElement(
'kbd',
null,
'esc'
),
' — Also, try resizing your browser window.'
)
),
_react2['default'].createElement(
'h3',
null,
'Default Options'
),
_react2['default'].createElement(_componentsGallery2['default'], { images: DEFAULT_IMAGES.map(function (_ref) {
var caption = _ref.caption;
var id = _ref.id;
var orientation = _ref.orientation;
var useForDemo = _ref.useForDemo;
return {
src: makeUnsplashSrc(id),
thumbnail: makeUnsplashThumbnail(id, orientation),
srcset: [makeUnsplashSrcSet(id, 1024), makeUnsplashSrcSet(id, 800), makeUnsplashSrcSet(id, 500), makeUnsplashSrcSet(id, 320)],
caption: caption,
orientation: orientation,
useForDemo: useForDemo
};
}) }),
_react2['default'].createElement(
'h3',
null,
'With Thumbnails'
),
_react2['default'].createElement(_componentsGallery2['default'], { images: THUMBNAIL_IMAGES.map(function (_ref2) {
var caption = _ref2.caption;
var id = _ref2.id;
var orientation = _ref2.orientation;
var useForDemo = _ref2.useForDemo;
return {
src: makeUnsplashSrc(id),
thumbnail: makeUnsplashThumbnail(id, orientation),
srcset: [makeUnsplashSrcSet(id, 1024), makeUnsplashSrcSet(id, 800), makeUnsplashSrcSet(id, 500), makeUnsplashSrcSet(id, 320)],
caption: caption,
orientation: orientation,
useForDemo: useForDemo
};
}), showThumbnails: true }),
_react2['default'].createElement(
'h3',
null,
'Themed Lightbox'
),
_react2['default'].createElement(_componentsGallery2['default'], { images: THEMED_IMAGES.map(function (_ref3) {
var caption = _ref3.caption;
var id = _ref3.id;
var orientation = _ref3.orientation;
var useForDemo = _ref3.useForDemo;
return {
src: makeUnsplashSrc(id),
thumbnail: makeUnsplashThumbnail(id, orientation),
srcset: [makeUnsplashSrcSet(id, 1024), makeUnsplashSrcSet(id, 800), makeUnsplashSrcSet(id, 500), makeUnsplashSrcSet(id, 320)],
caption: caption,
orientation: orientation,
useForDemo: useForDemo
};
}), theme: theme, showThumbnails: true })
), document.getElementById('example'));
},{"./components/Gallery":2,"react":undefined,"react-dom":undefined}],2:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _aphroditeNoImportant = require('aphrodite/no-important');
var _reactImages = require('react-images');
var _reactImages2 = _interopRequireDefault(_reactImages);
var Gallery = (function (_Component) {
_inherits(Gallery, _Component);
function Gallery() {
_classCallCheck(this, Gallery);
_get(Object.getPrototypeOf(Gallery.prototype), 'constructor', this).call(this);
this.state = {
lightboxIsOpen: false,
currentImage: 0
};
this.closeLightbox = this.closeLightbox.bind(this);
this.gotoNext = this.gotoNext.bind(this);
this.gotoPrevious = this.gotoPrevious.bind(this);
this.gotoImage = this.gotoImage.bind(this);
this.handleClickImage = this.handleClickImage.bind(this);
this.openLightbox = this.openLightbox.bind(this);
}
_createClass(Gallery, [{
key: 'openLightbox',
value: function openLightbox(index, event) {
event.preventDefault();
this.setState({
currentImage: index,
lightboxIsOpen: true
});
}
}, {
key: 'closeLightbox',
value: function closeLightbox() {
this.setState({
currentImage: 0,
lightboxIsOpen: false
});
}
}, {
key: 'gotoPrevious',
value: function gotoPrevious() {
this.setState({
currentImage: this.state.currentImage - 1
});
}
}, {
key: 'gotoNext',
value: function gotoNext() {
this.setState({
currentImage: this.state.currentImage + 1
});
}
}, {
key: 'gotoImage',
value: function gotoImage(index) {
this.setState({
currentImage: index
});
}
}, {
key: 'handleClickImage',
value: function handleClickImage() {
if (this.state.currentImage === this.props.images.length - 1) return;
this.gotoNext();
}
}, {
key: 'renderGallery',
value: function renderGallery() {
var _this = this;
var images = this.props.images;
if (!images) return;
var gallery = images.filter(function (i) {
return i.useForDemo;
}).map(function (obj, i) {
return _react2['default'].createElement(
'a',
{
href: obj.src,
className: (0, _aphroditeNoImportant.css)(classes.thumbnail, classes[obj.orientation]),
key: i,
onClick: function (e) {
return _this.openLightbox(i, e);
}
},
_react2['default'].createElement('img', { src: obj.thumbnail, className: (0, _aphroditeNoImportant.css)(classes.source) })
);
});
return _react2['default'].createElement(
'div',
{ className: (0, _aphroditeNoImportant.css)(classes.gallery) },
gallery
);
}
}, {
key: 'render',
value: function render() {
return _react2['default'].createElement(
'div',
{ className: 'section' },
this.props.heading && _react2['default'].createElement(
'h2',
null,
this.props.heading
),
this.props.subheading && _react2['default'].createElement(
'p',
null,
this.props.subheading
),
this.renderGallery(),
_react2['default'].createElement(_reactImages2['default'], {
currentImage: this.state.currentImage,
images: this.props.images,
isOpen: this.state.lightboxIsOpen,
onClickImage: this.handleClickImage,
onClickNext: this.gotoNext,
onClickPrev: this.gotoPrevious,
onClickThumbnail: this.gotoImage,
onClose: this.closeLightbox,
showThumbnails: this.props.showThumbnails,
theme: this.props.theme
})
);
}
}]);
return Gallery;
})(_react.Component);
Gallery.displayName = 'Gallery';
Gallery.propTypes = {
heading: _propTypes2['default'].string,
images: _propTypes2['default'].array,
showThumbnails: _propTypes2['default'].bool,
subheading: _propTypes2['default'].string
};
var gutter = {
small: 2,
large: 4
};
var classes = _aphroditeNoImportant.StyleSheet.create({
gallery: {
marginRight: -gutter.small,
overflow: 'hidden',
'@media (min-width: 500px)': {
marginRight: -gutter.large
}
},
// anchor
thumbnail: {
boxSizing: 'border-box',
display: 'block',
float: 'left',
lineHeight: 0,
paddingRight: gutter.small,
paddingBottom: gutter.small,
overflow: 'hidden',
'@media (min-width: 500px)': {
paddingRight: gutter.large,
paddingBottom: gutter.large
}
},
// orientation
landscape: {
width: '30%'
},
square: {
paddingBottom: 0,
width: '40%',
'@media (min-width: 500px)': {
paddingBottom: 0
}
},
// actual <img />
source: {
border: 0,
display: 'block',
height: 'auto',
maxWidth: '100%',
width: 'auto'
}
});
exports['default'] = Gallery;
module.exports = exports['default'];
},{"aphrodite/no-important":8,"prop-types":undefined,"react":undefined,"react-images":undefined}],3:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var _inlineStylePrefixerStatic = require('inline-style-prefixer/static');
var _inlineStylePrefixerStatic2 = _interopRequireDefault(_inlineStylePrefixerStatic);
var _util = require('./util');
/**
* Generate CSS for a selector and some styles.
*
* This function handles the media queries, pseudo selectors, and descendant
* styles that can be used in aphrodite styles.
*
* @param {string} selector: A base CSS selector for the styles to be generated
* with.
* @param {Object} styleTypes: A list of properties of the return type of
* StyleSheet.create, e.g. [styles.red, styles.blue].
* @param stringHandlers: See `generateCSSRuleset`
* @param useImportant: See `generateCSSRuleset`
*
* To actually generate the CSS special-construct-less styles are passed to
* `generateCSSRuleset`.
*
* For instance, a call to
*
* generateCSSInner(".foo", {
* color: "red",
* "@media screen": {
* height: 20,
* ":hover": {
* backgroundColor: "black"
* }
* },
* ":active": {
* fontWeight: "bold",
* ">>bar": {
* _names: { "foo_bar": true },
* height: 10,
* }
* }
* });
*
* will make 5 calls to `generateCSSRuleset`:
*
* generateCSSRuleset(".foo", { color: "red" }, ...)
* generateCSSRuleset(".foo:active", { fontWeight: "bold" }, ...)
* generateCSSRuleset(".foo:active .foo_bar", { height: 10 }, ...)
* // These 2 will be wrapped in @media screen {}
* generateCSSRuleset(".foo", { height: 20 }, ...)
* generateCSSRuleset(".foo:hover", { backgroundColor: "black" }, ...)
*/
var generateCSS = function generateCSS(selector, styleTypes, stringHandlers, useImportant) {
var merged = styleTypes.reduce(_util.recursiveMerge);
var declarations = {};
var mediaQueries = {};
var pseudoStyles = {};
Object.keys(merged).forEach(function (key) {
if (key[0] === ':') {
pseudoStyles[key] = merged[key];
} else if (key[0] === '@') {
mediaQueries[key] = merged[key];
} else {
declarations[key] = merged[key];
}
});
return generateCSSRuleset(selector, declarations, stringHandlers, useImportant) + Object.keys(pseudoStyles).map(function (pseudoSelector) {
return generateCSSRuleset(selector + pseudoSelector, pseudoStyles[pseudoSelector], stringHandlers, useImportant);
}).join("") + Object.keys(mediaQueries).map(function (mediaQuery) {
var ruleset = generateCSS(selector, [mediaQueries[mediaQuery]], stringHandlers, useImportant);
return mediaQuery + '{' + ruleset + '}';
}).join("");
};
exports.generateCSS = generateCSS;
/**
* Helper method of generateCSSRuleset to facilitate custom handling of certain
* CSS properties. Used for e.g. font families.
*
* See generateCSSRuleset for usage and documentation of paramater types.
*/
var runStringHandlers = function runStringHandlers(declarations, stringHandlers) {
var result = {};
Object.keys(declarations).forEach(function (key) {
// If a handler exists for this particular key, let it interpret
// that value first before continuing
if (stringHandlers && stringHandlers.hasOwnProperty(key)) {
result[key] = stringHandlers[key](declarations[key]);
} else {
result[key] = declarations[key];
}
});
return result;
};
/**
* Generate a CSS ruleset with the selector and containing the declarations.
*
* This function assumes that the given declarations don't contain any special
* children (such as media queries, pseudo-selectors, or descendant styles).
*
* Note that this method does not deal with nesting used for e.g.
* psuedo-selectors or media queries. That responsibility is left to the
* `generateCSS` function.
*
* @param {string} selector: the selector associated with the ruleset
* @param {Object} declarations: a map from camelCased CSS property name to CSS
* property value.
* @param {Object.<string, function>} stringHandlers: a map from camelCased CSS
* property name to a function which will map the given value to the value
* that is output.
* @param {bool} useImportant: A boolean saying whether to append "!important"
* to each of the CSS declarations.
* @returns {string} A string of raw CSS.
*
* Examples:
*
* generateCSSRuleset(".blah", { color: "red" })
* -> ".blah{color: red !important;}"
* generateCSSRuleset(".blah", { color: "red" }, {}, false)
* -> ".blah{color: red}"
* generateCSSRuleset(".blah", { color: "red" }, {color: c => c.toUpperCase})
* -> ".blah{color: RED}"
* generateCSSRuleset(".blah:hover", { color: "red" })
* -> ".blah:hover{color: red}"
*/
var generateCSSRuleset = function generateCSSRuleset(selector, declarations, stringHandlers, useImportant) {
var handledDeclarations = runStringHandlers(declarations, stringHandlers);
var prefixedDeclarations = (0, _inlineStylePrefixerStatic2['default'])(handledDeclarations);
var prefixedRules = (0, _util.flatten)((0, _util.objectToPairs)(prefixedDeclarations).map(function (_ref) {
var _ref2 = _slicedToArray(_ref, 2);
var key = _ref2[0];
var value = _ref2[1];
if (Array.isArray(value)) {
var _ret = (function () {
// inline-style-prefix-all returns an array when there should be
// multiple rules, we will flatten to single rules
var prefixedValues = [];
var unprefixedValues = [];
value.forEach(function (v) {
if (v.indexOf('-') === 0) {
prefixedValues.push(v);
} else {
unprefixedValues.push(v);
}
});
prefixedValues.sort();
unprefixedValues.sort();
return {
v: prefixedValues.concat(unprefixedValues).map(function (v) {
return [key, v];
})
};
})();
if (typeof _ret === 'object') return _ret.v;
}
return [[key, value]];
}));
var rules = prefixedRules.map(function (_ref3) {
var _ref32 = _slicedToArray(_ref3, 2);
var key = _ref32[0];
var value = _ref32[1];
var stringValue = (0, _util.stringifyValue)(key, value);
var ret = (0, _util.kebabifyStyleName)(key) + ':' + stringValue + ';';
return useImportant === false ? ret : (0, _util.importantify)(ret);
}).join("");
if (rules) {
return selector + '{' + rules + '}';
} else {
return "";
}
};
exports.generateCSSRuleset = generateCSSRuleset;
},{"./util":7,"inline-style-prefixer/static":28}],4:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
var _util = require('./util');
var _inject = require('./inject');
var StyleSheet = {
create: function create(sheetDefinition) {
return (0, _util.mapObj)(sheetDefinition, function (_ref) {
var _ref2 = _slicedToArray(_ref, 2);
var key = _ref2[0];
var val = _ref2[1];
return [key, {
// TODO(emily): Make a 'production' mode which doesn't prepend
// the class name here, to make the generated CSS smaller.
_name: key + '_' + (0, _util.hashObject)(val),
_definition: val
}];
});
},
rehydrate: function rehydrate() {
var renderedClassNames = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0];
(0, _inject.addRenderedClassNames)(renderedClassNames);
}
};
/**
* Utilities for using Aphrodite server-side.
*/
var StyleSheetServer = {
renderStatic: function renderStatic(renderFunc) {
(0, _inject.reset)();
(0, _inject.startBuffering)();
var html = renderFunc();
var cssContent = (0, _inject.flushToString)();
return {
html: html,
css: {
content: cssContent,
renderedClassNames: (0, _inject.getRenderedClassNames)()
}
};
}
};
/**
* Utilities for using Aphrodite in tests.
*
* Not meant to be used in production.
*/
var StyleSheetTestUtils = {
/**
* Prevent styles from being injected into the DOM.
*
* This is useful in situations where you'd like to test rendering UI
* components which use Aphrodite without any of the side-effects of
* Aphrodite happening. Particularly useful for testing the output of
* components when you have no DOM, e.g. testing in Node without a fake DOM.
*
* Should be paired with a subsequent call to
* clearBufferAndResumeStyleInjection.
*/
suppressStyleInjection: function suppressStyleInjection() {
(0, _inject.reset)();
(0, _inject.startBuffering)();
},
/**
* Opposite method of preventStyleInject.
*/
clearBufferAndResumeStyleInjection: function clearBufferAndResumeStyleInjection() {
(0, _inject.reset)();
}
};
var css = function css() {
for (var _len = arguments.length, styleDefinitions = Array(_len), _key = 0; _key < _len; _key++) {
styleDefinitions[_key] = arguments[_key];
}
var useImportant = true; // Append !important to all style definitions
return (0, _inject.injectAndGetClassName)(useImportant, styleDefinitions);
};
exports['default'] = {
StyleSheet: StyleSheet,
StyleSheetServer: StyleSheetServer,
StyleSheetTestUtils: StyleSheetTestUtils,
css: css
};
module.exports = exports['default'];
},{"./inject":5,"./util":7}],5:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var _asap = require('asap');
var _asap2 = _interopRequireDefault(_asap);
var _generate = require('./generate');
var _util = require('./util');
// The current <style> tag we are inserting into, or null if we haven't
// inserted anything yet. We could find this each time using
// `document.querySelector("style[data-aphrodite"])`, but holding onto it is
// faster.
var styleTag = null;
// Inject a string of styles into a <style> tag in the head of the document. This
// will automatically create a style tag and then continue to use it for
// multiple injections. It will also use a style tag with the `data-aphrodite`
// tag on it if that exists in the DOM. This could be used for e.g. reusing the
// same style tag that server-side rendering inserts.
var injectStyleTag = function injectStyleTag(cssContents) {
if (styleTag == null) {
// Try to find a style tag with the `data-aphrodite` attribute first.
styleTag = document.querySelector("style[data-aphrodite]");
// If that doesn't work, generate a new style tag.
if (styleTag == null) {
// Taken from
// http://stackoverflow.com/questions/524696/how-to-create-a-style-tag-with-javascript
var head = document.head || document.getElementsByTagName('head')[0];
styleTag = document.createElement('style');
styleTag.type = 'text/css';
styleTag.setAttribute("data-aphrodite", "");
head.appendChild(styleTag);
}
}
if (styleTag.styleSheet) {
styleTag.styleSheet.cssText += cssContents;
} else {
styleTag.appendChild(document.createTextNode(cssContents));
}
};
// Custom handlers for stringifying CSS values that have side effects
// (such as fontFamily, which can cause @font-face rules to be injected)
var stringHandlers = {
// With fontFamily we look for objects that are passed in and interpret
// them as @font-face rules that we need to inject. The value of fontFamily
// can either be a string (as normal), an object (a single font face), or
// an array of objects and strings.
fontFamily: function fontFamily(val) {
if (Array.isArray(val)) {
return val.map(fontFamily).join(",");
} else if (typeof val === "object") {
injectStyleOnce(val.fontFamily, "@font-face", [val], false);
return '"' + val.fontFamily + '"';
} else {
return val;
}
},
// With animationName we look for an object that contains keyframes and
// inject them as an `@keyframes` block, returning a uniquely generated
// name. The keyframes object should look like
// animationName: {
// from: {
// left: 0,
// top: 0,
// },
// '50%': {
// left: 15,
// top: 5,
// },
// to: {
// left: 20,
// top: 20,
// }
// }
// TODO(emily): `stringHandlers` doesn't let us rename the key, so I have
// to use `animationName` here. Improve that so we can call this
// `animation` instead of `animationName`.
animationName: function animationName(val) {
if (typeof val !== "object") {
return val;
}
// Generate a unique name based on the hash of the object. We can't
// just use the hash because the name can't start with a number.
// TODO(emily): this probably makes debugging hard, allow a custom
// name?
var name = 'keyframe_' + (0, _util.hashObject)(val);
// Since keyframes need 3 layers of nesting, we use `generateCSS` to
// build the inner layers and wrap it in `@keyframes` ourselves.
var finalVal = '@keyframes ' + name + '{';
Object.keys(val).forEach(function (key) {
finalVal += (0, _generate.generateCSS)(key, [val[key]], stringHandlers, false);
});
finalVal += '}';
injectGeneratedCSSOnce(name, finalVal);
return name;
}
};
// This is a map from Aphrodite's generated class names to `true` (acting as a
// set of class names)
var alreadyInjected = {};
// This is the buffer of styles which have not yet been flushed.
var injectionBuffer = "";
// A flag to tell if we are already buffering styles. This could happen either
// because we scheduled a flush call already, so newly added styles will
// already be flushed, or because we are statically buffering on the server.
var isBuffering = false;
var injectGeneratedCSSOnce = function injectGeneratedCSSOnce(key, generatedCSS) {
if (!alreadyInjected[key]) {
if (!isBuffering) {
// We should never be automatically buffering on the server (or any
// place without a document), so guard against that.
if (typeof document === "undefined") {
throw new Error("Cannot automatically buffer without a document");
}
// If we're not already buffering, schedule a call to flush the
// current styles.
isBuffering = true;
(0, _asap2['default'])(flushToStyleTag);
}
injectionBuffer += generatedCSS;
alreadyInjected[key] = true;
}
};
var injectStyleOnce = function injectStyleOnce(key, selector, definitions, useImportant) {
if (!alreadyInjected[key]) {
var generated = (0, _generate.generateCSS)(selector, definitions, stringHandlers, useImportant);
injectGeneratedCSSOnce(key, generated);
}
};
exports.injectStyleOnce = injectStyleOnce;
var reset = function reset() {
injectionBuffer = "";
alreadyInjected = {};
isBuffering = false;
styleTag = null;
};
exports.reset = reset;
var startBuffering = function startBuffering() {
if (isBuffering) {
throw new Error("Cannot buffer while already buffering");
}
isBuffering = true;
};
exports.startBuffering = startBuffering;
var flushToString = function flushToString() {
isBuffering = false;
var ret = injectionBuffer;
injectionBuffer = "";
return ret;
};
exports.flushToString = flushToString;
var flushToStyleTag = function flushToStyleTag() {
var cssContent = flushToString();
if (cssContent.length > 0) {
injectStyleTag(cssContent);
}
};
exports.flushToStyleTag = flushToStyleTag;
var getRenderedClassNames = function getRenderedClassNames() {
return Object.keys(alreadyInjected);
};
exports.getRenderedClassNames = getRenderedClassNames;
var addRenderedClassNames = function addRenderedClassNames(classNames) {
classNames.forEach(function (className) {
alreadyInjected[className] = true;
});
};
exports.addRenderedClassNames = addRenderedClassNames;
/**
* Inject styles associated with the passed style definition objects, and return
* an associated CSS class name.
*
* @param {boolean} useImportant If true, will append !important to generated
* CSS output. e.g. {color: red} -> "color: red !important".
* @param {Object[]} styleDefinitions style definition objects as returned as
* properties of the return value of StyleSheet.create().
*/
var injectAndGetClassName = function injectAndGetClassName(useImportant, styleDefinitions) {
// Filter out falsy values from the input, to allow for
// `css(a, test && c)`
var validDefinitions = styleDefinitions.filter(function (def) {
return def;
});
// Break if there aren't any valid styles.
if (validDefinitions.length === 0) {
return "";
}
var className = validDefinitions.map(function (s) {
return s._name;
}).join("-o_O-");
injectStyleOnce(className, '.' + className, validDefinitions.map(function (d) {
return d._definition;
}), useImportant);
return className;
};
exports.injectAndGetClassName = injectAndGetClassName;
},{"./generate":3,"./util":7,"asap":9}],6:[function(require,module,exports){
// Module with the same interface as the core aphrodite module,
// except that styles injected do not automatically have !important
// appended to them.
//
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var _inject = require('./inject');
var _indexJs = require('./index.js');
var css = function css() {
for (var _len = arguments.length, styleDefinitions = Array(_len), _key = 0; _key < _len; _key++) {
styleDefinitions[_key] = arguments[_key];
}
var useImportant = false; // Don't append !important to style definitions
return (0, _inject.injectAndGetClassName)(useImportant, styleDefinitions);
};
exports.StyleSheet = _indexJs.StyleSheet;
exports.StyleSheetServer = _indexJs.StyleSheetServer;
exports.StyleSheetTestUtils = _indexJs.StyleSheetTestUtils;
exports.css = css;
},{"./index.js":4,"./inject":5}],7:[function(require,module,exports){
// {K1: V1, K2: V2, ...} -> [[K1, V1], [K2, V2]]
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var objectToPairs = function objectToPairs(obj) {
return Object.keys(obj).map(function (key) {
return [key, obj[key]];
});
};
exports.objectToPairs = objectToPairs;
// [[K1, V1], [K2, V2]] -> {K1: V1, K2: V2, ...}
var pairsToObject = function pairsToObject(pairs) {
var result = {};
pairs.forEach(function (_ref) {
var _ref2 = _slicedToArray(_ref, 2);
var key = _ref2[0];
var val = _ref2[1];
result[key] = val;
});
return result;
};
var mapObj = function mapObj(obj, fn) {
return pairsToObject(objectToPairs(obj).map(fn));
};
exports.mapObj = mapObj;
// Flattens an array one level
// [[A], [B, C, [D]]] -> [A, B, C, [D]]
var flatten = function flatten(list) {
return list.reduce(function (memo, x) {
return memo.concat(x);
}, []);
};
exports.flatten = flatten;
var UPPERCASE_RE = /([A-Z])/g;
var MS_RE = /^ms-/;
var kebabify = function kebabify(string) {
return string.replace(UPPERCASE_RE, '-$1').toLowerCase();
};
var kebabifyStyleName = function kebabifyStyleName(string) {
return kebabify(string).replace(MS_RE, '-ms-');
};
exports.kebabifyStyleName = kebabifyStyleName;
var recursiveMerge = function recursiveMerge(a, b) {
// TODO(jlfwong): Handle malformed input where a and b are not the same
// type.
if (typeof a !== 'object') {
return b;
}
var ret = _extends({}, a);
Object.keys(b).forEach(function (key) {
if (ret.hasOwnProperty(key)) {
ret[key] = recursiveMerge(a[key], b[key]);
} else {
ret[key] = b[key];
}
});
return ret;
};
exports.recursiveMerge = recursiveMerge;
/**
* CSS properties which accept numbers but are not in units of "px".
* Taken from React's CSSProperty.js
*/
var isUnitlessNumber = {
animationIterationCount: true,
borderImageOutset: true,
borderImageSlice: true,
borderImageWidth: true,
boxFlex: true,
boxFlexGroup: true,
boxOrdinalGroup: true,
columnCount: true,
flex: true,
flexGrow: true,
flexPositive: true,
flexShrink: true,
flexNegative: true,
flexOrder: true,
gridRow: true,
gridColumn: true,
fontWeight: true,
lineClamp: true,
lineHeight: true,
opacity: true,
order: true,
orphans: true,
tabSize: true,
widows: true,
zIndex: true,
zoom: true,
// SVG-related properties
fillOpacity: true,
floodOpacity: true,
stopOpacity: true,
strokeDasharray: true,
strokeDashoffset: true,
strokeMiterlimit: true,
strokeOpacity: true,
strokeWidth: true
};
/**
* Taken from React's CSSProperty.js
*
* @param {string} prefix vendor-specific prefix, eg: Webkit
* @param {string} key style name, eg: transitionDuration
* @return {string} style name prefixed with `prefix`, properly camelCased, eg:
* WebkitTransitionDuration
*/
function prefixKey(prefix, key) {
return prefix + key.charAt(0).toUpperCase() + key.substring(1);
}
/**
* Support style names that may come passed in prefixed by adding permutations
* of vendor prefixes.
* Taken from React's CSSProperty.js
*/
var prefixes = ['Webkit', 'ms', 'Moz', 'O'];
// Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an
// infinite loop, because it iterates over the newly added props too.
// Taken from React's CSSProperty.js
Object.keys(isUnitlessNumber).forEach(function (prop) {
prefixes.forEach(function (prefix) {
isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop];
});
});
var stringifyValue = function stringifyValue(key, prop) {
if (typeof prop === "number") {
if (isUnitlessNumber[key]) {
return "" + prop;
} else {
return prop + "px";
}
} else {
return prop;
}
};
exports.stringifyValue = stringifyValue;
/**
* JS Implementation of MurmurHash2
*
* @author <a href="mailto:gary.court@gmail.com">Gary Court</a>
* @see http://github.com/garycourt/murmurhash-js
* @author <a href="mailto:aappleby@gmail.com">Austin Appleby</a>
* @see http://sites.google.com/site/murmurhash/
*
* @param {string} str ASCII only
* @return {string} Base 36 encoded hash result
*/
function murmurhash2_32_gc(str) {
var l = str.length;
var h = l;
var i = 0;
var k = undefined;
while (l >= 4) {
k = str.charCodeAt(i) & 0xff | (str.charCodeAt(++i) & 0xff) << 8 | (str.charCodeAt(++i) & 0xff) << 16 | (str.charCodeAt(++i) & 0xff) << 24;
k = (k & 0xffff) * 0x5bd1e995 + (((k >>> 16) * 0x5bd1e995 & 0xffff) << 16);
k ^= k >>> 24;
k = (k & 0xffff) * 0x5bd1e995 + (((k >>> 16) * 0x5bd1e995 & 0xffff) << 16);
h = (h & 0xffff) * 0x5bd1e995 + (((h >>> 16) * 0x5bd1e995 & 0xffff) << 16) ^ k;
l -= 4;
++i;
}
switch (l) {
case 3:
h ^= (str.charCodeAt(i + 2) & 0xff) << 16;
case 2:
h ^= (str.charCodeAt(i + 1) & 0xff) << 8;
case 1:
h ^= str.charCodeAt(i) & 0xff;
h = (h & 0xffff) * 0x5bd1e995 + (((h >>> 16) * 0x5bd1e995 & 0xffff) << 16);
}
h ^= h >>> 13;
h = (h & 0xffff) * 0x5bd1e995 + (((h >>> 16) * 0x5bd1e995 & 0xffff) << 16);
h ^= h >>> 15;
return (h >>> 0).toString(36);
}
// Hash a javascript object using JSON.stringify. This is very fast, about 3
// microseconds on my computer for a sample object:
// http://jsperf.com/test-hashfnv32a-hash/5
//
// Note that this uses JSON.stringify to stringify the objects so in order for
// this to produce consistent hashes browsers need to have a consistent
// ordering of objects. Ben Alpert says that Facebook depends on this, so we
// can probably depend on this too.
var hashObject = function hashObject(object) {
return murmurhash2_32_gc(JSON.stringify(object));
};
exports.hashObject = hashObject;
var IMPORTANT_RE = /^([^:]+:.*?)( !important)?;$/;
// Given a single style rule string like "a: b;", adds !important to generate
// "a: b !important;".
var importantify = function importantify(string) {
return string.replace(IMPORTANT_RE, function (_, base, important) {
return base + " !important;";
});
};
exports.importantify = importantify;
},{}],8:[function(require,module,exports){
module.exports = require('./lib/no-important.js');
},{"./lib/no-important.js":6}],9:[function(require,module,exports){
"use strict";
// rawAsap provides everything we need except exception management.
var rawAsap = require("./raw");
// RawTasks are recycled to reduce GC churn.
var freeTasks = [];
// We queue errors to ensure they are thrown in right order (FIFO).
// Array-as-queue is good enough here, since we are just dealing with exceptions.
var pendingErrors = [];
var requestErrorThrow = rawAsap.makeRequestCallFromTimer(throwFirstError);
function throwFirstError() {
if (pendingErrors.length) {
throw pendingErrors.shift();
}
}
/**
* Calls a task as soon as possible after returning, in its own event, with priority
* over other events like animation, reflow, and repaint. An error thrown from an
* event will not interrupt, nor even substantially slow down the processing of
* other events, but will be rather postponed to a lower priority event.
* @param {{call}} task A callable object, typically a function that takes no
* arguments.
*/
module.exports = asap;
function asap(task) {
var rawTask;
if (freeTasks.length) {
rawTask = freeTasks.pop();
} else {
rawTask = new RawTask();
}
rawTask.task = task;
rawAsap(rawTask);
}
// We wrap tasks with recyclable task objects. A task object implements
// `call`, just like a function.
function RawTask() {
this.task = null;
}
// The sole purpose of wrapping the task is to catch the exception and recycle
// the task object after its single use.
RawTask.prototype.call = function () {
try {
this.task.call();
} catch (error) {
if (asap.onerror) {
// This hook exists purely for testing purposes.
// Its name will be periodically randomized to break any code that
// depends on its existence.
asap.onerror(error);
} else {
// In a web browser, exceptions are not fatal. However, to avoid
// slowing down the queue of pending tasks, we rethrow the error in a
// lower priority turn.
pendingErrors.push(error);
requestErrorThrow();
}
} finally {
this.task = null;
freeTasks[freeTasks.length] = this;
}
};
},{"./raw":10}],10:[function(require,module,exports){
(function (global){
"use strict";
// Use the fastest means possible to execute a task in its own turn, with
// priority over other events including IO, animation, reflow, and redraw
// events in browsers.
//
// An exception thrown by a task will permanently interrupt the processing of
// subsequent tasks. The higher level `asap` function ensures that if an
// exception is thrown by a task, that the task queue will continue flushing as
// soon as possible, but if you use `rawAsap` directly, you are responsible to
// either ensure that no exceptions are thrown from your task, or to manually
// call `rawAsap.requestFlush` if an exception is thrown.
module.exports = rawAsap;
function rawAsap(task) {
if (!queue.length) {
requestFlush();
flushing = true;
}
// Equivalent to push, but avoids a function call.
queue[queue.length] = task;
}
var queue = [];
// Once a flush has been requested, no further calls to `requestFlush` are
// necessary until the next `flush` completes.
var flushing = false;
// `requestFlush` is an implementation-specific method that attempts to kick
// off a `flush` event as quickly as possible. `flush` will attempt to exhaust
// the event queue before yielding to the browser's own event loop.
var requestFlush;
// The position of the next task to execute in the task queue. This is
// preserved between calls to `flush` so that it can be resumed if
// a task throws an exception.
var index = 0;
// If a task schedules additional tasks recursively, the task queue can grow
// unbounded. To prevent memory exhaustion, the task queue will periodically
// truncate already-completed tasks.
var capacity = 1024;
// The flush function processes all tasks that have been scheduled with
// `rawAsap` unless and until one of those tasks throws an exception.
// If a task throws an exception, `flush` ensures that its state will remain
// consistent and will resume where it left off when called again.
// However, `flush` does not make any arrangements to be called again if an
// exception is thrown.
function flush() {
while (index < queue.length) {
var currentIndex = index;
// Advance the index before calling the task. This ensures that we will
// begin flushing on the next task the task throws an error.
index = index + 1;
queue[currentIndex].call();
// Prevent leaking memory for long chains of recursive calls to `asap`.
// If we call `asap` within tasks scheduled by `asap`, the queue will
// grow, but to avoid an O(n) walk for every task we execute, we don't
// shift tasks off the queue after they have been executed.
// Instead, we periodically shift 1024 tasks off the queue.
if (index > capacity) {
// Manually shift all values starting at the index back to the
// beginning of the queue.
for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) {
queue[scan] = queue[scan + index];
}
queue.length -= index;
index = 0;
}
}
queue.length = 0;
index = 0;
flushing = false;
}
// `requestFlush` is implemented using a strategy based on data collected from
// every available SauceLabs Selenium web driver worker at time of writing.
// https://docs.google.com/spreadsheets/d/1mG-5UYGup5qxGdEMWkhP6BWCz053NUb2E1QoUTU16uA/edit#gid=783724593
// Safari 6 and 6.1 for desktop, iPad, and iPhone are the only browsers that
// have WebKitMutationObserver but not un-prefixed MutationObserver.
// Must use `global` or `self` instead of `window` to work in both frames and web
// workers. `global` is a provision of Browserify, Mr, Mrs, or Mop.
/* globals self */
var scope = typeof global !== "undefined" ? global : self;
var BrowserMutationObserver = scope.MutationObserver || scope.WebKitMutationObserver;
// MutationObservers are desirable because they have high priority and work
// reliably everywhere they are implemented.
// They are implemented in all modern browsers.
//
// - Android 4-4.3
// - Chrome 26-34
// - Firefox 14-29
// - Internet Explorer 11
// - iPad Safari 6-7.1
// - iPhone Safari 7-7.1
// - Safari 6-7
if (typeof BrowserMutationObserver === "function") {
requestFlush = makeRequestCallFromMutationObserver(flush);
// MessageChannels are desirable because they give direct access to the HTML
// task queue, are implemented in Internet