@@ -66,15 +66,27 @@ const nativeVariantSelectors = new Map([
66
66
[ 'hovered' , ':hover' ] ,
67
67
[ 'focused' , ':focus' ] ,
68
68
[ 'readonly' , ':read-only' ] ,
69
- [ 'open' , '[open]' ] ,
69
+ [ 'open' , '[open]' ]
70
+ ] ) ;
71
+
72
+ // Variants where both native and RAC attributes should apply. We don't override these.
73
+ const nativeMergeSelectors = new Map ( [
70
74
[ 'placeholder' , ':placeholder-shown' ]
71
75
] ) ;
72
76
73
77
// If no prefix is specified, we want to avoid overriding native variants on non-RAC components, so we only target elements with the data-rac attribute for those variants.
74
- let getSelector = ( prefix , attributeName , attributeValue ) => {
78
+ let getSelector = ( prefix , attributeName , attributeValue , hoverOnlyWhenSupported ) => {
75
79
let baseSelector = attributeValue ? `[data-${ attributeName } ="${ attributeValue } "]` : `[data-${ attributeName } ]` ;
76
- if ( prefix === '' && nativeVariantSelectors . has ( attributeName ) ) {
77
- return [ `&:where([data-rac])${ baseSelector } ` , `&:where(:not([data-rac]))${ nativeVariantSelectors . get ( attributeName ) } ` ] ;
80
+ let nativeSelector = nativeVariantSelectors . get ( attributeName ) ;
81
+ if ( prefix === '' && nativeSelector ) {
82
+ let wrappedNativeSelector = `&:where(:not([data-rac]))${ nativeSelector } ` ;
83
+ let nativeSelectorGenerator = wrappedNativeSelector ;
84
+ if ( nativeSelector === ':hover' && hoverOnlyWhenSupported ) {
85
+ nativeSelectorGenerator = wrap => `@media (hover: hover) and (pointer: fine) { ${ wrap ( wrappedNativeSelector ) } }` ;
86
+ }
87
+ return [ `&:where([data-rac])${ baseSelector } ` , nativeSelectorGenerator ] ;
88
+ } else if ( prefix === '' && nativeMergeSelectors . has ( attributeName ) ) {
89
+ return [ `&${ baseSelector } ` , `&${ nativeMergeSelectors . get ( attributeName ) } ` ] ;
78
90
} else {
79
91
return `&${ baseSelector } ` ;
80
92
}
@@ -88,36 +100,46 @@ let mapSelector = (selector, fn) => {
88
100
}
89
101
} ;
90
102
103
+ let wrapSelector = ( selector , wrap ) => {
104
+ if ( typeof selector === 'function' ) {
105
+ return selector ( wrap ) ;
106
+ } else {
107
+ return wrap ( selector ) ;
108
+ }
109
+ } ;
110
+
91
111
let addVariants = ( variantName , selectors , addVariant , matchVariant ) => {
92
- addVariant ( variantName , selectors ) ;
112
+ addVariant ( variantName , mapSelector ( selectors , selector => wrapSelector ( selector , s => s ) ) ) ;
93
113
matchVariant (
94
114
'group' ,
95
115
( _ , { modifier} ) =>
96
116
modifier
97
- ? mapSelector ( selectors , selector => `:merge(.group\\/${ modifier } )${ selector . slice ( 1 ) } &` )
98
- : mapSelector ( selectors , selector => `:merge(.group)${ selector . slice ( 1 ) } &` ) ,
117
+ ? mapSelector ( selectors , selector => wrapSelector ( selector , s => `:merge(.group\\/${ modifier } )${ s . slice ( 1 ) } &` ) )
118
+ : mapSelector ( selectors , selector => wrapSelector ( selector , s => `:merge(.group)${ s . slice ( 1 ) } &` ) ) ,
99
119
{ values : { [ variantName ] : variantName } }
100
120
) ;
101
121
matchVariant (
102
122
'peer' ,
103
123
( _ , { modifier} ) =>
104
124
modifier
105
- ? mapSelector ( selectors , selector => `:merge(.peer\\/${ modifier } )${ selector . slice ( 1 ) } ~ &` )
106
- : mapSelector ( selectors , selector => `:merge(.peer)${ selector . slice ( 1 ) } ~ &` ) ,
125
+ ? mapSelector ( selectors , selector => wrapSelector ( selector , s => `:merge(.peer\\/${ modifier } )${ s . slice ( 1 ) } ~ &` ) )
126
+ : mapSelector ( selectors , selector => wrapSelector ( selector , s => `:merge(.peer)${ s . slice ( 1 ) } ~ &` ) ) ,
107
127
{ values : { [ variantName ] : variantName } }
108
128
) ;
109
129
} ;
110
130
111
- module . exports = plugin . withOptions ( ( options ) => ( ( { addVariant, matchVariant} ) => {
131
+ module . exports = plugin . withOptions ( ( options ) => ( ( { addVariant, matchVariant, config } ) => {
112
132
let prefix = options ?. prefix ? `${ options . prefix } -` : '' ;
133
+ let future = config ( ) . future ;
134
+ let hoverOnlyWhenSupported = future === 'all' || future ?. hoverOnlyWhenSupported ;
113
135
114
136
// Enum attributes go first because currently they are all non-interactive states.
115
137
Object . keys ( attributes . enum ) . forEach ( ( attributeName ) => {
116
138
attributes . enum [ attributeName ] . forEach (
117
139
( attributeValue ) => {
118
140
let name = shortNames [ attributeName ] || attributeName ;
119
141
let variantName = `${ prefix } ${ name } -${ attributeValue } ` ;
120
- let selectors = getSelector ( prefix , attributeName , attributeValue ) ;
142
+ let selectors = getSelector ( prefix , attributeName , attributeValue , hoverOnlyWhenSupported ) ;
121
143
addVariants ( variantName , selectors , addVariant , matchVariant ) ;
122
144
}
123
145
) ;
@@ -127,7 +149,7 @@ module.exports = plugin.withOptions((options) => (({addVariant, matchVariant}) =
127
149
let variantName = Array . isArray ( attribute ) ? attribute [ 0 ] : attribute ;
128
150
variantName = `${ prefix } ${ variantName } ` ;
129
151
let attributeName = Array . isArray ( attribute ) ? attribute [ 1 ] : attribute ;
130
- let selectors = getSelector ( prefix , attributeName ) ;
152
+ let selectors = getSelector ( prefix , attributeName , null , hoverOnlyWhenSupported ) ;
131
153
addVariants ( variantName , selectors , addVariant , matchVariant ) ;
132
154
} ) ;
133
155
} ) ) ;
0 commit comments