Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release/5.3.0 #497

Closed
wants to merge 12 commits into from
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 10 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
{
"name": "react-helmet",
"description": "A document head manager for React",
"version": "5.2.1",
"main": "./lib/Helmet.js",
"name": "react-helmet-with-visor",
"description": "Fork of the react-helmet with ability to inject custom seo string",
"version": "5.3.2",
"main": "./lib/HelmetLib.js",
"author": "NFL <engineers@nfl.com>",
"contributors": [
"Chris Welch <chris.welch@nfl.com>"
"Chris Welch <chris.welch@nfl.com>",
"Nikolai Kulikov <nikolai.kulikov.dev@gmail.com>"
],
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/nfl/react-helmet"
"url": "https://github.com/kokushkin/react-helmet-with-visor"
},
"keywords": [
"react-helmet",
"react-helmet-with-visor",
"injection",
"seo",
"nfl",
"react",
"document",
Expand Down
44 changes: 23 additions & 21 deletions src/Helmet.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import {
handleClientStateChange,
mapStateOnServer,
reducePropsToState,
warn
warn,
nestedComponentWarning,
onlyElementsWarning,
getTypeName
} from "./HelmetUtils.js";
import {TAG_NAMES, VALID_TAG_NAMES} from "./HelmetConstants.js";

Expand Down Expand Up @@ -78,7 +81,8 @@ const Helmet = Component =>
scriptTags: [],
styleTags: [],
title: "",
titleAttributes: {}
titleAttributes: {},
openedVisorTags: []
});
}

Expand All @@ -98,9 +102,10 @@ const Helmet = Component =>
return null;
}

switch (child.type) {
switch (getTypeName(child)) {
case TAG_NAMES.SCRIPT:
case TAG_NAMES.NOSCRIPT:
case TAG_NAMES.HELMETS_OPENED_VISOR:
return {
innerHTML: nestedChildren
};
Expand All @@ -112,7 +117,7 @@ const Helmet = Component =>
}

throw new Error(
`<${child.type} /> elements are self-closing and can not contain children. Refer to our API for more information.`
`<${getTypeName(child)} /> elements are self-closing and can not contain children. Refer to our API for more information.`
);
}

Expand All @@ -124,8 +129,8 @@ const Helmet = Component =>
}) {
return {
...arrayTypeChildren,
[child.type]: [
...(arrayTypeChildren[child.type] || []),
[getTypeName(child)]: [
...(arrayTypeChildren[getTypeName(child)] || []),
{
...newChildProps,
...this.mapNestedChildrenToProps(child, nestedChildren)
Expand All @@ -140,11 +145,11 @@ const Helmet = Component =>
newChildProps,
nestedChildren
}) {
switch (child.type) {
switch (getTypeName(child)) {
case TAG_NAMES.TITLE:
return {
...newProps,
[child.type]: nestedChildren,
[getTypeName(child)]: nestedChildren,
titleAttributes: {...newChildProps}
};

Expand All @@ -163,7 +168,7 @@ const Helmet = Component =>

return {
...newProps,
[child.type]: {...newChildProps}
[getTypeName(child)]: {...newChildProps}
};
}

Expand All @@ -182,18 +187,14 @@ const Helmet = Component =>

warnOnInvalidChildren(child, nestedChildren) {
if (process.env.NODE_ENV !== "production") {
if (!VALID_TAG_NAMES.some(name => 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.`
);
if (!VALID_TAG_NAMES.some(name => getTypeName(child) === name)) {
if (
typeof child.type === "function"
) {
return warn(nestedComponentWarning(getTypeName(child)));
}

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.`
);
return warn(onlyElementsWarning(getTypeName(child)));
}

if (
Expand All @@ -205,7 +206,7 @@ const Helmet = Component =>
))
) {
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.`
`Helmet expects a string as a child of <${getTypeName(child)}>. Did you forget to wrap your children in braces? ( <${getTypeName(child)}>{\`\`}</${getTypeName(child)}> ) Refer to our API for more information.`
);
}
}
Expand All @@ -228,11 +229,12 @@ const Helmet = Component =>

this.warnOnInvalidChildren(child, nestedChildren);

switch (child.type) {
switch (getTypeName(child)) {
case TAG_NAMES.LINK:
case TAG_NAMES.META:
case TAG_NAMES.NOSCRIPT:
case TAG_NAMES.SCRIPT:
case TAG_NAMES.HELMETS_OPENED_VISOR:
case TAG_NAMES.STYLE:
arrayTypeChildren = this.flattenArrayTypeChildren({
child,
Expand Down
6 changes: 4 additions & 2 deletions src/HelmetConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ export const TAG_NAMES = {
NOSCRIPT: "noscript",
SCRIPT: "script",
STYLE: "style",
TITLE: "title"
TITLE: "title",
HELMETS_OPENED_VISOR: "HelmetsOpenedVisor"
};

export const VALID_TAG_NAMES = Object.keys(TAG_NAMES).map(
Expand All @@ -31,7 +32,8 @@ export const TAG_PROPERTIES = {
NAME: "name",
PROPERTY: "property",
REL: "rel",
SRC: "src"
SRC: "src",
OPENED_VISOR: "openedVisor"
};

export const REACT_TAG_MAP = {
Expand Down
5 changes: 5 additions & 0 deletions src/HelmetLib.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {Helmet} from "./Helmet.js";
import {HelmetsOpenedVisor} from "./HelmetsOpenedVisor.js";

export {Helmet, HelmetsOpenedVisor};
export default Helmet;
129 changes: 92 additions & 37 deletions src/HelmetUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
REACT_TAG_MAP,
SELF_CLOSING_TAGS,
TAG_NAMES,
TAG_PROPERTIES
TAG_PROPERTIES,
VALID_TAG_NAMES
} from "./HelmetConstants.js";

const encodeSpecialCharacters = (str, encode = true) => {
Expand Down Expand Up @@ -236,6 +237,11 @@ const reducePropsToState = propsList => ({
[TAG_PROPERTIES.SRC, TAG_PROPERTIES.INNER_HTML],
propsList
),
openedVisorTags: getTagsFromPropsList(
TAG_NAMES.HELMETS_OPENED_VISOR,
[TAG_PROPERTIES.INNER_HTML],
propsList
),
styleTags: getTagsFromPropsList(
TAG_NAMES.STYLE,
[TAG_PROPERTIES.CSS_TEXT],
Expand Down Expand Up @@ -316,7 +322,8 @@ const commitTagChanges = (newState, cb) => {
scriptTags,
styleTags,
title,
titleAttributes
titleAttributes,
openedVisorTags
} = newState;
updateAttributes(TAG_NAMES.BODY, bodyAttributes);
updateAttributes(TAG_NAMES.HTML, htmlAttributes);
Expand All @@ -329,7 +336,11 @@ const commitTagChanges = (newState, cb) => {
metaTags: updateTags(TAG_NAMES.META, metaTags),
noscriptTags: updateTags(TAG_NAMES.NOSCRIPT, noscriptTags),
scriptTags: updateTags(TAG_NAMES.SCRIPT, scriptTags),
styleTags: updateTags(TAG_NAMES.STYLE, styleTags)
styleTags: updateTags(TAG_NAMES.STYLE, styleTags),
openedVisorTags: updateTags(
TAG_NAMES.HELMETS_OPENED_VISOR,
openedVisorTags
),
};

const addedTags = {};
Expand Down Expand Up @@ -421,42 +432,31 @@ const updateTags = (type, tags) => {

if (tags && tags.length) {
tags.forEach(tag => {
const newElement = document.createElement(type);

for (const 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 {
const value = typeof tag[attribute] === "undefined"
? ""
: tag[attribute];
newElement.setAttribute(attribute, value);
}
}
}

newElement.setAttribute(HELMET_ATTRIBUTE, "true");
let elements = [];

// Remove a duplicate tag from domTagstoRemove, so it isn't cleared.
if (
oldTags.some((existingTag, index) => {
indexToDelete = index;
return newElement.isEqualNode(existingTag);
})
) {
oldTags.splice(indexToDelete, 1);
if (type !== TAG_NAMES.HELMETS_OPENED_VISOR) {
elements.push(createRegularElement(type, tag));
} else {
newTags.push(newElement);
const visorElements = createElementsFromVisor(tag);
elements = Array.prototype.slice.call(visorElements);
}

elements.forEach(newElement => {
newElement.setAttribute(HELMET_ATTRIBUTE, "true");

// Remove a duplicate tag from domTagstoRemove, so it isn't cleared.
if (
oldTags.some((existingTag, index) => {
indexToDelete = index;
return newElement.isEqualNode(existingTag);
})
) {
oldTags.splice(indexToDelete, 1);
} else {
newTags.push(newElement);
}
});

});
}

Expand All @@ -469,6 +469,39 @@ const updateTags = (type, tags) => {
};
};

const createRegularElement = (type, tag) => {
const newElement = document.createElement(type);

for (const 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 {
const value = typeof tag[attribute] === "undefined"
? ""
: tag[attribute];
newElement.setAttribute(attribute, value);
}
}
}

return newElement;
};

const createElementsFromVisor = tag => {
const newElement = document.createElement("div");
newElement.innerHTML = tag.innerHTML;
return newElement.children;
};

const generateElementAttributesAsString = attributes =>
Object.keys(attributes).reduce((str, key) => {
const attr = typeof attributes[key] !== "undefined"
Expand Down Expand Up @@ -613,7 +646,8 @@ const mapStateOnServer = ({
scriptTags,
styleTags,
title = "",
titleAttributes
titleAttributes,
openedVisorTags
}) => ({
base: getMethodsForTag(TAG_NAMES.BASE, baseTag, encode),
bodyAttributes: getMethodsForTag(
Expand All @@ -630,13 +664,34 @@ const mapStateOnServer = ({
meta: getMethodsForTag(TAG_NAMES.META, metaTags, encode),
noscript: getMethodsForTag(TAG_NAMES.NOSCRIPT, noscriptTags, encode),
script: getMethodsForTag(TAG_NAMES.SCRIPT, scriptTags, encode),
openedVisor: getMethodsForTag(
TAG_NAMES.HELMETS_OPENED_VISOR,
openedVisorTags,
encode
),
style: getMethodsForTag(TAG_NAMES.STYLE, styleTags, encode),
title: getMethodsForTag(TAG_NAMES.TITLE, {title, titleAttributes}, encode)
});

const getTypeName = child => {
return child && (child.type.name || child.type);
};

const nestedComponentWarning = type =>
`You may be attempting to nest <Helmet> components within each other,
which is not allowed. Refer to our API for more information. Component type: <${type}>`;

const onlyElementsWarning = type =>
`Only elements types ${VALID_TAG_NAMES.join(
", "
)} are allowed. Helmet does not support rendering <${type}> elements. Refer to our API for more information.`;

export {convertReactPropstoHtmlAttributes};
export {handleClientStateChange};
export {mapStateOnServer};
export {reducePropsToState};
export {requestAnimationFrame};
export {warn};
export {getTypeName};
export {nestedComponentWarning};
export {onlyElementsWarning}
1 change: 1 addition & 0 deletions src/HelmetsOpenedVisor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const HelmetsOpenedVisor = () => null;
Loading