├── .commitlintrc.json
├── .editorconfig
├── .eslintrc.json
├── .gitignore
├── .husky
├── commit-msg
└── pre-commit
├── .lintstagedrc.json
├── .prettierrc.json
├── LICENSE
├── README.md
├── jest-setup.ts
├── jest.config.ts
├── package.json
├── src
├── index.test.tsx
└── index.tsx
├── tsconfig.json
├── tsup.config.ts
└── yarn.lock
/.commitlintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["@commitlint/config-conventional"]
3 | }
4 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: https://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | [*]
7 | indent_style = space
8 | indent_size = 2
9 | end_of_line = lf
10 | charset = utf-8
11 | trim_trailing_whitespace = true
12 | insert_final_newline = true
13 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "env": {
4 | "browser": true,
5 | "es2021": true
6 | },
7 | "extends": [
8 | "plugin:react/recommended",
9 | "airbnb",
10 | "airbnb/hooks",
11 | "airbnb-typescript",
12 | "prettier"
13 | ],
14 | "parser": "@typescript-eslint/parser",
15 | "parserOptions": {
16 | "project": "./tsconfig.json",
17 | "ecmaFeatures": {
18 | "jsx": true
19 | },
20 | "ecmaVersion": "latest",
21 | "sourceType": "module"
22 | },
23 | "plugins": ["react", "@typescript-eslint", "prettier"],
24 | "rules": {
25 | "prettier/prettier": "error",
26 | "no-unused-vars": "off",
27 | "@typescript-eslint/no-unused-vars": "error",
28 | "import/no-extraneous-dependencies": ["error", { "devDependencies": true }],
29 | "react/require-default-props": "off",
30 | "react/no-unstable-nested-components": ["error", { "allowAsProps": true }],
31 | "react/jsx-no-useless-fragment": "off",
32 | "react/jsx-props-no-spreading": "off"
33 | },
34 | "overrides": [
35 | {
36 | "files": ["**/__tests__/**/*", "**/*.{spec,test}.*"],
37 | "env": {
38 | "jest/globals": true
39 | },
40 | "plugins": ["jest", "jest-dom", "testing-library"],
41 | "extends": [
42 | "plugin:jest/recommended",
43 | "plugin:jest-dom/recommended",
44 | "plugin:testing-library/react"
45 | ],
46 | "rules": {}
47 | }
48 | ]
49 | }
50 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 |
78 | # Next.js build output
79 | .next
80 |
81 | # Nuxt.js build / generate output
82 | .nuxt
83 | dist
84 |
85 | # Gatsby files
86 | .cache/
87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
88 | # https://nextjs.org/blog/next-9-1#public-directory-support
89 | # public
90 |
91 | # vuepress build output
92 | .vuepress/dist
93 |
94 | # Serverless directories
95 | .serverless/
96 |
97 | # FuseBox cache
98 | .fusebox/
99 |
100 | # DynamoDB Local files
101 | .dynamodb/
102 |
103 | # TernJS port file
104 | .tern-port
105 |
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | . "$(dirname -- "$0")/_/husky.sh"
3 |
4 | npx --no -- commitlint --edit
5 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | . "$(dirname -- "$0")/_/husky.sh"
3 |
4 | npx lint-staged
5 |
--------------------------------------------------------------------------------
/.lintstagedrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "*.{js,js,ts,tsx}": [
3 | "eslint --fix --max-warnings 0",
4 | "prettier --write",
5 | "cross-env CI=true npm run test --if-present -- --findRelatedTests --bail"
6 | ],
7 | "*.{html,json,md,mdx,yml,yaml}": ["prettier --write"]
8 | }
9 |
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 80,
3 | "tabWidth": 2,
4 | "useTabs": false,
5 | "semi": true,
6 | "singleQuote": true,
7 | "jsxSingleQuote": false,
8 | "quoteProps": "as-needed",
9 | "trailingComma": "all",
10 | "bracketSpacing": true,
11 | "bracketSameLine": false,
12 | "arrowParens": "avoid",
13 | "proseWrap": "preserve",
14 | "endOfLine": "lf"
15 | }
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Mo'men Sherif
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React HTML String 🚀
2 |
3 | A React declarative component for converting HTML strings into React components. Avoids the use of dangerouslySetInnerHTML and converts standard HTML elements, attributes and inline styles into their React equivalents or `Custom Components`.
4 |
5 | ## Install
6 |
7 | ```sh
8 | $ npm install react-html-string
9 |
10 | or
11 |
12 | $ yarn add react-html-string
13 | ```
14 |
15 | ## How to use
16 |
17 | ```jsx
18 | import HTMLString from 'react-html-string';
19 |
20 | const html = `
21 |
22 |
30 |
31 |
32 | - Render HTML string safely
33 | - Provide Custom Components if needed
34 |
35 |
Don't forget to ⭐️ the project
36 |
37 | `;
38 |
39 | export default function App() {
40 | return (
41 |
42 |
Hello, React!
43 |
44 |
45 | );
46 | }
47 | ```
48 |
49 | ### With Custom Components
50 |
51 | ```jsx
52 | import HTMLString from 'react-html-string';
53 |
54 | import Heading from './components/Heading';
55 |
56 | const components = {
57 | a: props => ,
58 | h1: Heading,
59 | };
60 |
61 | const html = `
62 |
63 |
71 |
72 |
73 | - Render HTML string safely
74 | - Provide Custom Components if needed
75 |
76 |
Don't forget to ⭐️ the project
77 |
78 | `;
79 |
80 | export default function App() {
81 | return (
82 |
83 |
Hello, React!
84 |
85 |
86 | );
87 | }
88 | ```
89 |
90 | ### TypeScript example
91 |
92 | `Each component is strongly typed with the equivalent dom node type.`
93 |
94 | ```tsx
95 | import HTMLString, { Components } from 'react-html-string';
96 |
97 | import Heading from './components/Heading';
98 |
99 | const components: Components = {
100 | a: props => ,
101 | h1: Heading,
102 | };
103 |
104 | const html = `
105 |
106 |
114 |
115 |
116 | - Render HTML string safely
117 | - Provide Custom Components if needed
118 |
119 |
Don't forget to ⭐️ the project
120 |
121 | `;
122 |
123 | export default function App() {
124 | return (
125 |
126 |
Hello, React!
127 |
128 |
129 | );
130 | }
131 | ```
132 |
--------------------------------------------------------------------------------
/jest-setup.ts:
--------------------------------------------------------------------------------
1 | import '@testing-library/jest-dom';
2 |
--------------------------------------------------------------------------------
/jest.config.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * For a detailed explanation regarding each configuration property and type check, visit:
3 | * https://jestjs.io/docs/configuration
4 | */
5 |
6 | export default {
7 | // All imported modules in your tests should be mocked automatically
8 | // automock: false,
9 |
10 | // Stop running tests after `n` failures
11 | // bail: 0,
12 |
13 | // The directory where Jest should store its cached dependency information
14 | // cacheDirectory: "/private/var/folders/h7/wgk7k_b1755f4sby25gy4k680000gn/T/jest_dx",
15 |
16 | // Automatically clear mock calls, instances, contexts and results before every test
17 | // clearMocks: false,
18 |
19 | // Indicates whether the coverage information should be collected while executing the test
20 | // collectCoverage: false,
21 |
22 | // An array of glob patterns indicating a set of files for which coverage information should be collected
23 | // collectCoverageFrom: undefined,
24 |
25 | // The directory where Jest should output its coverage files
26 | // coverageDirectory: undefined,
27 |
28 | // An array of regexp pattern strings used to skip coverage collection
29 | // coveragePathIgnorePatterns: [
30 | // "/node_modules/"
31 | // ],
32 |
33 | // Indicates which provider should be used to instrument code for coverage
34 | coverageProvider: 'v8',
35 |
36 | // A list of reporter names that Jest uses when writing coverage reports
37 | // coverageReporters: [
38 | // "json",
39 | // "text",
40 | // "lcov",
41 | // "clover"
42 | // ],
43 |
44 | // An object that configures minimum threshold enforcement for coverage results
45 | // coverageThreshold: undefined,
46 |
47 | // A path to a custom dependency extractor
48 | // dependencyExtractor: undefined,
49 |
50 | // Make calling deprecated APIs throw helpful error messages
51 | // errorOnDeprecated: false,
52 |
53 | // The default configuration for fake timers
54 | // fakeTimers: {
55 | // "enableGlobally": false
56 | // },
57 |
58 | // Force coverage collection from ignored files using an array of glob patterns
59 | // forceCoverageMatch: [],
60 |
61 | // A path to a module which exports an async function that is triggered once before all test suites
62 | // globalSetup: undefined,
63 |
64 | // A path to a module which exports an async function that is triggered once after all test suites
65 | // globalTeardown: undefined,
66 |
67 | // A set of global variables that need to be available in all test environments
68 | // globals: {},
69 |
70 | // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
71 | // maxWorkers: "50%",
72 |
73 | // An array of directory names to be searched recursively up from the requiring module's location
74 | // moduleDirectories: [
75 | // "node_modules"
76 | // ],
77 |
78 | // An array of file extensions your modules use
79 | // moduleFileExtensions: [
80 | // "js",
81 | // "mjs",
82 | // "cjs",
83 | // "jsx",
84 | // "ts",
85 | // "tsx",
86 | // "json",
87 | // "node"
88 | // ],
89 |
90 | // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
91 | // moduleNameMapper: {},
92 |
93 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
94 | // modulePathIgnorePatterns: [],
95 |
96 | // Activates notifications for test results
97 | // notify: false,
98 |
99 | // An enum that specifies notification mode. Requires { notify: true }
100 | // notifyMode: "failure-change",
101 |
102 | // A preset that is used as a base for Jest's configuration
103 | // preset: undefined,
104 |
105 | // Run tests from one or more projects
106 | // projects: undefined,
107 |
108 | // Use this configuration option to add custom reporters to Jest
109 | // reporters: undefined,
110 |
111 | // Automatically reset mock state before every test
112 | // resetMocks: false,
113 |
114 | // Reset the module registry before running each individual test
115 | // resetModules: false,
116 |
117 | // A path to a custom resolver
118 | // resolver: undefined,
119 |
120 | // Automatically restore mock state and implementation before every test
121 | // restoreMocks: false,
122 |
123 | // The root directory that Jest should scan for tests and modules within
124 | // rootDir: undefined,
125 |
126 | // A list of paths to directories that Jest should use to search for files in
127 | // roots: [
128 | // ""
129 | // ],
130 |
131 | // Allows you to use a custom runner instead of Jest's default test runner
132 | // runner: "jest-runner",
133 |
134 | // The paths to modules that run some code to configure or set up the testing environment before each test
135 | // setupFiles: [],
136 |
137 | // A list of paths to modules that run some code to configure or set up the testing framework before each test
138 | setupFilesAfterEnv: ['/jest-setup.ts'],
139 |
140 | // The number of seconds after which a test is considered as slow and reported as such in the results.
141 | // slowTestThreshold: 5,
142 |
143 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing
144 | // snapshotSerializers: [],
145 |
146 | // The test environment that will be used for testing
147 | testEnvironment: 'jsdom',
148 |
149 | // Options that will be passed to the testEnvironment
150 | // testEnvironmentOptions: {},
151 |
152 | // Adds a location field to test results
153 | // testLocationInResults: false,
154 |
155 | // The glob patterns Jest uses to detect test files
156 | // testMatch: [
157 | // "**/__tests__/**/*.[jt]s?(x)",
158 | // "**/?(*.)+(spec|test).[tj]s?(x)"
159 | // ],
160 |
161 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
162 | // testPathIgnorePatterns: [
163 | // "/node_modules/"
164 | // ],
165 |
166 | // The regexp pattern or array of patterns that Jest uses to detect test files
167 | // testRegex: [],
168 |
169 | // This option allows the use of a custom results processor
170 | // testResultsProcessor: undefined,
171 |
172 | // This option allows use of a custom test runner
173 | // testRunner: "jest-circus/runner",
174 |
175 | // A map from regular expressions to paths to transformers
176 | transform: {
177 | '^.+\\.tsx?$': 'esbuild-jest',
178 | },
179 |
180 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
181 | // transformIgnorePatterns: [
182 | // "/node_modules/",
183 | // "\\.pnp\\.[^\\/]+$"
184 | // ],
185 |
186 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
187 | // unmockedModulePathPatterns: undefined,
188 |
189 | // Indicates whether each individual test should be reported during the run
190 | // verbose: undefined,
191 |
192 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
193 | // watchPathIgnorePatterns: [],
194 |
195 | // Whether to use watchman for file crawling
196 | // watchman: true,
197 | };
198 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-html-string",
3 | "version": "0.1.1",
4 | "module": "./dist/index.esm.js",
5 | "main": "./dist/index.cjs.js",
6 | "types": "./dist/index.d.ts",
7 | "files": [
8 | "dist"
9 | ],
10 | "license": "MIT",
11 | "scripts": {
12 | "dev": "tsup --watch",
13 | "test": "jest",
14 | "test:watch": "jest --watch",
15 | "build": "tsup",
16 | "prerelease": "npm run build",
17 | "release": "np",
18 | "eslint:check": "eslint . --ext .js,.jsx,.ts,.tsx --ignore-path .gitignore --report-unused-disable-directives --max-warnings 0",
19 | "eslint:fix": "eslint . --fix --ext .js,.jsx,.ts,.tsx --ignore-path .gitignore --report-unused-disable-directives --max-warnings 0",
20 | "prettier:check": "prettier . --check --ignore-unknown --ignore-path .gitignore",
21 | "prettier:fix": "prettier . --write --ignore-unknown --ignore-path .gitignore",
22 | "commit": "cz",
23 | "prepare": "is-ci || husky install"
24 | },
25 | "publishConfig": {
26 | "access": "public"
27 | },
28 | "author": {
29 | "name": "Mo'men Sherif",
30 | "email": "momensherif.2019@gmail.com",
31 | "url": "https://github.com/MomenSherif"
32 | },
33 | "homepage": "https://github.com/MomenSherif/react-html-string",
34 | "repository": {
35 | "type": "git",
36 | "url": "https://github.com/MomenSherif/react-html-string"
37 | },
38 | "bugs": {
39 | "url": "https://github.com/MomenSherif/react-html-string/issues",
40 | "email": "momensherif.2019@gmail.com"
41 | },
42 | "keywords": [
43 | "react",
44 | "html",
45 | "htmlparser",
46 | "react html string",
47 | "inner html",
48 | "dangerouslySetInnerHTML"
49 | ],
50 | "devDependencies": {
51 | "@commitlint/cli": "^16.1.0",
52 | "@commitlint/config-conventional": "^16.0.0",
53 | "@testing-library/jest-dom": "^5.16.5",
54 | "@testing-library/react": "^13.4.0",
55 | "@types/jest": "^29.0.0",
56 | "@types/react": "^18.0.18",
57 | "@typescript-eslint/eslint-plugin": "^5.10.0",
58 | "@typescript-eslint/parser": "^5.10.0",
59 | "commitizen": "^4.2.4",
60 | "cross-env": "^7.0.3",
61 | "cz-conventional-changelog": "^3.3.0",
62 | "esbuild": "^0.15.7",
63 | "esbuild-jest": "^0.5.0",
64 | "eslint": "^8.7.0",
65 | "eslint-config-airbnb": "^19.0.4",
66 | "eslint-config-airbnb-typescript": "^16.1.0",
67 | "eslint-config-prettier": "^8.3.0",
68 | "eslint-plugin-import": "^2.25.4",
69 | "eslint-plugin-jest": "^26.0.0",
70 | "eslint-plugin-jest-dom": "^4.0.1",
71 | "eslint-plugin-jsx-a11y": "^6.5.1",
72 | "eslint-plugin-prettier": "^4.0.0",
73 | "eslint-plugin-react": "^7.28.0",
74 | "eslint-plugin-react-hooks": "^4.3.0",
75 | "eslint-plugin-testing-library": "^5.0.4",
76 | "husky": "^7.0.4",
77 | "is-ci": "^3.0.1",
78 | "jest": "^29.0.2",
79 | "jest-environment-jsdom": "^29.0.2",
80 | "lint-staged": "^12.3.1",
81 | "np": "^7.6.2",
82 | "prettier": "2.5.1",
83 | "react": "^18.2.0",
84 | "react-dom": "^18.2.0",
85 | "tsup": "^6.2.3",
86 | "typescript": "^4.8.2"
87 | },
88 | "dependencies": {
89 | "html-react-parser": "^3.0.4"
90 | },
91 | "peerDependencies": {
92 | "react": ">=16.8.0",
93 | "react-dom": ">=16.8.0"
94 | },
95 | "config": {
96 | "commitizen": {
97 | "path": "cz-conventional-changelog"
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/index.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render, screen } from '@testing-library/react';
3 | import HTMLString from '.';
4 |
5 | describe('', () => {
6 | const html = `
7 |
8 |
16 |
17 |
18 | - Render HTML string safely
19 | - Provide Custom Components if needed
20 |
21 |
Don't forget to ⭐️ the project
22 |
23 | `;
24 |
25 | it('renders react tree successfully from html string', () => {
26 | render();
27 |
28 | expect(
29 | screen.getByRole('heading', {
30 | level: 1,
31 | name: /hello from react html string/i,
32 | }),
33 | ).toBeInTheDocument();
34 | expect(
35 | screen.getByRole('link', { name: /react html string/i }),
36 | ).toBeInTheDocument();
37 |
38 | expect(screen.getByRole('separator')).toBeInTheDocument();
39 |
40 | expect(screen.getByRole('list')).toBeInTheDocument();
41 | expect(screen.getAllByRole('listitem')).toHaveLength(2);
42 | });
43 |
44 | it('renders custom react components', () => {
45 | render(
46 | Custom {children}
,
50 | a: () => HAHA this is fake link,
51 | }}
52 | />,
53 | );
54 |
55 | expect(
56 | screen.getByRole('heading', {
57 | level: 1,
58 | name: /Custom Hello from HAHA this is fake link/i,
59 | }),
60 | ).toBeInTheDocument();
61 | });
62 | });
63 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { useMemo } from 'react';
2 | import parse, { HTMLReactParserOptions, domToReact } from 'html-react-parser';
3 |
4 | export type Components = {
5 | [Property in keyof React.ReactHTML]?: React.ComponentType<
6 | React.ComponentProps
7 | >;
8 | };
9 |
10 | export type HTMLStringProps = {
11 | html: string;
12 | components?: Components;
13 | };
14 |
15 | export default function HTMLString({
16 | html = '',
17 | components = {},
18 | }: HTMLStringProps) {
19 | const parserOptions: HTMLReactParserOptions = useMemo(
20 | () => ({
21 | // @ts-ignore
22 | replace: ({ name, attribs, children: childNodes }) => {
23 | // @ts-ignore
24 | const Component = components[name];
25 |
26 | if (!Component) return null;
27 |
28 | const children = childNodes?.length
29 | ? domToReact(childNodes, parserOptions)
30 | : null;
31 |
32 | return React.createElement(Component, { name, ...attribs }, children);
33 | },
34 | }),
35 | [components],
36 | );
37 |
38 | const content = useMemo(
39 | () => parse(html, parserOptions),
40 | [html, parserOptions],
41 | );
42 |
43 | return <>{content}>;
44 | }
45 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/tsconfig",
3 | "display": "React HTML String",
4 | "compilerOptions": {
5 | "target": "ES2019",
6 | "module": "ESNext",
7 | "lib": ["dom", "dom.iterable", "esnext"],
8 | "declaration": true,
9 | "emitDeclarationOnly": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "moduleResolution": "node",
16 | "isolatedModules": true,
17 | "resolveJsonModule": true,
18 | "jsx": "react"
19 | },
20 | "exclude": ["node_modules"]
21 | }
22 |
--------------------------------------------------------------------------------
/tsup.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'tsup';
2 | import { dependencies, peerDependencies } from './package.json';
3 |
4 | export default defineConfig(options => ({
5 | entry: ['src/index.tsx'],
6 | outDir: 'dist',
7 | sourcemap: false,
8 | clean: true,
9 | dts: true,
10 | format: options.watch ? 'esm' : ['esm', 'cjs'],
11 | external: Object.keys(dependencies).concat(Object.keys(peerDependencies)),
12 | outExtension({ format }) {
13 | return {
14 | js: `.${format}.js`,
15 | };
16 | },
17 | minify: !options.watch,
18 | }));
19 |
--------------------------------------------------------------------------------