Skip to content

Commit fa09df8

Browse files
EvanBaconnecolas
andcommitted
[fix] ScrollView support for hiding scroll indicators
Implements 'showsHorizontalScrollIndicator' and 'showVerticalScrollIndicator' by polyfilling the 'scrollbar-width' property from the draft CSS spec for scrollbars. Scrollbars can only be shown for both or neither axis. Close necolas#1307 Co-authored-by: Nicolas Gallagher <nicolasgallagher@gmail.com>
1 parent be5106f commit fa09df8

File tree

6 files changed

+37
-7
lines changed

6 files changed

+37
-7
lines changed

packages/react-native-web/src/exports/ScrollView/ScrollViewBase.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,17 +122,20 @@ export default class ScrollViewBase extends Component<*> {
122122
...other
123123
} = this.props;
124124

125+
const hideScrollbar =
126+
showsHorizontalScrollIndicator === false || showsVerticalScrollIndicator === false;
125127
return (
126128
<View
127129
{...other}
128130
onScroll={this._handleScroll}
129131
onTouchMove={this._createPreventableScrollHandler(this.props.onTouchMove)}
130132
onWheel={this._createPreventableScrollHandler(this.props.onWheel)}
131133
ref={this._setViewRef}
132-
style={StyleSheet.compose(
134+
style={[
133135
style,
134-
!scrollEnabled && styles.scrollDisabled
135-
)}
136+
!scrollEnabled && styles.scrollDisabled,
137+
hideScrollbar && style.hideScrollbar
138+
]}
136139
/>
137140
);
138141
}
@@ -204,5 +207,8 @@ export default class ScrollViewBase extends Component<*> {
204207
const styles = StyleSheet.create({
205208
scrollDisabled: {
206209
touchAction: 'none'
210+
},
211+
hideScrollbar: {
212+
scrollbarWidth: 'none'
207213
}
208214
});

packages/react-native-web/src/exports/StyleSheet/__tests__/__snapshots__/compile-test.js.snap

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,15 @@ Object {
5858
],
5959
"value": "box-only",
6060
},
61+
"r-scrollbarWidth-2eszeu": Object {
62+
"identifier": "r-scrollbarWidth-2eszeu",
63+
"property": "scrollbarWidth",
64+
"rules": Array [
65+
".r-scrollbarWidth-2eszeu::-webkit-scrollbar{display:none}",
66+
".r-scrollbarWidth-2eszeu{overflow:-moz-scrollbars-none;-ms-overflow-style:none}",
67+
],
68+
"value": "none",
69+
},
6170
"r-transform-1ehiua4": Object {
6271
"identifier": "r-transform-1ehiua4",
6372
"property": "transform",

packages/react-native-web/src/exports/StyleSheet/__tests__/compile-test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ describe('StyleSheet/compile', () => {
1616
fontFamily: 'System',
1717
marginHorizontal: 10,
1818
placeholderTextColor: 'gray',
19+
scrollbarWidth: 'none',
1920
pointerEvents: 'box-only',
2021
transform: [
2122
{

packages/react-native-web/src/exports/StyleSheet/compile.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export function atomic(style: Style): CompilerOutput {
7575

7676
/**
7777
* Compile simple style object to classic CSS rules.
78-
* No support for 'placeholderTextColor' or 'pointerEvents'.
78+
* No support for 'placeholderTextColor', 'scrollbarWidth', or 'pointerEvents'.
7979
*/
8080
export function classic(style: Style, name: string): CompilerOutput {
8181
const identifier = createIdentifier('css', name, style);
@@ -97,7 +97,7 @@ export function classic(style: Style, name: string): CompilerOutput {
9797

9898
/**
9999
* Compile simple style object to inline DOM styles.
100-
* No support for 'animationKeyframes', 'placeholderTextColor', or 'pointerEvents'.
100+
* No support for 'animationKeyframes', 'placeholderTextColor', 'scrollbarWidth', or 'pointerEvents'.
101101
*/
102102
export function inline(style: Style) {
103103
return prefixInlineStyles(createReactDOMStyle(style));
@@ -144,6 +144,18 @@ function createAtomicRules(identifier: string, property, value): Rules {
144144
break;
145145
}
146146

147+
// Polyfill for draft spec
148+
// https://drafts.csswg.org/css-scrollbars-1/
149+
case 'scrollbarWidth': {
150+
if (value === 'none') {
151+
rules.push(
152+
`${selector}::-webkit-scrollbar{display:none}`,
153+
`${selector}{overflow:-moz-scrollbars-none;-ms-overflow-style:none}`
154+
);
155+
}
156+
break;
157+
}
158+
147159
// See #513
148160
case 'pointerEvents': {
149161
let finalValue = value;

packages/react-native-web/src/exports/StyleSheet/createStyleResolver.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,9 +231,10 @@ export default function createStyleResolver() {
231231
// require more complex transforms into multiple CSS rules. Here we assume that StyleManager
232232
// can bind these styles to a className, and prevent them becoming invalid inline-styles.
233233
if (
234-
styleProp === 'pointerEvents' ||
234+
styleProp === 'animationKeyframes' ||
235235
styleProp === 'placeholderTextColor' ||
236-
styleProp === 'animationKeyframes'
236+
styleProp === 'pointerEvents' ||
237+
styleProp === 'scrollbarWidth'
237238
) {
238239
const a = atomic({ [styleProp]: value });
239240
Object.values(a).forEach(({ identifier, rules }) => {

packages/react-native-web/src/exports/View/ViewStylePropTypes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ const ViewStylePropTypes = {
5555
overscrollBehavior: overscrollBehaviorType,
5656
overscrollBehaviorX: overscrollBehaviorType,
5757
overscrollBehaviorY: overscrollBehaviorType,
58+
scrollbarWidth: oneOf(['auto', 'none']),
5859
scrollSnapAlign: string,
5960
scrollSnapType: string,
6061
WebkitMaskImage: string,

0 commit comments

Comments
 (0)