diff --git a/components/lib/hooks/useStyle.js b/components/lib/hooks/useStyle.js index dbacbfff93..a467c7d1ff 100644 --- a/components/lib/hooks/useStyle.js +++ b/components/lib/hooks/useStyle.js @@ -1,45 +1,47 @@ import { useEffect, useRef, useState } from 'react'; -import { DomHandler, ObjectUtils } from '../utils/Utils'; +import PrimeReact, { PrimeReactContext } from '../api/Api'; +import { DomHandler } from '../utils/Utils'; let _id = 0; -export const useStyle = (css = {}, options = {}) => { +export const useStyle = (css, options = {}) => { const [isLoaded, setIsLoaded] = useState(false); + const styleRef = useRef(null); + const context = React.useContext(PrimeReactContext); - const cssRef = useRef(null); const defaultDocument = DomHandler.isClient() ? window.document : undefined; - const { document = defaultDocument, immediate = true, manual = false, name = `primereact_style_${++_id}`, media } = options; + const { document = defaultDocument, immediate = true, manual = false, name = `style_${++_id}`, id = undefined, media = undefined } = options; - useEffect(() => { - cssRef.current = css; - }, [css]); + const update = (newCSS) => { + isLoaded && css !== newCSS && (styleRef.current.textContent = newCSS); + }; const load = () => { if (!document) return; - const el = document.querySelector(`[data-pc-name="${name}"]`) || document.createElement('style'); + styleRef.current = document.querySelector(`style[data-primereact-style-id="${name}"]`) || document.getElementById(id) || document.createElement('style'); - if (ObjectUtils.isNotEmpty(el) || !el.isConnected) { - el.type = 'text/css'; - el.setAttribute('data-pc-name', name); - if (media) el.media = media; - document.head.appendChild(el); + if (!styleRef.current.isConnected) { + styleRef.current.type = 'text/css'; + id && (styleRef.current.id = id); + media && (styleRef.current.media = media); + DomHandler.addNonce(styleRef.current, (context && context.nonce) || PrimeReact.nonce); + document.head.appendChild(styleRef.current); + name && styleRef.current.setAttribute('data-primereact-style-id', name); } if (isLoaded) return; - el.textContent = cssRef.current; + styleRef.current.textContent = css; + setIsLoaded(true); }; const unload = () => { if (!document || !isLoaded) return; - const node = document.querySelector(`[data-pc-name="${name}"]`); - if (node && node.isConnected) { - document.head.removeChild(node); - setIsLoaded(false); - } + DomHandler.removeInlineStyle(styleRef.current); + setIsLoaded(false); }; useEffect(() => { @@ -50,8 +52,9 @@ export const useStyle = (css = {}, options = {}) => { }, [immediate, manual]); return { + id, name, - css: cssRef, + update, unload, load, isLoaded diff --git a/components/lib/utils/DomHandler.js b/components/lib/utils/DomHandler.js index 64e1364bd3..13cf91034e 100644 --- a/components/lib/utils/DomHandler.js +++ b/components/lib/utils/DomHandler.js @@ -981,15 +981,7 @@ export default class DomHandler { static createInlineStyle(nonce) { let styleElement = document.createElement('style'); - try { - if (!nonce) { - nonce = process.env.REACT_APP_CSS_NONCE; - } - } catch (error) { - // NOOP - } - - nonce && styleElement.setAttribute('nonce', nonce); + DomHandler.addNonce(styleElement, nonce); document.head.appendChild(styleElement); return styleElement; @@ -1009,6 +1001,18 @@ export default class DomHandler { return styleElement; } + static addNonce(styleElement, nonce) { + try { + if (!nonce) { + nonce = process.env.REACT_APP_CSS_NONCE; + } + } catch (error) { + // NOOP + } + + nonce && styleElement.setAttribute('nonce', nonce); + } + static getTargetElement(target) { if (!target) return null;