UNPKG

react-head

Version:

SSR-ready Document Head management for React 16+

236 lines (188 loc) 7.48 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var _extends = require('@babel/runtime/helpers/extends'); var React = require('react'); var _objectWithoutPropertiesLoose = require('@babel/runtime/helpers/objectWithoutPropertiesLoose'); var _inheritsLoose = require('@babel/runtime/helpers/inheritsLoose'); var ReactDOM = require('react-dom'); var _assertThisInitialized = require('@babel/runtime/helpers/assertThisInitialized'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var _extends__default = /*#__PURE__*/_interopDefaultLegacy(_extends); var _objectWithoutPropertiesLoose__default = /*#__PURE__*/_interopDefaultLegacy(_objectWithoutPropertiesLoose); var _inheritsLoose__default = /*#__PURE__*/_interopDefaultLegacy(_inheritsLoose); var _assertThisInitialized__default = /*#__PURE__*/_interopDefaultLegacy(_assertThisInitialized); var _React$createContext = /*#__PURE__*/React.createContext(null), Consumer = _React$createContext.Consumer, Provider = _React$createContext.Provider; var HeadTag = /*#__PURE__*/function (_React$Component) { _inheritsLoose__default['default'](HeadTag, _React$Component); function HeadTag() { var _this; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this; _this.state = { canUseDOM: false }; _this.headTags = null; _this.index = -1; return _this; } var _proto = HeadTag.prototype; _proto.componentDidMount = function componentDidMount() { var _this$props = this.props, tag = _this$props.tag, name = _this$props.name, property = _this$props.property; this.setState({ canUseDOM: true }); this.index = this.headTags.addClientTag(tag, name || property); }; _proto.componentWillUnmount = function componentWillUnmount() { var tag = this.props.tag; this.headTags.removeClientTag(tag, this.index); }; _proto.render = function render() { var _this2 = this; var _this$props2 = this.props, Tag = _this$props2.tag, rest = _objectWithoutPropertiesLoose__default['default'](_this$props2, ["tag"]); var canUseDOM = this.state.canUseDOM; return /*#__PURE__*/React.createElement(Consumer, null, function (headTags) { if (headTags == null) { throw Error('<HeadProvider /> should be in the tree'); } _this2.headTags = headTags; if (canUseDOM) { if (!headTags.shouldRenderTag(Tag, _this2.index)) { return null; } var ClientComp = /*#__PURE__*/React.createElement(Tag, rest); return /*#__PURE__*/ReactDOM.createPortal(ClientComp, document.head); } var ServerComp = /*#__PURE__*/React.createElement(Tag, _extends__default['default']({ "data-rh": "" }, rest)); headTags.addServerTag(ServerComp); return null; }); }; return HeadTag; }(React.Component); var cascadingTags = ['title', 'meta']; var HeadProvider = /*#__PURE__*/function (_React$Component) { _inheritsLoose__default['default'](HeadProvider, _React$Component); function HeadProvider() { var _this; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this; _this.indices = new Map(); _this.state = { addClientTag: function addClientTag(tag, name) { // consider only cascading tags if (cascadingTags.indexOf(tag) !== -1) { _this.setState(function (state) { var _ref; var names = state[tag] || []; return _ref = {}, _ref[tag] = [].concat(names, [name]), _ref; }); // track indices synchronously var _assertThisInitialize = _assertThisInitialized__default['default'](_this), indices = _assertThisInitialize.indices; var index = indices.has(tag) ? indices.get(tag) + 1 : 0; indices.set(tag, index); return index; } return -1; }, shouldRenderTag: function shouldRenderTag(tag, index) { if (cascadingTags.indexOf(tag) !== -1) { var names = _this.state[tag]; // eslint-disable-line react/destructuring-assignment // check if the tag is the last one of similar return names && names.lastIndexOf(names[index]) === index; } return true; }, removeClientTag: function removeClientTag(tag, index) { _this.setState(function (state) { var names = state[tag]; if (names) { var _ref2; names[index] = null; return _ref2 = {}, _ref2[tag] = names, _ref2; } return null; }); }, addServerTag: function addServerTag(tagNode) { var _this$props$headTags = _this.props.headTags, headTags = _this$props$headTags === void 0 ? [] : _this$props$headTags; // tweak only cascading tags if (cascadingTags.indexOf(tagNode.type) !== -1) { var index = headTags.findIndex(function (prev) { var prevName = prev.props.name || prev.props.property; var nextName = tagNode.props.name || tagNode.props.property; return prev.type === tagNode.type && prevName === nextName; }); if (index !== -1) { headTags.splice(index, 1); } } headTags.push(tagNode); } }; return _this; } var _proto = HeadProvider.prototype; _proto.componentDidMount = function componentDidMount() { var ssrTags = document.head.querySelectorAll("[data-rh=\"\"]"); // `forEach` on `NodeList` is not supported in Googlebot, so use a workaround Array.prototype.forEach.call(ssrTags, function (ssrTag) { return ssrTag.parentNode.removeChild(ssrTag); }); }; _proto.render = function render() { var _this$props = this.props, headTags = _this$props.headTags, children = _this$props.children; if (typeof window === 'undefined' && Array.isArray(headTags) === false) { throw Error('headTags array should be passed to <HeadProvider /> in node'); } return /*#__PURE__*/React.createElement(Provider, { value: this.state }, children); }; return HeadProvider; }(React.Component); var Title = function Title(props) { return /*#__PURE__*/React.createElement(HeadTag, _extends__default['default']({ tag: "title" }, props)); }; var Style = function Style(props) { return /*#__PURE__*/React.createElement(HeadTag, _extends__default['default']({ tag: "style" }, props)); }; var Meta = function Meta(props) { return /*#__PURE__*/React.createElement(HeadTag, _extends__default['default']({ tag: "meta" }, props)); }; var Link = function Link(props) { return /*#__PURE__*/React.createElement(HeadTag, _extends__default['default']({ tag: "link" }, props)); }; var Base = function Base(props) { return /*#__PURE__*/React.createElement(HeadTag, _extends__default['default']({ tag: "base" }, props)); }; exports.Base = Base; exports.HeadProvider = HeadProvider; exports.Link = Link; exports.Meta = Meta; exports.Style = Style; exports.Title = Title;