UNPKG

react-stripe-elements

Version:

React components for Stripe.js and Stripe Elements

188 lines (154 loc) 7.53 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.providerContextTypes = undefined; var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 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; } // TODO(jez) 'sync' and 'async' are bad tag names. // TODO(jez) What if redux also uses this.context.tag? var providerContextTypes = exports.providerContextTypes = { tag: _propTypes2.default.string.isRequired, stripe: _propTypes2.default.object, addStripeLoadListener: _propTypes2.default.func }; var getOrCreateStripe = function getOrCreateStripe(apiKey, options) { /** * Note that this is not meant to be a generic memoization solution. * This is specifically a solution for `StripeProvider`s being initialized * and destroyed regularly (with the same set of props) when users only * use `StripeProvider` for the subtree that contains their checkout form. */ window.Stripe.__cachedInstances = window.Stripe.__cachedInstances || {}; var cacheKey = 'key=' + apiKey + ' options=' + JSON.stringify(options); var stripe = window.Stripe.__cachedInstances[cacheKey] || window.Stripe(apiKey, options); window.Stripe.__cachedInstances[cacheKey] = stripe; return stripe; }; var ensureStripeShape = function ensureStripeShape(stripe) { if (stripe && stripe.elements && stripe.createSource && stripe.createToken && stripe.createPaymentMethod && stripe.handleCardPayment) { return stripe; } else { throw new Error("Please pass a valid Stripe object to StripeProvider. You can obtain a Stripe object by calling 'Stripe(...)' with your publishable key."); } }; var Provider = function (_React$Component) { _inherits(Provider, _React$Component); // on the other hand: childContextTypes is *required* to use context. function Provider(props) { _classCallCheck(this, Provider); var _this = _possibleConstructorReturn(this, _React$Component.call(this, props)); if (_this.props.apiKey && _this.props.stripe) { throw new Error("Please pass either 'apiKey' or 'stripe' to StripeProvider, not both."); } else if (_this.props.apiKey) { if (!window.Stripe) { throw new Error("Please load Stripe.js (https://js.stripe.com/v3/) on this page to use react-stripe-elements. If Stripe.js isn't available yet (it's loading asynchronously, or you're using server-side rendering), see https://github.com/stripe/react-stripe-elements#advanced-integrations"); } else { var _this$props = _this.props, _apiKey = _this$props.apiKey, _children = _this$props.children, options = _objectWithoutProperties(_this$props, ['apiKey', 'children']); var _stripe = getOrCreateStripe(_apiKey, options); _this._meta = { tag: 'sync', stripe: _stripe }; _this._register(); } } else if (_this.props.stripe) { // If we already have a stripe instance (in the constructor), we can behave synchronously. var _stripe2 = ensureStripeShape(_this.props.stripe); _this._meta = { tag: 'sync', stripe: _stripe2 }; _this._register(); } else if (_this.props.stripe === null) { _this._meta = { tag: 'async', stripe: null }; } else { throw new Error("Please pass either 'apiKey' or 'stripe' to StripeProvider. If you're using 'stripe' but don't have a Stripe instance yet, pass 'null' explicitly."); } _this._didWarn = false; _this._didWakeUpListeners = false; _this._listeners = []; return _this; } // Even though we're using flow, also use PropTypes so we can take advantage of developer warnings. Provider.prototype.getChildContext = function getChildContext() { var _this2 = this; // getChildContext is run after the constructor, so we WILL have access to // the initial state. // // However, context doesn't update in respnse to state changes like you // might expect: context is pulled by the child, not pushed by the parent. if (this._meta.tag === 'sync') { return { tag: 'sync', stripe: this._meta.stripe }; } else { return { tag: 'async', addStripeLoadListener: function addStripeLoadListener(fn) { if (_this2._meta.stripe) { fn(_this2._meta.stripe); } else { _this2._listeners.push(fn); } } }; } }; Provider.prototype.componentDidUpdate = function componentDidUpdate(prevProps) { var apiKeyChanged = this.props.apiKey && prevProps.apiKey && this.props.apiKey !== prevProps.apiKey; var stripeInstanceChanged = this.props.stripe && prevProps.stripe && this.props.stripe !== prevProps.stripe; if (!this._didWarn && (apiKeyChanged || stripeInstanceChanged) && window.console && window.console.error) { this._didWarn = true; // eslint-disable-next-line no-console console.error('StripeProvider does not support changing the apiKey parameter.'); return; } if (!this._didWakeUpListeners && this.props.stripe) { // Wake up the listeners if we've finally been given a StripeShape this._didWakeUpListeners = true; var _stripe3 = ensureStripeShape(this.props.stripe); this._meta.stripe = _stripe3; this._register(); this._listeners.forEach(function (fn) { fn(_stripe3); }); } }; Provider.prototype._register = function _register() { var stripe = this._meta.stripe; if (!stripe || !stripe._registerWrapper) { return; } stripe._registerWrapper({ name: 'react-stripe-elements', version: '6.1.2' || null }); }; Provider.prototype.render = function render() { return _react2.default.Children.only(this.props.children); }; return Provider; }(_react2.default.Component); Provider.propTypes = { apiKey: _propTypes2.default.string, // PropTypes.object is the only way we can accept a Stripe instance // eslint-disable-next-line react/forbid-prop-types stripe: _propTypes2.default.object, children: _propTypes2.default.node }; Provider.childContextTypes = providerContextTypes; Provider.defaultProps = { apiKey: undefined, stripe: undefined, children: null }; exports.default = Provider;