From 29696f8d83efb76fa07edf54a961e0d38778f67f Mon Sep 17 00:00:00 2001 From: Anton Ignatov Date: Thu, 12 Sep 2024 13:29:34 +0200 Subject: [PATCH 1/3] fixed prefixCssSelectors implementation (fix #377) --- packages/docusaurus-theme-redoc/package.json | 3 + .../src/theme/Redoc/ServerStyles.tsx | 87 ++++++------------- yarn.lock | 32 +++++++ 3 files changed, 60 insertions(+), 62 deletions(-) diff --git a/packages/docusaurus-theme-redoc/package.json b/packages/docusaurus-theme-redoc/package.json index 33044893..b1ac8c03 100644 --- a/packages/docusaurus-theme-redoc/package.json +++ b/packages/docusaurus-theme-redoc/package.json @@ -36,6 +36,8 @@ "clsx": "^1.2.1", "lodash": "^4.17.21", "mobx": "^6.12.4", + "postcss": "^8.4.45", + "postcss-prefix-selector": "^1.16.1", "redoc": "2.1.5", "styled-components": "^6.1.11" }, @@ -45,6 +47,7 @@ "@docusaurus/theme-common": "^3.4.0", "@docusaurus/types": "^3.4.0", "@types/lodash": "^4.14.200", + "@types/postcss-prefix-selector": "^1", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "@types/react-is": "^18.3.0", diff --git a/packages/docusaurus-theme-redoc/src/theme/Redoc/ServerStyles.tsx b/packages/docusaurus-theme-redoc/src/theme/Redoc/ServerStyles.tsx index 1969cdd5..afa8c5da 100644 --- a/packages/docusaurus-theme-redoc/src/theme/Redoc/ServerStyles.tsx +++ b/packages/docusaurus-theme-redoc/src/theme/Redoc/ServerStyles.tsx @@ -5,49 +5,27 @@ import { AppStore, Redoc, RedocRawOptions } from 'redoc'; // eslint-disable-next-line import/no-extraneous-dependencies import { renderToString } from 'react-dom/server'; import { ServerStyleSheet } from 'styled-components'; +import postcss from 'postcss'; +import prefixer from 'postcss-prefix-selector'; -/** - * @see https://stackoverflow.com/a/54077142 - */ -const prefixCssSelectors = function (rules: string, className: string) { - const classLen = className.length; - let char, nextChar, isAt, isIn; - - // makes sure the className will not concatenate the selector - className += ' '; - - // removes comments - rules = rules.replace(/\/\*(?:(?!\*\/)[\s\S])*\*\/|[\r\n\t]+/g, ''); - - // makes sure nextChar will not target a space - rules = rules.replace(/}(\s*)@/g, '}@'); - rules = rules.replace(/}(\s*)}/g, '}}'); - - for (let i = 0; i < rules.length - 2; i++) { - char = rules[i]; - nextChar = rules[i + 1]; +const prefixCssSelectors = function (css: string, className: string): string { + const processor = postcss().use( + prefixer({ + prefix: className, + }), + ); - if (char === '@' && nextChar !== 'f') isAt = true; - if (!isAt && char === '{') isIn = true; - if (isIn && char === '}') isIn = false; + return processor.process(css).css; +}; - if ( - !isIn && - nextChar !== '@' && - nextChar !== '}' && - (char === '}' || char === ',' || ((char === '{' || char === ';') && isAt)) - ) { - rules = rules.slice(0, i + 1) + className + rules.slice(i + 1); - i += classLen; - isAt = false; - } - } +const renderCss = function (store: AppStore): string { + const styleSheet = new ServerStyleSheet(); - // prefix the first select if it is not `@media` and if it is not yet prefixed - if (rules.indexOf(className) !== 0 && rules.indexOf('@') !== 0) - rules = className + rules; + renderToString( + styleSheet.collectStyles(React.createElement(Redoc, { store })), + ); - return rules; + return String(styleSheet.instance); }; const LIGHT_MODE_PREFIX = "html:not([data-theme='dark'])"; @@ -63,41 +41,26 @@ export function ServerStyles({ darkThemeOptions: RedocRawOptions; }) { const fullUrl = useBaseUrl(specProps.url, { absolute: true }); - const css = { - light: '', - dark: '', - }; - const lightSheet = new ServerStyleSheet(); - const lightStore = new AppStore(specProps.spec, fullUrl, lightThemeOptions); - renderToString( - lightSheet.collectStyles(React.createElement(Redoc, { store: lightStore })), - ); - const lightStyleTag = lightSheet.getStyleTags(); - let lightCss = lightStyleTag.slice(lightStyleTag.indexOf('>') + 1); - lightCss = lightCss.slice(0, lightCss.indexOf('') + 1); - darkCss = darkCss.slice(0, darkCss.indexOf('