diff --git a/src/react/hooks/paragon/useParagonThemeVariants.js b/src/react/hooks/paragon/useParagonThemeVariants.js index 737129ef9..a83eabba7 100644 --- a/src/react/hooks/paragon/useParagonThemeVariants.js +++ b/src/react/hooks/paragon/useParagonThemeVariants.js @@ -48,7 +48,7 @@ const useParagonThemeVariants = ({ document.querySelector('html').removeAttribute(htmlDataThemeVariantAttr); }; } - return () => {}; // no-op + return () => { }; // no-op }, [themeVariants, currentThemeVariant]); useEffect(() => { @@ -160,12 +160,15 @@ const useParagonThemeVariants = ({ return themeVariantLink; }; - if (!existingThemeVariantLink) { - const paragonThemeVariantLink = createThemeVariantLink(value.urls.default); - document.head.insertAdjacentElement( - 'afterbegin', - paragonThemeVariantLink, - ); + const insertBrandThemeVariantLink = () => { + const updatedStylesheetRel = generateStylesheetRelAttr(themeVariant); + + if (existingThemeVariantBrandLink) { + existingThemeVariantBrandLink.rel = updatedStylesheetRel; + existingThemeVariantBrandLink.removeAttribute('as'); + existingThemeVariantBrandLink.dataset.brandThemeVariant = themeVariant; + return; + } if (value.urls.brandOverride) { const brandThemeVariantLink = createThemeVariantLink(value.urls.brandOverride, { isBrandOverride: true }); @@ -181,20 +184,26 @@ const useParagonThemeVariants = ({ brandThemeVariantLink, ); } - } else { - setIsBrandThemeVariantLoaded(true); } + setIsBrandThemeVariantLoaded(true); + }; + + if (!existingThemeVariantLink) { + const paragonThemeVariantLink = createThemeVariantLink(value.urls.default); + document.head.insertAdjacentElement( + 'afterbegin', + paragonThemeVariantLink, + ); + insertBrandThemeVariantLink(existingThemeVariantBrandLink); } else { const updatedStylesheetRel = generateStylesheetRelAttr(themeVariant); existingThemeVariantLink.rel = updatedStylesheetRel; existingThemeVariantLink.removeAttribute('as'); - if (existingThemeVariantBrandLink) { - existingThemeVariantBrandLink.rel = updatedStylesheetRel; - existingThemeVariantBrandLink.removeAttribute('as'); - } - setIsParagonThemeVariantLoaded(true); - setIsBrandThemeVariantLoaded(true); + existingThemeVariantLink.dataset.paragonThemeVariant = themeVariant; + insertBrandThemeVariantLink(existingThemeVariantBrandLink); } + setIsParagonThemeVariantLoaded(true); + setIsBrandThemeVariantLoaded(true); }); }, [themeVariants, currentThemeVariant, onLoad]); }; diff --git a/src/react/hooks/paragon/useParagonThemeVariants.test.js b/src/react/hooks/paragon/useParagonThemeVariants.test.js index 505b863b4..85567231b 100644 --- a/src/react/hooks/paragon/useParagonThemeVariants.test.js +++ b/src/react/hooks/paragon/useParagonThemeVariants.test.js @@ -97,4 +97,28 @@ describe('useParagonThemeVariants', () => { expect(document.head.querySelectorAll('link').length).toBe(0); }); + it('shoud not create a new link if it already exists', () => { + document.head.innerHTML = ''; + + const themeVariants = { + light: { + urls: { + default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/light.min.css', + }, + }, + dark: { + urls: { + default: 'https://cdn.jsdelivr.net/npm/@edx/paragon@$21.0.0/dist/dark.min.css', + }, + }, + }; + + const currentTheme = 'light'; + renderHook(() => useParagonThemeVariants({ themeVariants, currentTheme, onLoad: themeOnLoad })); + const themeLinks = document.head.querySelectorAll('link'); + const lightThemeLink = document.head.querySelector('link[data-paragon-theme-variant="light"]'); + expect(themeLinks.length).toBe(2); + expect(lightThemeLink.rel).toContain('stylesheet'); + expect(lightThemeLink).not.toHaveAttribute('as', 'style'); + }); });