@@ -4,17 +4,94 @@ import { AppStore, Redoc } from 'redoc';
4
4
import { renderToString } from 'react-dom/server' ;
5
5
import { ServerStyleSheet } from 'styled-components' ;
6
6
7
- export function ServerStyles ( { store } : { store : AppStore } ) {
8
- const sheet = new ServerStyleSheet ( ) ;
9
- renderToString ( sheet . collectStyles ( React . createElement ( Redoc , { store } ) ) ) ;
10
- const css = sheet . getStyleTags ( ) ;
7
+ /**
8
+ * @see https://stackoverflow.com/a/54077142
9
+ */
10
+ const prefixCssSelectors = function ( rules : string , className : string ) {
11
+ const classLen = className . length ;
12
+ let char , nextChar , isAt , isIn ;
13
+
14
+ // makes sure the className will not concatenate the selector
15
+ className += ' ' ;
16
+
17
+ // removes comments
18
+ rules = rules . replace ( / \/ \* (?: (? ! \* \/ ) [ \s \S ] ) * \* \/ | [ \r \n \t ] + / g, '' ) ;
19
+
20
+ // makes sure nextChar will not target a space
21
+ rules = rules . replace ( / } ( \s * ) @ / g, '}@' ) ;
22
+ rules = rules . replace ( / } ( \s * ) } / g, '}}' ) ;
23
+
24
+ for ( let i = 0 ; i < rules . length - 2 ; i ++ ) {
25
+ char = rules [ i ] ;
26
+ nextChar = rules [ i + 1 ] ;
27
+
28
+ if ( char === '@' && nextChar !== 'f' ) isAt = true ;
29
+ if ( ! isAt && char === '{' ) isIn = true ;
30
+ if ( isIn && char === '}' ) isIn = false ;
31
+
32
+ if (
33
+ ! isIn &&
34
+ nextChar !== '@' &&
35
+ nextChar !== '}' &&
36
+ ( char === '}' || char === ',' || ( ( char === '{' || char === ';' ) && isAt ) )
37
+ ) {
38
+ rules = rules . slice ( 0 , i + 1 ) + className + rules . slice ( i + 1 ) ;
39
+ i += classLen ;
40
+ isAt = false ;
41
+ }
42
+ }
43
+
44
+ // prefix the first select if it is not `@media` and if it is not yet prefixed
45
+ if ( rules . indexOf ( className ) !== 0 && rules . indexOf ( '@' ) !== 0 )
46
+ rules = className + rules ;
47
+
48
+ return rules ;
49
+ } ;
50
+
51
+ const LIGHT_MODE_PREFIX = "html:not([data-theme='dark'])" ;
52
+ const DARK_MODE_PREFIX = "html([data-theme='dark'])" ;
53
+
54
+ export function ServerStyles ( {
55
+ lightStore,
56
+ darkStore,
57
+ } : {
58
+ lightStore : AppStore ;
59
+ darkStore : AppStore ;
60
+ } ) {
61
+ const css = {
62
+ light : '' ,
63
+ dark : '' ,
64
+ } ;
65
+ const lightSheet = new ServerStyleSheet ( ) ;
66
+ renderToString (
67
+ lightSheet . collectStyles ( React . createElement ( Redoc , { store : lightStore } ) ) ,
68
+ ) ;
69
+ const lightStyleTag = lightSheet . getStyleTags ( ) ;
70
+ let lightCss = lightStyleTag . slice ( lightStyleTag . indexOf ( '>' ) + 1 ) ;
71
+ lightCss = lightCss . slice ( 0 , lightCss . indexOf ( '<style' ) ) ;
72
+ css . light = prefixCssSelectors ( lightCss , LIGHT_MODE_PREFIX ) ;
73
+
74
+ const darkSheet = new ServerStyleSheet ( ) ;
75
+ renderToString (
76
+ darkSheet . collectStyles ( React . createElement ( Redoc , { store : darkStore } ) ) ,
77
+ ) ;
78
+ const darkStyleTag = darkSheet . getStyleTags ( ) ;
79
+ let darkCss = darkStyleTag . slice ( darkStyleTag . indexOf ( '>' ) + 1 ) ;
80
+ darkCss = darkCss . slice ( 0 , darkCss . indexOf ( '<style' ) ) ;
81
+ css . dark = prefixCssSelectors ( darkCss , DARK_MODE_PREFIX ) . slice (
82
+ DARK_MODE_PREFIX . length + 1 ,
83
+ ) ;
11
84
12
85
return (
13
- < div
14
- className = "redocusaurus-styles"
15
- dangerouslySetInnerHTML = { {
16
- __html : css ,
17
- } }
18
- />
86
+ < div className = "redocusaurus-styles" >
87
+ < style
88
+ key = "light-mode-styles"
89
+ dangerouslySetInnerHTML = { { __html : css . light } }
90
+ />
91
+ < style
92
+ key = "dark-mode-styles"
93
+ dangerouslySetInnerHTML = { { __html : css . dark } }
94
+ />
95
+ </ div >
19
96
) ;
20
97
}
0 commit comments