Skip to content

Commit

Permalink
Fix(web-react): Icon component supports SSR
Browse files Browse the repository at this point in the history
  * `dangerouslySetInnerHtml` do not work while rendering on server
  * this `Warning: Prop `dangerouslySetInnerHTML` did not match.` error
    was raised
  * we can avoid this by wrapping the component with something like
    `<NoSsr>`
  * @see: https://stackoverflow.com/questions/64079321/react-tooltip-and-next-js-ssr-issue
  * or by using some library like ReactHtmlParser to render HTML string
    magically as a component
  * @see: https://www.npmjs.com/package/react-html-parser
  • Loading branch information
literat committed Nov 8, 2023
1 parent 495c4d5 commit 79f9f6f
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 14 deletions.
2 changes: 2 additions & 0 deletions packages/web-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"eslint-plugin-react": "7.33.2",
"eslint-plugin-react-hooks": "4.6.0",
"eslint-plugin-standard": "5.0.0",
"html-react-parser": "^5.0.6",
"jest": "29.7.0",
"jest-cli": "29.7.0",
"jest-environment-jsdom": "29.7.0",
Expand All @@ -79,6 +80,7 @@
"peerDependencies": {
"@lmc-eu/spirit-icons": "*",
"@lmc-eu/spirit-web": "*",
"html-react-parser": "^5.0.6",
"react": "^17.0.2 || ^18.0.0",
"react-dom": "^17.0.2 || ^18.0.0"
},
Expand Down
17 changes: 14 additions & 3 deletions packages/web-react/src/components/Icon/Icon.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { useIcon, useStyleProps } from '../../hooks';
import { IconProps } from '../../types';
import { htmlParser } from '../../utils/htmlParser';

const defaultProps = {
ariaHidden: true,
Expand All @@ -16,6 +17,14 @@ export const Icon = (props: IconProps): JSX.Element => {
icon = `<title>${title}</title>${icon}`;
}

// @deprecated Usage of `html-react-parser` will be required in the next major version.
if (typeof window === 'undefined' && htmlParser == null) {
// eslint-disable-next-line no-console
console.warn(
'Icon component is not supported in SSR without use of `html-react-parser`. Please install, missing peer dependency.',
);
}

return (
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Incompatible HTMLElement and SVGSVGElement
Expand All @@ -24,13 +33,15 @@ export const Icon = (props: IconProps): JSX.Element => {
fill="none"
width={boxSize}
height={boxSize}
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: icon }}
aria-hidden={ariaHidden}
// @deprecated Usage of dangerouslySetInnerHTML is discouraged due to support of SSR and will be removed in the next major version.
{...(typeof window !== 'undefined' ? { dangerouslySetInnerHTML: { __html: icon } } : {})}
{...otherProps}
{...styleProps}
className={styleProps.className}
/>
>
{typeof window === 'undefined' && htmlParser != null ? htmlParser(icon) : null}
</svg>
);
};

Expand Down
28 changes: 26 additions & 2 deletions packages/web-react/src/components/Icon/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,30 @@
# Icon

Icons are graphical metaphors or symbols that can be used to compliment existing experiences.
Icons are graphical metaphors or symbols that can be used to complement existing experiences.

## 🚀 Getting started

To use this component in your project you need to run the following command using [npm](https://www.npmjs.com/):

```bash
npm install -S @lcm-eu/spirit-icons html-react-parser
```

If you prefer [Yarn](https://yarnpkg.com/), use the following command instead:

```bash
yarn add @lcm-eu/spirit-icons html-react-parser
```

### 📦 Dependencies

Both packages are required as **peer dependency** to keep package size as low as possible.
So they will not be automatically installed with `@lmc-eu/spirit-web-react`.

- [`@lmc-eu/spirit-icons`](https://github.com/lmc-eu/spirit-design-system/tree/main/packages/icons) - Spirit Icons package
- [`html-react-parser`](https://www.npmjs.com/package/html-react-parser) - HTML to React parser (avoid usage of `dangerouslySetInnerHTML` on the server side)

## 📝 Usage

```jsx
import { Icon, IconsProvider } from '@lmc-eu/spirit-web-react/components';
Expand All @@ -14,7 +38,7 @@ import icons from '@lmc-eu/spirit-icons/icons';
</IconsProvider>
```

## API
## 🧩 API

| Name | Type | Default | Required | Description |
| ------------------ | --------------- | ------- | -------- | ------------------------- |
Expand Down
3 changes: 3 additions & 0 deletions packages/web-react/src/utils/htmlParser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import parse from 'html-react-parser';

export const htmlParser = typeof window === 'undefined' ? parse : null;
70 changes: 61 additions & 9 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11126,20 +11126,20 @@ domexception@^4.0.0:
dependencies:
webidl-conversions "^7.0.0"

[email protected], domhandler@^5.0.2, domhandler@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31"
integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==
dependencies:
domelementtype "^2.3.0"

domhandler@^2.3.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803"
integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==
dependencies:
domelementtype "1"

domhandler@^5.0.2, domhandler@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31"
integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==
dependencies:
domelementtype "^2.3.0"

[email protected]:
version "1.5.1"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf"
Expand All @@ -11156,7 +11156,7 @@ domutils@^1.5.1, domutils@^1.7.0:
dom-serializer "0"
domelementtype "1"

domutils@^3.0.1:
domutils@^3.0.1, domutils@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e"
integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==
Expand Down Expand Up @@ -11400,7 +11400,7 @@ entities@^2.0.0, entities@^2.2.0:
resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==

entities@^4.2.0:
entities@^4.2.0, entities@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
Expand Down Expand Up @@ -14355,6 +14355,14 @@ [email protected]:
optionalDependencies:
unix-dgram "2.x"

[email protected]:
version "5.0.4"
resolved "https://registry.yarnpkg.com/html-dom-parser/-/html-dom-parser-5.0.4.tgz#2941a762317d088e747db31c8cf290987ec30a55"
integrity sha512-azy8THLKd4Ar0OVJpEgX+MSjYvKdNDWlGiRBIlovMqEQYMAnLLXBhhiSwjylDD3RDdcCYT8Utg6uoRDeLHUyHg==
dependencies:
domhandler "5.0.3"
htmlparser2 "9.0.0"

html-encoding-sniffer@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz#2cb1a8cf0db52414776e5b2a7a04d5dd98158de9"
Expand All @@ -14367,6 +14375,16 @@ html-escaper@^2.0.0:
resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==

html-react-parser@^5.0.6:
version "5.0.6"
resolved "https://registry.yarnpkg.com/html-react-parser/-/html-react-parser-5.0.6.tgz#ee9e8ae404aa38cfbaf3825cb26fabced46024a1"
integrity sha512-aPSzFhO2bK/L/mYQbMwFz+1QG8nhxozbwENt/52HTApasrBvDX87MFD5uSQIjq7Io0bnKzH4uh7PM42zZ4ag9A==
dependencies:
domhandler "5.0.3"
html-dom-parser "5.0.4"
react-property "2.0.2"
style-to-js "1.1.9"

html-tags@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140"
Expand All @@ -14377,6 +14395,16 @@ html-tags@^3.3.1:
resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.3.1.tgz#a04026a18c882e4bba8a01a3d39cfe465d40b5ce"
integrity sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==

[email protected]:
version "9.0.0"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-9.0.0.tgz#e431142b7eeb1d91672742dea48af8ac7140cddb"
integrity sha512-uxbSI98wmFT/G4P2zXx4OVx04qWUmyFPrD2/CNepa2Zo3GPNaCaaxElDgwUrwYWkK1nr9fft0Ya8dws8coDLLQ==
dependencies:
domelementtype "^2.3.0"
domhandler "^5.0.3"
domutils "^3.1.0"
entities "^4.5.0"

htmlparser2@^3.9.1:
version "3.10.1"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f"
Expand Down Expand Up @@ -14672,6 +14700,11 @@ [email protected], init-package-json@^3.0.2:
validate-npm-package-license "^3.0.4"
validate-npm-package-name "^4.0.0"

[email protected]:
version "0.2.2"
resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.2.2.tgz#d498b4e6de0373458fc610ff793f6b14ebf45633"
integrity sha512-EcKzdTHVe8wFVOGEYXiW9WmJXPjqi1T+234YpJr98RiFYKHV3cdy1+3mkTE+KHTHxFFLH51SfaGOoUdW+v7ViQ==

inquirer-autocomplete-prompt@^1.0.1:
version "1.4.0"
resolved "https://registry.yarnpkg.com/inquirer-autocomplete-prompt/-/inquirer-autocomplete-prompt-1.4.0.tgz#e767592f747e3d5bb6336fe71fb4094352e4c317"
Expand Down Expand Up @@ -20578,6 +20611,11 @@ react-is@^18.0.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.0.0.tgz#026f6c4a27dbe33bf4a35655b9e1327c4e55e3f5"
integrity sha512-yUcBYdBBbo3QiPsgYDcfQcIkGZHfxOaoE6HLSnr1sPzMhdyxusbfKOSUbSd/ocGi32dxcj366PsTj+5oggeKKw==

[email protected]:
version "2.0.2"
resolved "https://registry.yarnpkg.com/react-property/-/react-property-2.0.2.tgz#d5ac9e244cef564880a610bc8d868bd6f60fdda6"
integrity sha512-+PbtI3VuDV0l6CleQMsx2gtK0JZbZKbpdu5ynr+lbsuvtmgbNcS3VM0tuY2QjFNOcWxvXeHjDpy42RO+4U2rug==

react-refresh@^0.14.0:
version "0.14.0"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
Expand Down Expand Up @@ -22599,6 +22637,20 @@ style-search@^0.1.0:
resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902"
integrity sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI=

[email protected]:
version "1.1.9"
resolved "https://registry.yarnpkg.com/style-to-js/-/style-to-js-1.1.9.tgz#5bdc23ba7624016094a19d6ea90fa3f98bee34c4"
integrity sha512-6bkwhOlPOx+wKiHVlPTHjUqM4zDKv9pyccehB8zetZL0hhQ7MVp7UEWUsohjiMdxwhSsEdjMrEve+8qzUVmY4w==
dependencies:
style-to-object "1.0.4"

[email protected]:
version "1.0.4"
resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-1.0.4.tgz#496fded508ce520eca13e738e8af33b8b5af98f2"
integrity sha512-KyNO6mfijxSnypdvEjeXlhvbGPSh0l1zBJp80n+ncBQvrEbSwBHwZCpo0xz6Q4AKSPfXowWwypCBAUAdfz3rFQ==
dependencies:
inline-style-parser "0.2.2"

[email protected]:
version "9.0.5"
resolved "https://registry.yarnpkg.com/stylelint-config-prettier/-/stylelint-config-prettier-9.0.5.tgz#9f78bbf31c7307ca2df2dd60f42c7014ee9da56e"
Expand Down

0 comments on commit 79f9f6f

Please sign in to comment.