@shopify/polaris
Version:
Shopify’s product component library
880 lines (790 loc) • 29.3 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var _classCallCheck = _interopDefault(require('babel-runtime/helpers/classCallCheck'));
var _createClass = _interopDefault(require('babel-runtime/helpers/createClass'));
var _possibleConstructorReturn = _interopDefault(require('babel-runtime/helpers/possibleConstructorReturn'));
var _inherits = _interopDefault(require('babel-runtime/helpers/inherits'));
var React = require('react');
var tslib_1 = require('tslib');
var _shopify_javascriptUtilities_decorators = require('@shopify/javascript-utilities/decorators');
var _typeof = _interopDefault(require('babel-runtime/helpers/typeof'));
var _toConsumableArray = _interopDefault(require('babel-runtime/helpers/toConsumableArray'));
var PropTypes = require('prop-types');
var hoistStatics = _interopDefault(require('hoist-non-react-statics'));
var _shopify_reactUtilities_components = require('@shopify/react-utilities/components');
// tslint:disable-next-line no-require-imports no-var-requires
var CoreWeakMap = require('core-js/library/es6/weak-map');
var Messenger = function () {
function Messenger(target, handlers, options) {
_classCallCheck(this, Messenger);
this.target = target;
this.handlers = handlers;
this.targetOrigin = '*';
this.queue = [];
this.callbacks = {};
this.callbacksToID = new CoreWeakMap();
this.callbackIndex = 0;
if (typeof window === 'undefined') {
return;
}
this.name = options.name;
this.targetOrigin = options.targetOrigin;
this.debug = options.debug || false;
if (!this.targetOrigin.match(/^http(s)?:\/\//)) {
this.warn('warning: targetOrigin should include the protocol');
}
window.addEventListener('message', this.handleMessage.bind(this), false);
}
_createClass(Messenger, [{
key: 'setTarget',
value: function setTarget(target) {
this.target = target;
this.tryToDequeue();
}
}, {
key: 'send',
value: function send(message, data) {
var normalizedPayload = this.normalizePayload(data);
var newMessage = {
message: message,
data: normalizedPayload
};
var messageString = JSON.stringify(newMessage);
if (this.target != null) {
this.log('Posting message: ' + messageString + ' to ' + this.targetOrigin + ' }');
this.target.postMessage(messageString, this.targetOrigin);
} else {
this.log('Queueing message: ' + messageString);
this.queue.push(newMessage);
}
return normalizedPayload;
}
}, {
key: 'tryToDequeue',
value: function tryToDequeue() {
var queue = this.queue,
target = this.target;
if (target == null || queue.length === 0) {
return;
}
this.queue.forEach(function (message) {
target.postMessage(message, '*');
});
this.queue.length = 0;
}
}, {
key: 'log',
value: function log(message) {
if (!this.debug) {
return;
}
// tslint:disable-next-line no-console
console.log('[' + this.name + ' Messenger]: ' + message);
}
}, {
key: 'warn',
value: function warn(message) {
if (!this.debug) {
return;
}
// tslint:disable-next-line no-console
console.warn('[' + this.name + ' Messenger]: ' + message);
}
}, {
key: 'storeCallback',
value: function storeCallback(callback) {
// Optimization, so we don't store a new callback ID for callbacks
// we have sent before
if (this.callbacksToID.has(callback)) {
return this.callbacksToID.get(callback);
}
var id = 'EASDKCallback' + this.callbackIndex++;
this.callbacks[id] = callback;
this.callbacksToID.set(callback, id);
return id;
}
}, {
key: 'normalizePayload',
value: function normalizePayload(payload) {
var _this = this;
if (payload == null) {
return payload;
}
if (typeof payload === 'function') {
return this.storeCallback(payload);
} else if (payload instanceof Array) {
return payload.map(function (newPayload) {
return _this.normalizePayload(newPayload);
});
} else if ((typeof payload === 'undefined' ? 'undefined' : _typeof(payload)) === 'object') {
return Object.keys(payload).reduce(function (newPayload, key) {
newPayload[key] = _this.normalizePayload(payload[key]);
return newPayload;
}, {});
} else {
return payload;
}
}
}, {
key: 'handleMessage',
value: function handleMessage(event) {
if (!this.isFromTargetOrigin(event)) {
this.log('client received ' + event.data + ' from unknown origin ' + event.origin + '. Expected ' + this.targetOrigin);
return;
}
this.log('Received message: ' + event.data + ' from ' + event.origin);
var receivedMessage = void 0;
try {
receivedMessage = JSON.parse(event.data);
} catch (error) {
// tslint:disable-next-line
console.error('Received received invalid JSON and cannot process the message. ' + error + ' : ' + event.data + ' : ' + JSON.stringify(event.data));
return;
}
this.invokeCallback(receivedMessage);
this.invokeHandler(receivedMessage);
}
}, {
key: 'isFromTargetOrigin',
value: function isFromTargetOrigin(_ref) {
var origin = _ref.origin;
return origin != null && origin === this.targetOrigin;
}
}, {
key: 'invokeCallback',
value: function invokeCallback(receivedMessage) {
var callback = this.callbacks[receivedMessage.message];
if (typeof callback === 'function') {
callback();
}
}
}, {
key: 'invokeHandler',
value: function invokeHandler(receivedMessage) {
var handler = this.handlers[receivedMessage.message];
if (typeof handler === 'function') {
handler(receivedMessage.data);
}
}
}]);
return Messenger;
}();
function transformBreadcrumb(breadcrumb) {
if (breadcrumb.content == null) {
throw new Error('No content provided for breadcrumb (' + JSON.stringify(breadcrumb) + ')');
}
var target = void 0;
if (breadcrumb.target) {
target = breadcrumb.target;
} else if (breadcrumb.url) {
target = getTargetFromURL(breadcrumb.url);
} else {
target = undefined;
}
return {
label: breadcrumb.content,
href: breadcrumb.url,
target: target,
message: target === 'app' ? generateCallback(breadcrumb.url) : breadcrumb.onAction
};
}
function transformAction(action) {
var style = void 0;
if (action.disabled) {
style = 'disabled';
} else if (action.destructive) {
style = 'danger';
}
var target = void 0;
if (action.target) {
target = action.target;
} else if (action.url) {
target = getTargetFromURL(action.url);
} else {
target = undefined;
}
return {
label: action.content,
href: action.url,
target: target,
message: target === 'app' ? generateCallback(action.url) : action.onAction,
style: style
};
}
function transformActionGroup(actionGroup) {
return {
type: 'dropdown',
label: actionGroup.title,
links: actionGroup.actions.map(transformAction)
};
}
function getTargetFromURL(url) {
if (url[0] === '/') {
return 'shopify';
} else if (url.indexOf(window.location.hostname) >= 0 || url[0] !== '/' && url.indexOf('http') !== 0) {
return 'app';
} else {
return 'new';
}
}
function generateCallback(url) {
if (url == null) {
return;
}
return function () {
window.location.assign(url);
};
}
function transformPagination(pagination) {
if (pagination == null) {
return undefined;
}
var hasNext = pagination.hasNext,
hasPrevious = pagination.hasPrevious,
nextURL = pagination.nextURL,
previousURL = pagination.previousURL,
onNext = pagination.onNext,
onPrevious = pagination.onPrevious;
var finalPagination = {};
if (hasNext) {
if (onNext) {
finalPagination.next = { message: onNext };
} else if (nextURL) {
finalPagination.next = { href: nextURL };
}
}
if (hasPrevious) {
if (onPrevious) {
finalPagination.previous = { message: onPrevious };
} else if (previousURL) {
finalPagination.previous = { href: previousURL };
}
}
return finalPagination;
}
var Bar = function () {
function Bar(messenger) {
_classCallCheck(this, Bar);
this.messenger = messenger;
}
_createClass(Bar, [{
key: 'update',
value: function update(config) {
var title = config.title,
icon = config.icon,
breadcrumbs = config.breadcrumbs,
secondaryActions = config.secondaryActions,
actionGroups = config.actionGroups,
primaryAction = config.primaryAction,
pagination = config.pagination;
this.messenger.send('Shopify.API.Bar.initialize', {
buttons: {
primary: primaryAction ? transformAction(primaryAction) : undefined,
secondary: [].concat(_toConsumableArray((secondaryActions || []).map(transformAction)), _toConsumableArray((actionGroups || []).map(transformActionGroup)))
},
title: title,
icon: icon,
breadcrumb: getLastLevelBreadcrumb(breadcrumbs),
pagination: transformPagination(pagination)
});
if (actionGroups) {
document.addEventListener('click', this.closeDropdown);
} else {
document.removeEventListener('click', this.closeDropdown);
}
}
}, {
key: 'closeDropdown',
value: function closeDropdown() {
this.messenger.send('Shopify.API.Bar.closeDropdown');
}
}]);
return Bar;
}();
tslib_1.__decorate([_shopify_javascriptUtilities_decorators.autobind], Bar.prototype, "closeDropdown", null);
function getLastLevelBreadcrumb(breadcrumbs) {
return breadcrumbs && breadcrumbs.length > 0 ? transformBreadcrumb(breadcrumbs[breadcrumbs.length - 1]) : undefined;
}
var Modal = function () {
function Modal(messenger) {
_classCallCheck(this, Modal);
this.messenger = messenger;
}
_createClass(Modal, [{
key: 'open',
value: function open(config) {
var title = config.title,
primaryAction = config.primaryAction,
secondaryActions = config.secondaryActions,
src = config.src,
width = config.width,
height = config.height,
onClose = config.onClose;
if (onClose != null) {
this.storeCloseCallback(onClose);
}
this.messenger.send('Shopify.API.Modal.open', {
src: src,
title: title,
width: width,
height: height,
buttons: {
primary: primaryAction ? transformAction(primaryAction) : undefined,
secondary: secondaryActions ? secondaryActions.map(transformAction) : undefined
}
});
}
}, {
key: 'alert',
value: function alert(config) {
var children = config.children,
title = config.title,
destructive = config.destructive,
confirmContent = config.confirmContent,
cancelContent = config.cancelContent,
onCancel = config.onCancel,
onConfirm = config.onConfirm;
this.storeCloseCallback(function (result) {
if (result) {
if (onConfirm) {
onConfirm();
}
} else {
if (onCancel) {
onCancel();
}
}
});
if (onCancel && cancelContent) {
this.messenger.send('Shopify.API.Modal.confirm', {
message: {
title: title,
message: children,
okButton: confirmContent,
cancelButton: cancelContent,
style: destructive ? 'danger' : undefined
}
});
} else {
this.messenger.send('Shopify.API.Modal.alert', {
message: {
title: title,
message: children,
okButton: confirmContent,
style: destructive ? 'danger' : undefined
}
});
}
}
}, {
key: 'close',
value: function close(result, data) {
if (this.closeCallback == null) {
return;
}
this.messenger.send('Shopify.API.Modal.close', {
result: result,
data: data
});
}
}, {
key: 'storeCloseCallback',
value: function storeCloseCallback(callback) {
this.closeCallback = callback;
}
}, {
key: 'callCloseCallback',
value: function callCloseCallback(result, data) {
var closeCallback = this.closeCallback;
if (typeof closeCallback === 'function') {
delete this.closeCallback;
closeCallback(result, data);
}
}
}]);
return Modal;
}();
var ResourcePicker = function () {
function ResourcePicker(messenger, modal) {
_classCallCheck(this, ResourcePicker);
this.messenger = messenger;
this.modal = modal;
}
_createClass(ResourcePicker, [{
key: 'close',
value: function close() {
this.modal.close();
}
}, {
key: 'open',
value: function open(_ref) {
var title = _ref.title,
products = _ref.products,
collections = _ref.collections,
_ref$allowMultiple = _ref.allowMultiple,
allowMultiple = _ref$allowMultiple === undefined ? false : _ref$allowMultiple,
onCancel = _ref.onCancel,
onSelection = _ref.onSelection;
this.modal.storeCloseCallback(function (success, data) {
if (!success) {
if (onCancel != null) {
onCancel();
}
return;
}
if (onSelection == null) {
return;
}
onSelection(data);
});
var resources = [];
if (products) {
resources.push('products');
}
if (collections) {
resources.push('collections');
}
if (collections) {
this.messenger.send('Shopify.API.Modal.collectionPicker', {
title: title,
selectMultiple: allowMultiple,
selectable_resources: resources
});
} else {
this.messenger.send('Shopify.API.Modal.productPicker', {
title: title,
selectMultiple: allowMultiple,
selectable_resources: resources
});
}
}
}]);
return ResourcePicker;
}();
var EASDK$1 = function () {
function EASDK(_ref, metadata) {
var _this = this;
var apiKey = _ref.apiKey,
shopOrigin = _ref.shopOrigin,
debug = _ref.debug,
forceRedirect = _ref.forceRedirect;
_classCallCheck(this, EASDK);
checkFrameRedirect(apiKey, shopOrigin, forceRedirect);
this.messenger = new Messenger(window.parent, {
'Shopify.API.initialize': function ShopifyAPIInitialize(data) {
if (data && data.User && data.User.current) {
_this.currentUser = data.User.current;
}
},
'Shopify.API.Modal.close': function ShopifyAPIModalClose(_ref2) {
var result = _ref2.result,
data = _ref2.data;
_this.Modal.callCloseCallback(result, data);
}
}, {
name: 'iframe',
targetOrigin: shopOrigin,
debug: debug
});
this.Bar = new Bar(this.messenger);
this.Modal = new Modal(this.messenger);
this.ResourcePicker = new ResourcePicker(this.messenger, this.Modal);
this.messenger.send('Shopify.API.initialize', { apiKey: apiKey, shopOrigin: shopOrigin, metadata: metadata, debug: debug, forceRedirect: forceRedirect });
}
_createClass(EASDK, [{
key: 'startLoading',
value: function startLoading() {
this.messenger.send('Shopify.API.Bar.loading.on');
}
}, {
key: 'stopLoading',
value: function stopLoading() {
this.messenger.send('Shopify.API.Bar.loading.off');
}
}, {
key: 'showFlashNotice',
value: function showFlashNotice(message) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var _options$error = options.error,
error = _options$error === undefined ? false : _options$error;
var type = error ? 'Shopify.API.flash.error' : 'Shopify.API.flash.notice';
this.messenger.send(type, { message: message });
}
}, {
key: 'pushState',
value: function pushState(location) {
this.messenger.send('Shopify.API.pushState', { location: location });
}
}, {
key: 'redirect',
value: function redirect(location) {
this.messenger.send('Shopify.API.redirect', { location: location });
}
}]);
return EASDK;
}();
tslib_1.__decorate([_shopify_javascriptUtilities_decorators.autobind], EASDK$1.prototype, "startLoading", null);
tslib_1.__decorate([_shopify_javascriptUtilities_decorators.autobind], EASDK$1.prototype, "stopLoading", null);
tslib_1.__decorate([_shopify_javascriptUtilities_decorators.autobind], EASDK$1.prototype, "showFlashNotice", null);
tslib_1.__decorate([_shopify_javascriptUtilities_decorators.autobind], EASDK$1.prototype, "pushState", null);
tslib_1.__decorate([_shopify_javascriptUtilities_decorators.autobind], EASDK$1.prototype, "redirect", null);
function checkFrameRedirect(apiKey) {
var shopOrigin = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'https://myshopify.com';
var forceRedirect = arguments[2];
if (window !== window.parent) {
return;
}
var redirectUrl = shopOrigin + '/admin/apps/';
if (apiKey) {
redirectUrl = '' + redirectUrl + apiKey + window.location.pathname + window.location.search;
}
if (forceRedirect) {
window.location.assign(redirectUrl);
} else {
// tslint:disable-next-line no-console
console.error('Embedded app was not loaded in an iframe and redirecting is disabled. Set forceRedirect to true and this page will redirect to: ' + redirectUrl);
}
}
var contextTypes = {
easdk: PropTypes.instanceOf(EASDK$1)
};
function withEASDK() {
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
displayName = _ref.displayName;
return function addEASDK(WrappedComponent) {
var WithEASDK = function (_React$Component) {
_inherits(WithEASDK, _React$Component);
function WithEASDK() {
_classCallCheck(this, WithEASDK);
return _possibleConstructorReturn(this, (WithEASDK.__proto__ || Object.getPrototypeOf(WithEASDK)).apply(this, arguments));
}
_createClass(WithEASDK, [{
key: 'render',
value: function render() {
// TODO: should remove the cast once https://github.com/Microsoft/TypeScript/issues/10727 is resolved
var props = Object.assign({}, this.props, { easdk: this.context.easdk });
return React.createElement(WrappedComponent, props);
}
}]);
return WithEASDK;
}(React.Component);
WithEASDK.displayName = 'withEASDK(' + (displayName || _shopify_reactUtilities_components.getDisplayName(WrappedComponent)) + ')';
WithEASDK.WrappedComponent = WrappedComponent;
WithEASDK.contextTypes = contextTypes;
var FinalComponent = hoistStatics(WithEASDK, WrappedComponent);
return FinalComponent;
};
}
var Alert$1 = function (_React$PureComponent) {
_inherits(Alert, _React$PureComponent);
function Alert() {
_classCallCheck(this, Alert);
var _this = _possibleConstructorReturn(this, (Alert.__proto__ || Object.getPrototypeOf(Alert)).apply(this, arguments));
_this.focusReturnPoint = null;
return _this;
}
_createClass(Alert, [{
key: 'componentDidMount',
value: function componentDidMount() {
var open = this.props.open;
if (open) {
this.handleEASDKMessaging();
this.focusReturnPoint = document.activeElement;
}
}
}, {
key: 'componentDidUpdate',
value: function componentDidUpdate(_ref) {
var wasOpen = _ref.open;
var open = this.props.open;
if (wasOpen !== open) {
this.handleEASDKMessaging();
}
if (!wasOpen && open) {
this.focusReturnPoint = document.activeElement;
} else if (wasOpen && !open && this.focusReturnPoint != null && document.contains(this.focusReturnPoint)) {
this.focusReturnPoint.focus();
this.focusReturnPoint = null;
}
}
// tslint:disable-next-line prefer-function-over-method
}, {
key: 'render',
value: function render() {
return null;
}
}, {
key: 'handleEASDKMessaging',
value: function handleEASDKMessaging() {
var _props = this.props,
open = _props.open,
easdk = _props.easdk;
if (easdk == null) {
return;
}
if (open) {
easdk.Modal.alert(this.props);
} else {
easdk.Modal.close();
}
}
}]);
return Alert;
}(React.PureComponent);
var Alert$2 = withEASDK()(Alert$1);
var name = "@shopify/polaris";
var version = "1.7.0";
var METADATA = {
interface: {
name: name,
version: version
}
};
var App$1 = function (_React$Component) {
_inherits(App, _React$Component);
function App() {
_classCallCheck(this, App);
var _this = _possibleConstructorReturn(this, (App.__proto__ || Object.getPrototypeOf(App)).apply(this, arguments));
_this.easdk = new EASDK$1({
apiKey: _this.props.apiKey,
shopOrigin: _this.props.shopOrigin,
forceRedirect: _this.props.forceRedirect,
debug: _this.props.debug
}, METADATA);
return _this;
}
_createClass(App, [{
key: 'getChildContext',
value: function getChildContext() {
return { easdk: this.easdk };
}
}, {
key: 'render',
value: function render() {
return React.Children.only(this.props.children);
}
}]);
return App;
}(React.Component);
App$1.childContextTypes = { easdk: PropTypes.instanceOf(EASDK$1) };
var Modal$3 = function (_React$PureComponent) {
_inherits(Modal, _React$PureComponent);
function Modal() {
_classCallCheck(this, Modal);
var _this = _possibleConstructorReturn(this, (Modal.__proto__ || Object.getPrototypeOf(Modal)).apply(this, arguments));
_this.focusReturnPoint = null;
return _this;
}
_createClass(Modal, [{
key: 'componentDidMount',
value: function componentDidMount() {
var open = this.props.open;
if (open) {
this.handleEASDKMessaging();
this.focusReturnPoint = document.activeElement;
}
}
}, {
key: 'componentDidUpdate',
value: function componentDidUpdate(_ref) {
var wasOpen = _ref.open;
var open = this.props.open;
if (wasOpen !== open) {
this.handleEASDKMessaging();
}
if (!wasOpen && open) {
this.focusReturnPoint = document.activeElement;
} else if (wasOpen && !open && this.focusReturnPoint != null && document.contains(this.focusReturnPoint)) {
this.focusReturnPoint.focus();
this.focusReturnPoint = null;
}
}
// tslint:disable-next-line prefer-function-over-method
}, {
key: 'render',
value: function render() {
return null;
}
}, {
key: 'handleEASDKMessaging',
value: function handleEASDKMessaging() {
var _props = this.props,
open = _props.open,
easdk = _props.easdk;
if (easdk == null) {
return;
}
if (open) {
easdk.Modal.open(this.props);
} else {
easdk.Modal.close();
}
}
}]);
return Modal;
}(React.PureComponent);
var Modal$4 = withEASDK()(Modal$3);
var ResourcePicker$2 = function (_React$PureComponent) {
_inherits(ResourcePicker, _React$PureComponent);
function ResourcePicker() {
_classCallCheck(this, ResourcePicker);
var _this = _possibleConstructorReturn(this, (ResourcePicker.__proto__ || Object.getPrototypeOf(ResourcePicker)).apply(this, arguments));
_this.focusReturnPoint = null;
return _this;
}
_createClass(ResourcePicker, [{
key: 'componentDidMount',
value: function componentDidMount() {
var open = this.props.open;
if (open) {
this.handleEASDKMessaging();
this.focusReturnPoint = document.activeElement;
}
}
}, {
key: 'componentDidUpdate',
value: function componentDidUpdate(_ref) {
var wasOpen = _ref.open;
var open = this.props.open;
if (wasOpen !== open) {
this.handleEASDKMessaging();
}
if (!wasOpen && open) {
this.focusReturnPoint = document.activeElement;
} else if (wasOpen && !open && this.focusReturnPoint != null && document.contains(this.focusReturnPoint)) {
this.focusReturnPoint.focus();
this.focusReturnPoint = null;
}
}
// tslint:disable-next-line prefer-function-over-method
}, {
key: 'render',
value: function render() {
return null;
}
}, {
key: 'handleEASDKMessaging',
value: function handleEASDKMessaging() {
var _props = this.props,
open = _props.open,
easdk = _props.easdk;
if (easdk == null) {
return;
}
if (open) {
easdk.ResourcePicker.open(this.props);
} else {
easdk.ResourcePicker.close();
}
}
}]);
return ResourcePicker;
}(React.PureComponent);
var Modal$6 = withEASDK()(ResourcePicker$2);
exports.Alert = Alert$2;
exports.EmbeddedApp = App$1;
exports.Modal = Modal$4;
exports.ResourcePicker = Modal$6;
exports.EASDK = EASDK$1;
exports.withEASDK = withEASDK;