@@ -10,38 +10,41 @@ function addStylesheetRule(rule) {
10
10
11
11
const generateCssClassName = customAlphabet (
12
12
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' ,
13
- 32
13
+ 16
14
14
)
15
15
16
16
// Inspired by https://codesandbox.io/s/pseudo-class-sticker-sheet-jiu2x
17
17
const useAddSelector = ( ref , selector ) => {
18
18
const [ modifiedClassName , setModifiedClassName ] = useState ( '' )
19
19
useEffect ( ( ) => {
20
- const className = ref . current . classList [ ref . current . classList . length - 1 ]
20
+ const className = ref . current ? .classList [ ref . current . classList . length - 1 ]
21
21
const fullSelector = `${ className && `.${ className } ` } ${ selector } `
22
- // NOTE: This could be improved, because checking the provided selector starts with a '.'
23
- // is probably not the best way to determine the selector is a class name or not.
24
- const isClassNameSelector = selector . startsWith ( '.' )
25
- let newRule = ''
26
- for ( const ss of document . styleSheets ) {
27
- for ( const rule of ss . cssRules ) {
28
- if ( fullSelector === rule . selectorText ) {
29
- const cssClassName = isClassNameSelector ? selector : `.${ generateCssClassName ( ) } `
30
- newRule = `${ cssClassName } { ${ rule . style . cssText } }`
31
- setModifiedClassName ( cssClassName . substring ( 1 ) )
32
- break
22
+ const newClassName = generateCssClassName ( )
23
+ let newRules = [ ]
24
+ for ( const styleSheet of document . styleSheets ) {
25
+ for ( const rule of styleSheet . cssRules ) {
26
+ if ( rule . selectorText ?. startsWith ( fullSelector ) ) {
27
+ /**
28
+ * Replace current CSS selector with the generated one so that
29
+ * after adding the newClassName all children can be matched
30
+ * i.e. we map:
31
+ * .component:focus > input -> .generatedClass > input
32
+ */
33
+ const CSSSelector = rule . selectorText . replace ( fullSelector , `.${ newClassName } ` )
34
+ newRules . push ( `${ CSSSelector } { ${ rule . style . cssText } }` )
33
35
}
34
36
}
35
- if ( newRule ) {
36
- addStylesheetRule ( newRule )
37
- break
37
+ if ( newRules . length > 0 ) {
38
+ newRules . forEach ( addStylesheetRule )
39
+ setModifiedClassName ( newClassName )
40
+ break // Avoid triggering infinite loop since we're modifying stylesheets
38
41
}
39
42
}
40
43
} , [ ref , selector ] )
41
44
return [ modifiedClassName ]
42
45
}
43
46
44
- const WithSelector = props => {
47
+ const WithSelector = ( props ) => {
45
48
const ref = useRef ( null )
46
49
const [ modifiedClassName ] = useAddSelector ( ref , props . selector )
47
50
0 commit comments