@sohanemon/utils 5.0.5 → 5.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Props for the HtmlInjector component
|
|
4
|
+
*/
|
|
5
|
+
type HtmlInjectorProps = Omit<React.ComponentProps<"div">, "dangerouslySetInnerHTML"> & {
|
|
6
|
+
/** The HTML content to inject and render */
|
|
7
|
+
html: string;
|
|
8
|
+
/**
|
|
9
|
+
* Whether to sanitize the HTML content by removing potentially dangerous elements and attributes
|
|
10
|
+
* @default false
|
|
11
|
+
*/
|
|
12
|
+
sanitize?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Whether to execute script tags found in the HTML content
|
|
15
|
+
* @default true
|
|
16
|
+
*/
|
|
17
|
+
executeScripts?: boolean;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* A robust component for safely injecting and rendering HTML content with optional script execution.
|
|
21
|
+
*
|
|
22
|
+
* This component provides a safe way to render dynamic HTML content with the following features:
|
|
23
|
+
* - Optional HTML sanitization to remove dangerous elements and attributes
|
|
24
|
+
* - Controlled script execution with proper cleanup
|
|
25
|
+
* - Memory leak prevention by tracking and removing injected scripts
|
|
26
|
+
* - Error handling for malformed HTML and script execution failures
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```tsx
|
|
30
|
+
* // Basic HTML injection
|
|
31
|
+
* <HtmlInjector html="<p>Hello <strong>World</strong></p>" />
|
|
32
|
+
*
|
|
33
|
+
* // With sanitization enabled
|
|
34
|
+
* <HtmlInjector
|
|
35
|
+
* html="<p>Safe content</p><script>alert('removed')</script>"
|
|
36
|
+
* sanitize={true}
|
|
37
|
+
* />
|
|
38
|
+
*
|
|
39
|
+
* // Disable script execution
|
|
40
|
+
* <HtmlInjector
|
|
41
|
+
* html="<p>Content</p><script>console.log('not executed')</script>"
|
|
42
|
+
* executeScripts={false}
|
|
43
|
+
* />
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* @param props - The component props
|
|
47
|
+
* @returns A div element containing the injected HTML content, or null if no HTML is provided
|
|
48
|
+
*/
|
|
49
|
+
export declare function HtmlInjector({ className, html, sanitize, executeScripts, ...props }: HtmlInjectorProps): import("react/jsx-runtime").JSX.Element;
|
|
50
|
+
export {};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cn } from "../functions";
|
|
5
|
+
/**
|
|
6
|
+
* A robust component for safely injecting and rendering HTML content with optional script execution.
|
|
7
|
+
*
|
|
8
|
+
* This component provides a safe way to render dynamic HTML content with the following features:
|
|
9
|
+
* - Optional HTML sanitization to remove dangerous elements and attributes
|
|
10
|
+
* - Controlled script execution with proper cleanup
|
|
11
|
+
* - Memory leak prevention by tracking and removing injected scripts
|
|
12
|
+
* - Error handling for malformed HTML and script execution failures
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* // Basic HTML injection
|
|
17
|
+
* <HtmlInjector html="<p>Hello <strong>World</strong></p>" />
|
|
18
|
+
*
|
|
19
|
+
* // With sanitization enabled
|
|
20
|
+
* <HtmlInjector
|
|
21
|
+
* html="<p>Safe content</p><script>alert('removed')</script>"
|
|
22
|
+
* sanitize={true}
|
|
23
|
+
* />
|
|
24
|
+
*
|
|
25
|
+
* // Disable script execution
|
|
26
|
+
* <HtmlInjector
|
|
27
|
+
* html="<p>Content</p><script>console.log('not executed')</script>"
|
|
28
|
+
* executeScripts={false}
|
|
29
|
+
* />
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @param props - The component props
|
|
33
|
+
* @returns A div element containing the injected HTML content, or null if no HTML is provided
|
|
34
|
+
*/
|
|
35
|
+
export function HtmlInjector({ className, html, sanitize = false, executeScripts = true, ...props }) {
|
|
36
|
+
const injectedScriptsRef = React.useRef([]);
|
|
37
|
+
const containerRef = React.useRef(null);
|
|
38
|
+
React.useEffect(() => {
|
|
39
|
+
// NOTE: Cleanup previously injected scripts
|
|
40
|
+
injectedScriptsRef.current.forEach((script) => {
|
|
41
|
+
if (script.parentNode) {
|
|
42
|
+
script.parentNode.removeChild(script);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
injectedScriptsRef.current = [];
|
|
46
|
+
if (!executeScripts || !html)
|
|
47
|
+
return;
|
|
48
|
+
try {
|
|
49
|
+
const tempContainer = document.createElement("div");
|
|
50
|
+
tempContainer.innerHTML = html;
|
|
51
|
+
const scripts = tempContainer.querySelectorAll("script");
|
|
52
|
+
scripts.forEach((oldScript) => {
|
|
53
|
+
const newScript = document.createElement("script");
|
|
54
|
+
// HACK: Copy text content
|
|
55
|
+
if (oldScript.textContent) {
|
|
56
|
+
newScript.textContent = oldScript.textContent;
|
|
57
|
+
}
|
|
58
|
+
// HACK: Copy all attributes (src, type, async, defer, etc.)
|
|
59
|
+
Array.from(oldScript.attributes).forEach((attr) => {
|
|
60
|
+
newScript.setAttribute(attr.name, attr.value);
|
|
61
|
+
});
|
|
62
|
+
newScript.onerror = (error) => {
|
|
63
|
+
console.error("Script injection error:", error);
|
|
64
|
+
};
|
|
65
|
+
document.body.appendChild(newScript);
|
|
66
|
+
injectedScriptsRef.current.push(newScript);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
console.error("HTML injection error:", error);
|
|
71
|
+
}
|
|
72
|
+
}, [html, executeScripts]);
|
|
73
|
+
React.useEffect(() => {
|
|
74
|
+
return () => {
|
|
75
|
+
injectedScriptsRef.current.forEach((script) => {
|
|
76
|
+
if (script.parentNode) {
|
|
77
|
+
script.parentNode.removeChild(script);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
}, []);
|
|
82
|
+
const processedHtml = React.useMemo(() => {
|
|
83
|
+
if (!html)
|
|
84
|
+
return "";
|
|
85
|
+
if (sanitize) {
|
|
86
|
+
// Basic sanitization - remove potentially dangerous elements
|
|
87
|
+
const container = document.createElement("div");
|
|
88
|
+
container.innerHTML = html;
|
|
89
|
+
// Remove script tags if sanitize is enabled
|
|
90
|
+
container.querySelectorAll("script").forEach((script) => script.remove());
|
|
91
|
+
// Remove potentially dangerous attributes
|
|
92
|
+
const dangerousAttrs = ["onclick", "onload", "onerror", "onmouseover"];
|
|
93
|
+
container.querySelectorAll("*").forEach((el) => {
|
|
94
|
+
dangerousAttrs.forEach((attr) => {
|
|
95
|
+
if (el.hasAttribute(attr)) {
|
|
96
|
+
el.removeAttribute(attr);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
return container.innerHTML;
|
|
101
|
+
}
|
|
102
|
+
return html;
|
|
103
|
+
}, [html, sanitize]);
|
|
104
|
+
if (!html) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
return (_jsx("div", { ref: containerRef, className: cn(className), dangerouslySetInnerHTML: { __html: processedHtml }, ...props }));
|
|
108
|
+
}
|
package/dist/components/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
export { Icon as Iconify } from '@iconify/react';
|
|
3
3
|
export { MediaWrapper } from './media-wrapper';
|
|
4
|
+
export { HtmlInjector } from './html-injector';
|
|
4
5
|
export { ResponsiveIndicator, ResponsiveIndicator as TailwindIndicator, } from './responsive-indicator';
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -33,7 +33,7 @@ export declare function useDebounce<T>(state: T, delay?: number): T;
|
|
|
33
33
|
/**
|
|
34
34
|
* Hook to handle effects with layout synchronization in the browser.
|
|
35
35
|
*/
|
|
36
|
-
export declare const useIsomorphicEffect: typeof React.
|
|
36
|
+
export declare const useIsomorphicEffect: typeof React.useEffect;
|
|
37
37
|
/**
|
|
38
38
|
* Hook to invoke a callback after a specified timeout.
|
|
39
39
|
* @param callback - The callback function to invoke.
|