react-helmet-stuff
Version:
A document head manager for React
914 lines (754 loc) • 35.3 kB
JavaScript
import PropTypes from 'prop-types';
import withSideEffect from 'react-side-effect';
import isEqual from 'react-fast-compare';
import React from 'react';
import objectAssign from 'object-assign';
var ATTRIBUTE_NAMES = {
BODY: "bodyAttributes",
HTML: "htmlAttributes",
TITLE: "titleAttributes"
};
var TAG_NAMES = {
BASE: "base",
BODY: "body",
HEAD: "head",
HTML: "html",
LINK: "link",
META: "meta",
NOSCRIPT: "noscript",
SCRIPT: "script",
STYLE: "style",
TITLE: "title"
};
var VALID_TAG_NAMES = Object.values(TAG_NAMES);
var TAG_PROPERTIES = {
CHARSET: "charset",
CSS_TEXT: "cssText",
HREF: "href",
HTTPEQUIV: "http-equiv",
INNER_HTML: "innerHTML",
ITEM_PROP: "itemprop",
NAME: "name",
PROPERTY: "property",
REL: "rel",
SRC: "src",
TARGET: "target"
};
var REACT_TAG_MAP = {
accesskey: "accessKey",
charset: "charSet",
class: "className",
contenteditable: "contentEditable",
contextmenu: "contextMenu",
"http-equiv": "httpEquiv",
itemprop: "itemProp",
tabindex: "tabIndex"
};
var HELMET_PROPS = {
DEFAULT_TITLE: "defaultTitle",
DEFER: "defer",
ENCODE_SPECIAL_CHARACTERS: "encodeSpecialCharacters",
ON_CHANGE_CLIENT_STATE: "onChangeClientState",
TITLE_TEMPLATE: "titleTemplate"
};
var HTML_TAG_MAP = Object.keys(REACT_TAG_MAP).reduce(function (obj, key) {
obj[REACT_TAG_MAP[key]] = key;
return obj;
}, {});
var SELF_CLOSING_TAGS = [TAG_NAMES.NOSCRIPT, TAG_NAMES.SCRIPT, TAG_NAMES.STYLE];
var HELMET_ATTRIBUTE = "data-react-helmet";
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
return typeof obj;
} : function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
var classCallCheck = function (instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
};
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 _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 inherits = function (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 objectWithoutProperties = function (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;
};
var possibleConstructorReturn = function (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;
};
var encodeSpecialCharacters = function encodeSpecialCharacters(str) {
var encode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
if (encode === false) {
return String(str);
}
return String(str).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
};
var getTitleFromPropsList = function getTitleFromPropsList(propsList) {
var innermostTitle = getInnermostProperty(propsList, TAG_NAMES.TITLE);
var innermostTemplate = getInnermostProperty(propsList, HELMET_PROPS.TITLE_TEMPLATE);
if (innermostTemplate && innermostTitle) {
// use function arg to avoid need to escape $ characters
return innermostTemplate.replace(/%s/g, function () {
return Array.isArray(innermostTitle) ? innermostTitle.join("") : innermostTitle;
});
}
var innermostDefaultTitle = getInnermostProperty(propsList, HELMET_PROPS.DEFAULT_TITLE);
return innermostTitle || innermostDefaultTitle || undefined;
};
var getOnChangeClientState = function getOnChangeClientState(propsList) {
return getInnermostProperty(propsList, HELMET_PROPS.ON_CHANGE_CLIENT_STATE) || function () {};
};
var getAttributesFromPropsList = function getAttributesFromPropsList(tagType, propsList) {
return propsList.filter(function (props) {
return typeof props[tagType] !== "undefined";
}).map(function (props) {
return props[tagType];
}).reduce(function (tagAttrs, current) {
return _extends({}, tagAttrs, current);
}, {});
};
var getBaseTagFromPropsList = function getBaseTagFromPropsList(primaryAttributes, propsList) {
return propsList.filter(function (props) {
return typeof props[TAG_NAMES.BASE] !== "undefined";
}).map(function (props) {
return props[TAG_NAMES.BASE];
}).reverse().reduce(function (innermostBaseTag, tag) {
if (!innermostBaseTag.length) {
var keys = Object.keys(tag);
for (var i = 0; i < keys.length; i++) {
var attributeKey = keys[i];
var lowerCaseAttributeKey = attributeKey.toLowerCase();
if (primaryAttributes.indexOf(lowerCaseAttributeKey) !== -1 && tag[lowerCaseAttributeKey]) {
return innermostBaseTag.concat(tag);
}
}
}
return innermostBaseTag;
}, []);
};
var getTagsFromPropsList = function getTagsFromPropsList(tagName, primaryAttributes, propsList) {
// Calculate list of tags, giving priority innermost component (end of the propslist)
var approvedSeenTags = {};
return propsList.filter(function (props) {
if (Array.isArray(props[tagName])) {
return true;
}
if (typeof props[tagName] !== "undefined") {
warn("Helmet: " + tagName + " should be of type \"Array\". Instead found type \"" + _typeof(props[tagName]) + "\"");
}
return false;
}).map(function (props) {
return props[tagName];
}).reverse().reduce(function (approvedTags, instanceTags) {
var instanceSeenTags = {};
instanceTags.filter(function (tag) {
var primaryAttributeKey = void 0;
var keys = Object.keys(tag);
for (var i = 0; i < keys.length; i++) {
var attributeKey = keys[i];
var lowerCaseAttributeKey = attributeKey.toLowerCase();
// Special rule with link tags, since rel and href are both primary tags, rel takes priority
if (primaryAttributes.indexOf(lowerCaseAttributeKey) !== -1 && !(primaryAttributeKey === TAG_PROPERTIES.REL && tag[primaryAttributeKey].toLowerCase() === "canonical") && !(lowerCaseAttributeKey === TAG_PROPERTIES.REL && tag[lowerCaseAttributeKey].toLowerCase() === "stylesheet")) {
primaryAttributeKey = lowerCaseAttributeKey;
}
// Special case for innerHTML which doesn't work lowercased
if (primaryAttributes.indexOf(attributeKey) !== -1 && (attributeKey === TAG_PROPERTIES.INNER_HTML || attributeKey === TAG_PROPERTIES.CSS_TEXT || attributeKey === TAG_PROPERTIES.ITEM_PROP)) {
primaryAttributeKey = attributeKey;
}
}
if (!primaryAttributeKey || !tag[primaryAttributeKey]) {
return false;
}
var value = tag[primaryAttributeKey].toLowerCase();
if (!approvedSeenTags[primaryAttributeKey]) {
approvedSeenTags[primaryAttributeKey] = {};
}
if (!instanceSeenTags[primaryAttributeKey]) {
instanceSeenTags[primaryAttributeKey] = {};
}
if (!approvedSeenTags[primaryAttributeKey][value]) {
instanceSeenTags[primaryAttributeKey][value] = true;
return true;
}
return false;
}).reverse().forEach(function (tag) {
return approvedTags.push(tag);
});
// Update seen tags with tags from this instance
var keys = Object.keys(instanceSeenTags);
for (var i = 0; i < keys.length; i++) {
var attributeKey = keys[i];
var tagUnion = objectAssign({}, approvedSeenTags[attributeKey], instanceSeenTags[attributeKey]);
approvedSeenTags[attributeKey] = tagUnion;
}
return approvedTags;
}, []).reverse();
};
var getInnermostProperty = function getInnermostProperty(propsList, property) {
for (var i = propsList.length - 1; i >= 0; i--) {
var props = propsList[i];
if (props.hasOwnProperty(property)) {
return props[property];
}
}
return null;
};
var reducePropsToState = function reducePropsToState(propsList) {
return {
baseTag: getBaseTagFromPropsList([TAG_PROPERTIES.HREF, TAG_PROPERTIES.TARGET], propsList),
bodyAttributes: getAttributesFromPropsList(ATTRIBUTE_NAMES.BODY, propsList),
defer: getInnermostProperty(propsList, HELMET_PROPS.DEFER),
encode: getInnermostProperty(propsList, HELMET_PROPS.ENCODE_SPECIAL_CHARACTERS),
htmlAttributes: getAttributesFromPropsList(ATTRIBUTE_NAMES.HTML, propsList),
linkTags: getTagsFromPropsList(TAG_NAMES.LINK, [TAG_PROPERTIES.REL, TAG_PROPERTIES.HREF], propsList),
metaTags: getTagsFromPropsList(TAG_NAMES.META, [TAG_PROPERTIES.NAME, TAG_PROPERTIES.CHARSET, TAG_PROPERTIES.HTTPEQUIV, TAG_PROPERTIES.PROPERTY, TAG_PROPERTIES.ITEM_PROP], propsList),
noscriptTags: getTagsFromPropsList(TAG_NAMES.NOSCRIPT, [TAG_PROPERTIES.INNER_HTML], propsList),
onChangeClientState: getOnChangeClientState(propsList),
scriptTags: getTagsFromPropsList(TAG_NAMES.SCRIPT, [TAG_PROPERTIES.SRC, TAG_PROPERTIES.INNER_HTML], propsList),
styleTags: getTagsFromPropsList(TAG_NAMES.STYLE, [TAG_PROPERTIES.CSS_TEXT], propsList),
title: getTitleFromPropsList(propsList),
titleAttributes: getAttributesFromPropsList(ATTRIBUTE_NAMES.TITLE, propsList)
};
};
var rafPolyfill = function () {
var clock = Date.now();
return function (callback) {
var currentTime = Date.now();
if (currentTime - clock > 16) {
clock = currentTime;
callback(currentTime);
} else {
setTimeout(function () {
rafPolyfill(callback);
}, 0);
}
};
}();
var cafPolyfill = function cafPolyfill(id) {
return clearTimeout(id);
};
var requestAnimationFrame = typeof window !== "undefined" ? window.requestAnimationFrame && window.requestAnimationFrame.bind(window) || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || rafPolyfill : global.requestAnimationFrame || rafPolyfill;
var cancelAnimationFrame = typeof window !== "undefined" ? window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || cafPolyfill : global.cancelAnimationFrame || cafPolyfill;
var warn = function warn(msg) {
return console && typeof console.warn === "function" && console.warn(msg);
};
var _helmetCallback = null;
var handleClientStateChange = function handleClientStateChange(newState) {
if (_helmetCallback) {
cancelAnimationFrame(_helmetCallback);
}
if (newState.defer) {
_helmetCallback = requestAnimationFrame(function () {
commitTagChanges(newState, function () {
_helmetCallback = null;
});
});
} else {
commitTagChanges(newState);
_helmetCallback = null;
}
};
var commitTagChanges = function commitTagChanges(newState, cb) {
var baseTag = newState.baseTag,
bodyAttributes = newState.bodyAttributes,
htmlAttributes = newState.htmlAttributes,
linkTags = newState.linkTags,
metaTags = newState.metaTags,
noscriptTags = newState.noscriptTags,
onChangeClientState = newState.onChangeClientState,
scriptTags = newState.scriptTags,
styleTags = newState.styleTags,
title = newState.title,
titleAttributes = newState.titleAttributes;
updateAttributes(TAG_NAMES.BODY, bodyAttributes);
updateAttributes(TAG_NAMES.HTML, htmlAttributes);
updateTitle(title, titleAttributes);
var tagUpdates = {
baseTag: updateTags(TAG_NAMES.BASE, baseTag),
linkTags: updateTags(TAG_NAMES.LINK, linkTags),
metaTags: updateTags(TAG_NAMES.META, metaTags),
noscriptTags: updateTags(TAG_NAMES.NOSCRIPT, noscriptTags),
scriptTags: updateTags(TAG_NAMES.SCRIPT, scriptTags),
styleTags: updateTags(TAG_NAMES.STYLE, styleTags)
};
var addedTags = {};
var removedTags = {};
Object.keys(tagUpdates).forEach(function (tagType) {
var _tagUpdates$tagType = tagUpdates[tagType],
newTags = _tagUpdates$tagType.newTags,
oldTags = _tagUpdates$tagType.oldTags;
if (newTags.length) {
addedTags[tagType] = newTags;
}
if (oldTags.length) {
removedTags[tagType] = tagUpdates[tagType].oldTags;
}
});
cb && cb();
onChangeClientState(newState, addedTags, removedTags);
};
var flattenArray = function flattenArray(possibleArray) {
return Array.isArray(possibleArray) ? possibleArray.join("") : possibleArray;
};
var updateTitle = function updateTitle(title, attributes) {
if (typeof title !== "undefined" && document.title !== title) {
document.title = flattenArray(title);
}
updateAttributes(TAG_NAMES.TITLE, attributes);
};
var updateAttributes = function updateAttributes(tagName, attributes) {
var elementTag = document.getElementsByTagName(tagName)[0];
if (!elementTag) {
return;
}
var helmetAttributeString = elementTag.getAttribute(HELMET_ATTRIBUTE);
var helmetAttributes = helmetAttributeString ? helmetAttributeString.split(",") : [];
var attributesToRemove = [].concat(helmetAttributes);
var attributeKeys = Object.keys(attributes);
for (var i = 0; i < attributeKeys.length; i++) {
var attribute = attributeKeys[i];
var value = attributes[attribute] || "";
if (elementTag.getAttribute(attribute) !== value) {
elementTag.setAttribute(attribute, value);
}
if (helmetAttributes.indexOf(attribute) === -1) {
helmetAttributes.push(attribute);
}
var indexToSave = attributesToRemove.indexOf(attribute);
if (indexToSave !== -1) {
attributesToRemove.splice(indexToSave, 1);
}
}
for (var _i = attributesToRemove.length - 1; _i >= 0; _i--) {
elementTag.removeAttribute(attributesToRemove[_i]);
}
if (helmetAttributes.length === attributesToRemove.length) {
elementTag.removeAttribute(HELMET_ATTRIBUTE);
} else if (elementTag.getAttribute(HELMET_ATTRIBUTE) !== attributeKeys.join(",")) {
elementTag.setAttribute(HELMET_ATTRIBUTE, attributeKeys.join(","));
}
};
var updateTags = function updateTags(type, tags) {
var headElement = document.head || document.querySelector(TAG_NAMES.HEAD);
var tagNodes = headElement.querySelectorAll(type + "[" + HELMET_ATTRIBUTE + "]");
var oldTags = Array.prototype.slice.call(tagNodes);
var newTags = [];
var indexToDelete = void 0;
if (tags && tags.length) {
tags.forEach(function (tag) {
var newElement = document.createElement(type);
for (var attribute in tag) {
if (tag.hasOwnProperty(attribute)) {
if (attribute === TAG_PROPERTIES.INNER_HTML) {
newElement.innerHTML = tag.innerHTML;
} else if (attribute === TAG_PROPERTIES.CSS_TEXT) {
if (newElement.styleSheet) {
newElement.styleSheet.cssText = tag.cssText;
} else {
newElement.appendChild(document.createTextNode(tag.cssText));
}
} else {
var value = typeof tag[attribute] === "undefined" ? "" : tag[attribute];
newElement.setAttribute(attribute, value);
}
}
}
newElement.setAttribute(HELMET_ATTRIBUTE, "true");
// Remove a duplicate tag from domTagstoRemove, so it isn't cleared.
if (oldTags.some(function (existingTag, index) {
indexToDelete = index;
return newElement.isEqualNode(existingTag);
})) {
oldTags.splice(indexToDelete, 1);
} else {
newTags.push(newElement);
}
});
}
oldTags.forEach(function (tag) {
return tag.parentNode.removeChild(tag);
});
newTags.forEach(function (tag) {
return headElement.prepend(tag);
});
return {
oldTags: oldTags,
newTags: newTags
};
};
var generateElementAttributesAsString = function generateElementAttributesAsString(attributes) {
return Object.keys(attributes).reduce(function (str, key) {
var attr = typeof attributes[key] !== "undefined" ? key + "=\"" + attributes[key] + "\"" : "" + key;
return str ? str + " " + attr : attr;
}, "");
};
var generateTitleAsString = function generateTitleAsString(type, title, attributes, encode) {
var attributeString = generateElementAttributesAsString(attributes);
var flattenedTitle = flattenArray(title);
return attributeString ? "<" + type + " " + HELMET_ATTRIBUTE + "=\"true\" " + attributeString + ">" + encodeSpecialCharacters(flattenedTitle, encode) + "</" + type + ">" : "<" + type + " " + HELMET_ATTRIBUTE + "=\"true\">" + encodeSpecialCharacters(flattenedTitle, encode) + "</" + type + ">";
};
var generateTagsAsString = function generateTagsAsString(type, tags, encode) {
return tags.reduce(function (str, tag) {
var attributeHtml = Object.keys(tag).filter(function (attribute) {
return !(attribute === TAG_PROPERTIES.INNER_HTML || attribute === TAG_PROPERTIES.CSS_TEXT);
}).reduce(function (string, attribute) {
var attr = typeof tag[attribute] === "undefined" ? attribute : attribute + "=\"" + encodeSpecialCharacters(tag[attribute], encode) + "\"";
return string ? string + " " + attr : attr;
}, "");
var tagContent = tag.innerHTML || tag.cssText || "";
var isSelfClosing = SELF_CLOSING_TAGS.indexOf(type) === -1;
return str + "<" + type + " " + HELMET_ATTRIBUTE + "=\"true\" " + attributeHtml + (isSelfClosing ? "/>" : ">" + tagContent + "</" + type + ">");
}, "");
};
var convertElementAttributestoReactProps = function convertElementAttributestoReactProps(attributes) {
var initProps = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return Object.keys(attributes).reduce(function (obj, key) {
obj[REACT_TAG_MAP[key] || key] = attributes[key];
return obj;
}, initProps);
};
var convertReactPropstoHtmlAttributes = function convertReactPropstoHtmlAttributes(props) {
var initAttributes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return Object.keys(props).reduce(function (obj, key) {
obj[HTML_TAG_MAP[key] || key] = props[key];
return obj;
}, initAttributes);
};
var generateTitleAsReactComponent = function generateTitleAsReactComponent(type, title, attributes) {
var _initProps;
// assigning into an array to define toString function on it
var initProps = (_initProps = {
key: title
}, _initProps[HELMET_ATTRIBUTE] = true, _initProps);
var props = convertElementAttributestoReactProps(attributes, initProps);
return [React.createElement(TAG_NAMES.TITLE, props, title)];
};
var generateTagsAsReactComponent = function generateTagsAsReactComponent(type, tags) {
return tags.map(function (tag, i) {
var _mappedTag;
var mappedTag = (_mappedTag = {
key: i
}, _mappedTag[HELMET_ATTRIBUTE] = true, _mappedTag);
Object.keys(tag).forEach(function (attribute) {
var mappedAttribute = REACT_TAG_MAP[attribute] || attribute;
if (mappedAttribute === TAG_PROPERTIES.INNER_HTML || mappedAttribute === TAG_PROPERTIES.CSS_TEXT) {
var content = tag.innerHTML || tag.cssText;
mappedTag.dangerouslySetInnerHTML = { __html: content };
} else {
mappedTag[mappedAttribute] = tag[attribute];
}
});
return React.createElement(type, mappedTag);
});
};
var getMethodsForTag = function getMethodsForTag(type, tags, encode) {
switch (type) {
case TAG_NAMES.TITLE:
return {
toComponent: function toComponent() {
return generateTitleAsReactComponent(type, tags.title, tags.titleAttributes, encode);
},
toString: function toString() {
return generateTitleAsString(type, tags.title, tags.titleAttributes, encode);
}
};
case ATTRIBUTE_NAMES.BODY:
case ATTRIBUTE_NAMES.HTML:
return {
toComponent: function toComponent() {
return convertElementAttributestoReactProps(tags);
},
toString: function toString() {
return generateElementAttributesAsString(tags);
}
};
default:
return {
toComponent: function toComponent() {
return generateTagsAsReactComponent(type, tags);
},
toString: function toString() {
return generateTagsAsString(type, tags, encode);
}
};
}
};
var mapStateOnServer = function mapStateOnServer(_ref) {
var baseTag = _ref.baseTag,
bodyAttributes = _ref.bodyAttributes,
encode = _ref.encode,
htmlAttributes = _ref.htmlAttributes,
linkTags = _ref.linkTags,
metaTags = _ref.metaTags,
noscriptTags = _ref.noscriptTags,
scriptTags = _ref.scriptTags,
styleTags = _ref.styleTags,
_ref$title = _ref.title,
title = _ref$title === undefined ? "" : _ref$title,
titleAttributes = _ref.titleAttributes;
return {
base: getMethodsForTag(TAG_NAMES.BASE, baseTag, encode),
bodyAttributes: getMethodsForTag(ATTRIBUTE_NAMES.BODY, bodyAttributes, encode),
htmlAttributes: getMethodsForTag(ATTRIBUTE_NAMES.HTML, htmlAttributes, encode),
link: getMethodsForTag(TAG_NAMES.LINK, linkTags, encode),
meta: getMethodsForTag(TAG_NAMES.META, metaTags, encode),
noscript: getMethodsForTag(TAG_NAMES.NOSCRIPT, noscriptTags, encode),
script: getMethodsForTag(TAG_NAMES.SCRIPT, scriptTags, encode),
style: getMethodsForTag(TAG_NAMES.STYLE, styleTags, encode),
title: getMethodsForTag(TAG_NAMES.TITLE, { title: title, titleAttributes: titleAttributes }, encode)
};
};
var Helmet = function Helmet(Component) {
var _class, _temp;
return _temp = _class = function (_React$Component) {
inherits(HelmetWrapper, _React$Component);
function HelmetWrapper() {
classCallCheck(this, HelmetWrapper);
return possibleConstructorReturn(this, _React$Component.apply(this, arguments));
}
HelmetWrapper.prototype.shouldComponentUpdate = function shouldComponentUpdate(nextProps) {
return !isEqual(this.props, nextProps);
};
HelmetWrapper.prototype.mapNestedChildrenToProps = function mapNestedChildrenToProps(child, nestedChildren) {
if (!nestedChildren) {
return null;
}
switch (child.type) {
case TAG_NAMES.SCRIPT:
case TAG_NAMES.NOSCRIPT:
return {
innerHTML: nestedChildren
};
case TAG_NAMES.STYLE:
return {
cssText: nestedChildren
};
}
throw new Error("<" + child.type + " /> elements are self-closing and can not contain children. Refer to our API for more information.");
};
HelmetWrapper.prototype.flattenArrayTypeChildren = function flattenArrayTypeChildren(_ref) {
var _babelHelpers$extends;
var child = _ref.child,
arrayTypeChildren = _ref.arrayTypeChildren,
newChildProps = _ref.newChildProps,
nestedChildren = _ref.nestedChildren;
return _extends({}, arrayTypeChildren, (_babelHelpers$extends = {}, _babelHelpers$extends[child.type] = [].concat(arrayTypeChildren[child.type] || [], [_extends({}, newChildProps, this.mapNestedChildrenToProps(child, nestedChildren))]), _babelHelpers$extends));
};
HelmetWrapper.prototype.mapObjectTypeChildren = function mapObjectTypeChildren(_ref2) {
var _babelHelpers$extends2, _babelHelpers$extends3;
var child = _ref2.child,
newProps = _ref2.newProps,
newChildProps = _ref2.newChildProps,
nestedChildren = _ref2.nestedChildren;
switch (child.type) {
case TAG_NAMES.TITLE:
return _extends({}, newProps, (_babelHelpers$extends2 = {}, _babelHelpers$extends2[child.type] = nestedChildren, _babelHelpers$extends2.titleAttributes = _extends({}, newChildProps), _babelHelpers$extends2));
case TAG_NAMES.BODY:
return _extends({}, newProps, {
bodyAttributes: _extends({}, newChildProps)
});
case TAG_NAMES.HTML:
return _extends({}, newProps, {
htmlAttributes: _extends({}, newChildProps)
});
}
return _extends({}, newProps, (_babelHelpers$extends3 = {}, _babelHelpers$extends3[child.type] = _extends({}, newChildProps), _babelHelpers$extends3));
};
HelmetWrapper.prototype.mapArrayTypeChildrenToProps = function mapArrayTypeChildrenToProps(arrayTypeChildren, newProps) {
var newFlattenedProps = _extends({}, newProps);
Object.keys(arrayTypeChildren).forEach(function (arrayChildName) {
var _babelHelpers$extends4;
newFlattenedProps = _extends({}, newFlattenedProps, (_babelHelpers$extends4 = {}, _babelHelpers$extends4[arrayChildName] = arrayTypeChildren[arrayChildName], _babelHelpers$extends4));
});
return newFlattenedProps;
};
HelmetWrapper.prototype.warnOnInvalidChildren = function warnOnInvalidChildren(child, nestedChildren) {
if (process.env.NODE_ENV !== "production") {
if (!VALID_TAG_NAMES.some(function (name) {
return child.type === name;
})) {
if (typeof child.type === "function") {
return warn("You may be attempting to nest <Helmet> components within each other, which is not allowed. Refer to our API for more information.");
}
return warn("Only elements types " + VALID_TAG_NAMES.join(", ") + " are allowed. Helmet does not support rendering <" + child.type + "> elements. Refer to our API for more information.");
}
if (nestedChildren && typeof nestedChildren !== "string" && (!Array.isArray(nestedChildren) || nestedChildren.some(function (nestedChild) {
return typeof nestedChild !== "string";
}))) {
throw new Error("Helmet expects a string as a child of <" + child.type + ">. Did you forget to wrap your children in braces? ( <" + child.type + ">{``}</" + child.type + "> ) Refer to our API for more information.");
}
}
return true;
};
HelmetWrapper.prototype.mapChildrenToProps = function mapChildrenToProps(children, newProps) {
var _this2 = this;
var arrayTypeChildren = {};
React.Children.forEach(children, function (child) {
if (!child || !child.props) {
return;
}
var _child$props = child.props,
nestedChildren = _child$props.children,
childProps = objectWithoutProperties(_child$props, ["children"]);
var newChildProps = convertReactPropstoHtmlAttributes(childProps);
_this2.warnOnInvalidChildren(child, nestedChildren);
switch (child.type) {
case TAG_NAMES.LINK:
case TAG_NAMES.META:
case TAG_NAMES.NOSCRIPT:
case TAG_NAMES.SCRIPT:
case TAG_NAMES.STYLE:
arrayTypeChildren = _this2.flattenArrayTypeChildren({
child: child,
arrayTypeChildren: arrayTypeChildren,
newChildProps: newChildProps,
nestedChildren: nestedChildren
});
break;
default:
newProps = _this2.mapObjectTypeChildren({
child: child,
newProps: newProps,
newChildProps: newChildProps,
nestedChildren: nestedChildren
});
break;
}
});
newProps = this.mapArrayTypeChildrenToProps(arrayTypeChildren, newProps);
return newProps;
};
HelmetWrapper.prototype.render = function render() {
var _props = this.props,
children = _props.children,
props = objectWithoutProperties(_props, ["children"]);
var newProps = _extends({}, props);
if (children) {
newProps = this.mapChildrenToProps(children, newProps);
}
return React.createElement(Component, newProps);
};
createClass(HelmetWrapper, null, [{
key: "canUseDOM",
// Component.peek comes from react-side-effect:
// For testing, you may use a static peek() method available on the returned component.
// It lets you get the current state without resetting the mounted instance stack.
// Don’t use it for anything other than testing.
/**
* @param {Object} base: {"target": "_blank", "href": "http://mysite.com/"}
* @param {Object} bodyAttributes: {"className": "root"}
* @param {String} defaultTitle: "Default Title"
* @param {Boolean} defer: true
* @param {Boolean} encodeSpecialCharacters: true
* @param {Object} htmlAttributes: {"lang": "en", "amp": undefined}
* @param {Array} link: [{"rel": "canonical", "href": "http://mysite.com/example"}]
* @param {Array} meta: [{"name": "description", "content": "Test description"}]
* @param {Array} noscript: [{"innerHTML": "<img src='http://mysite.com/js/test.js'"}]
* @param {Function} onChangeClientState: "(newState) => console.log(newState)"
* @param {Array} script: [{"type": "text/javascript", "src": "http://mysite.com/js/test.js"}]
* @param {Array} style: [{"type": "text/css", "cssText": "div { display: block; color: blue; }"}]
* @param {String} title: "Title"
* @param {Object} titleAttributes: {"itemprop": "name"}
* @param {String} titleTemplate: "MySite.com - %s"
*/
set: function set$$1(canUseDOM) {
Component.canUseDOM = canUseDOM;
}
}]);
return HelmetWrapper;
}(React.Component), _class.propTypes = {
base: PropTypes.object,
bodyAttributes: PropTypes.object,
children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
defaultTitle: PropTypes.string,
defer: PropTypes.bool,
encodeSpecialCharacters: PropTypes.bool,
htmlAttributes: PropTypes.object,
link: PropTypes.arrayOf(PropTypes.object),
meta: PropTypes.arrayOf(PropTypes.object),
noscript: PropTypes.arrayOf(PropTypes.object),
onChangeClientState: PropTypes.func,
script: PropTypes.arrayOf(PropTypes.object),
style: PropTypes.arrayOf(PropTypes.object),
title: PropTypes.string,
titleAttributes: PropTypes.object,
titleTemplate: PropTypes.string
}, _class.defaultProps = {
defer: true,
encodeSpecialCharacters: true
}, _class.peek = Component.peek, _class.rewind = function () {
var mappedState = Component.rewind();
if (!mappedState) {
// provide fallback if mappedState is undefined
mappedState = mapStateOnServer({
baseTag: [],
bodyAttributes: {},
encodeSpecialCharacters: true,
htmlAttributes: {},
linkTags: [],
metaTags: [],
noscriptTags: [],
scriptTags: [],
styleTags: [],
title: "",
titleAttributes: {}
});
}
return mappedState;
}, _temp;
};
var NullComponent = function NullComponent() {
return null;
};
var HelmetSideEffects = withSideEffect(reducePropsToState, handleClientStateChange, mapStateOnServer)(NullComponent);
var HelmetExport = Helmet(HelmetSideEffects);
HelmetExport.renderStatic = HelmetExport.rewind;
export default HelmetExport;
export { HelmetExport as Helmet };