Skip to content

Commit 0e2aa5d

Browse files
committed
Add scrollTopAtClose prop; Add marginTop prop; Add scrollable example; Add onTransitionEnd prop; shadows are now hidden when overflowHeight is set to 0 and sheet is closed; New release 1.1.0
1 parent 01be0f9 commit 0e2aa5d

18 files changed

+390
-80
lines changed

README.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ npm i -S react-swipeable-bottom-sheet
1717
- [Uncontrolled bottom sheet](http://manufont.github.io/react-swipeable-bottom-sheet/index.html)
1818
- [Controlled bottom sheet](http://manufont.github.io/react-swipeable-bottom-sheet/controlled.html)
1919
- [Fullscreen bottom sheet](http://manufont.github.io/react-swipeable-bottom-sheet/fullscreen.html)
20+
- [Scrollable bottom sheet](http://manufont.github.io/react-swipeable-bottom-sheet/scroll.html)
2021

2122

2223
## Usage
@@ -32,7 +33,7 @@ import SwipeableBottomSheet from 'react-swipeable-bottom-sheet';
3233
</SwipeableBottomSheet>
3334
```
3435

35-
The bottom sheet's height (when open) scales automatically with its content. If it exceeds the window height, content is scrollable.
36+
The bottom sheet's height (when open) scales automatically with its content. If it exceeds the window height, content become scrollable.
3637

3738

3839
### Props
@@ -43,10 +44,13 @@ The bottom sheet's height (when open) scales automatically with its content. If
4344
| open | bool | | Use this property to enable controlled mode. If `true`, it will open the sheet. |
4445
| defaultOpen | bool | false | If `true`, the sheet is open at component mount. |
4546
| onChange | function(isOpen) | | The callback that fires after sheet opens or closes. |
47+
| onTransitionEnd | function() | | The callback that fires after opening or closing animation. |
4648
| fullScreen | bool | false | If `true`, the sheet takes the full height of the window when open. |
49+
| marginTop | number | 0 | The top margin applied to the top of the sheet when open. Use this prop to prevent navbar overflow. |
4750
| shadowTip | bool | true | If `true`, a box shadow is displayed at sheet bottom when closed. This is used to show that content is hidden below. |
4851
| topShadow | bool | true | If `true`, a box shadow is displayed at sheet top border. |
4952
| overlay | bool | true | If `true`, an overlay is displayed behind sheet when open. A click on the overlay closes the sheet. |
53+
| scrollTopAtClose | bool | true | If `true`, the content is scrolled to the top when sheet closes. |
5054
| swipeableViewsProps | object | `{}` | Props passed to SwipeableViews component (see [documentation](https://github.com/oliviertassinari/react-swipeable-views#api)). |
5155
| style | object | `{}` | Style applied on the root (non-swiped) component. |
5256
| bodyStyle | object | `{}` | Style applied on the body of the bottom sheet. |

dist/react-swipeable-bottom-sheet.js

+117-21
Original file line numberDiff line numberDiff line change
@@ -3874,7 +3874,6 @@ var HeightUpdater = (function (_Component) {
38743874
key: 'componentWillMount',
38753875
value: function componentWillMount() {
38763876
window.addEventListener('resize', this.onWindowResize);
3877-
this.onWindowResize();
38783877
}
38793878
}, {
38803879
key: 'componentWillUnmount',
@@ -3908,6 +3907,64 @@ Object.defineProperty(exports, '__esModule', {
39083907
value: true
39093908
});
39103909

3910+
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
3911+
3912+
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
3913+
3914+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
3915+
3916+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
3917+
3918+
function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
3919+
3920+
var _react = (typeof window !== "undefined" ? window['React'] : typeof global !== "undefined" ? global['React'] : null);
3921+
3922+
var _react2 = _interopRequireDefault(_react);
3923+
3924+
var _propTypes = require('prop-types');
3925+
3926+
var _propTypes2 = _interopRequireDefault(_propTypes);
3927+
3928+
var ScrollToTop = (function (_Component) {
3929+
_inherits(ScrollToTop, _Component);
3930+
3931+
function ScrollToTop() {
3932+
_classCallCheck(this, ScrollToTop);
3933+
3934+
_get(Object.getPrototypeOf(ScrollToTop.prototype), 'constructor', this).apply(this, arguments);
3935+
}
3936+
3937+
_createClass(ScrollToTop, [{
3938+
key: 'componentDidMount',
3939+
value: function componentDidMount() {
3940+
this.props.element().scrollTop = 0;
3941+
}
3942+
}, {
3943+
key: 'render',
3944+
value: function render() {
3945+
return null;
3946+
}
3947+
}]);
3948+
3949+
return ScrollToTop;
3950+
})(_react.Component);
3951+
3952+
ScrollToTop.propTypes = {
3953+
element: _propTypes2['default'].func.isRequired
3954+
};
3955+
3956+
exports['default'] = ScrollToTop;
3957+
module.exports = exports['default'];
3958+
3959+
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
3960+
},{"prop-types":100}],116:[function(require,module,exports){
3961+
(function (global){
3962+
'use strict';
3963+
3964+
Object.defineProperty(exports, '__esModule', {
3965+
value: true
3966+
});
3967+
39113968
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
39123969

39133970
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
@@ -3936,6 +3993,10 @@ var _HeightUpdater = require('./HeightUpdater');
39363993

39373994
var _HeightUpdater2 = _interopRequireDefault(_HeightUpdater);
39383995

3996+
var _ScrollToTop = require('./ScrollToTop');
3997+
3998+
var _ScrollToTop2 = _interopRequireDefault(_ScrollToTop);
3999+
39394000
var SwipeableBottomSheet = (function (_Component) {
39404001
_inherits(SwipeableBottomSheet, _Component);
39414002

@@ -3944,8 +4005,13 @@ var SwipeableBottomSheet = (function (_Component) {
39444005

39454006
_get(Object.getPrototypeOf(SwipeableBottomSheet.prototype), 'constructor', this).call(this, props);
39464007

4008+
this.onHeightChange = this.onHeightChange.bind(this);
4009+
this.onChangeIndex = this.onChangeIndex.bind(this);
4010+
this.onTransitionEnd = this.onTransitionEnd.bind(this);
4011+
39474012
this.state = {
3948-
open: props.defaultOpen
4013+
open: props.defaultOpen,
4014+
height: window.innerHeight
39494015
};
39504016
}
39514017

@@ -3966,22 +4032,41 @@ var SwipeableBottomSheet = (function (_Component) {
39664032
}
39674033
}
39684034
}, {
3969-
key: 'render',
3970-
value: function render() {
3971-
var _this = this;
3972-
4035+
key: 'onTransitionEnd',
4036+
value: function onTransitionEnd() {
39734037
var _props = this.props;
39744038
var overflowHeight = _props.overflowHeight;
3975-
var fullScreen = _props.fullScreen;
3976-
var open = _props.open;
3977-
var topShadow = _props.topShadow;
3978-
var shadowTip = _props.shadowTip;
3979-
var overlay = _props.overlay;
39804039
var swipeableViewsProps = _props.swipeableViewsProps;
39814040

4041+
if (overflowHeight === 0) {
4042+
this.bodyElt.scrollTop = 0;
4043+
}
4044+
if (swipeableViewsProps.onTransitionEnd) {
4045+
swipeableViewsProps.onTransitionEnd();
4046+
}
4047+
}
4048+
}, {
4049+
key: 'render',
4050+
value: function render() {
4051+
var _this = this;
4052+
4053+
var _props2 = this.props;
4054+
var overflowHeight = _props2.overflowHeight;
4055+
var fullScreen = _props2.fullScreen;
4056+
var marginTop = _props2.marginTop;
4057+
var open = _props2.open;
4058+
var topShadow = _props2.topShadow;
4059+
var shadowTip = _props2.shadowTip;
4060+
var overlay = _props2.overlay;
4061+
var swipeableViewsProps = _props2.swipeableViewsProps;
4062+
var scrollTopAtClose = _props2.scrollTopAtClose;
4063+
4064+
var hiddenWhenClosed = overflowHeight === 0;
39824065
var isControlled = open !== undefined;
39834066
var isOpen = isControlled ? open : this.state.open;
4067+
var hideShadows = hiddenWhenClosed && !isOpen;
39844068
var index = isOpen ? 1 : 0;
4069+
var maxHeight = this.state.height - marginTop;
39854070

39864071
var styles = {
39874072
root: _extends({
@@ -3998,7 +4083,7 @@ var SwipeableBottomSheet = (function (_Component) {
39984083
}, swipeableViewsProps.style),
39994084
container: _extends({
40004085
boxSizing: 'border-box'
4001-
}, topShadow && {
4086+
}, topShadow && !hideShadows && {
40024087
boxShadow: 'rgba(0, 0, 0, 0.156863) 0px -6px 5px'
40034088
}, swipeableViewsProps.containerStyle),
40044089
slide: _extends({
@@ -4012,16 +4097,16 @@ var SwipeableBottomSheet = (function (_Component) {
40124097
body: _extends({
40134098
overflow: isOpen ? 'auto' : 'hidden',
40144099
backgroundColor: 'white',
4015-
height: fullScreen ? this.state.height : 'initial',
4016-
maxHeight: this.state.height
4100+
height: fullScreen ? maxHeight : 'initial',
4101+
maxHeight: maxHeight
40174102
}, this.props.bodyStyle)
40184103
},
40194104
overlay: _extends({
40204105
position: 'fixed',
4021-
height: '100vh',
4022-
width: '100vw',
40234106
top: 0,
40244107
right: 0,
4108+
left: 0,
4109+
height: this.state.height,
40254110
transition: 'opacity 450ms',
40264111
pointerEvents: 'none',
40274112
backgroundColor: 'black',
@@ -4047,7 +4132,7 @@ var SwipeableBottomSheet = (function (_Component) {
40474132
{ style: styles.root },
40484133
_react2['default'].createElement(_HeightUpdater2['default'], {
40494134
height: this.state.height,
4050-
onHeightChange: this.onHeightChange.bind(this)
4135+
onHeightChange: this.onHeightChange
40514136
}),
40524137
overlay && _react2['default'].createElement('div', { style: styles.overlay, onClick: function () {
40534138
return _this.onChangeIndex(0);
@@ -4058,20 +4143,26 @@ var SwipeableBottomSheet = (function (_Component) {
40584143
index: index,
40594144
axis: 'y',
40604145
enableMouseEvents: true,
4061-
onChangeIndex: this.onChangeIndex.bind(this)
4146+
onChangeIndex: this.onChangeIndex
40624147
}, this.props.swipeableViewsProps, {
4148+
onTransitionEnd: this.onTransitionEnd,
40634149
style: styles.swiper.root,
40644150
containerStyle: styles.swiper.container,
40654151
slideStyle: styles.swiper.slide
40664152
}),
40674153
_react2['default'].createElement(
40684154
'div',
4069-
{ style: styles.swiper.body },
4155+
{ style: styles.swiper.body, ref: function (elt) {
4156+
return _this.bodyElt = elt;
4157+
} },
40704158
this.props.children
40714159
),
40724160
_react2['default'].createElement('div', { style: styles.swiper.bottomSlide })
40734161
),
4074-
shadowTip && _react2['default'].createElement('div', { style: styles.shadowTip })
4162+
shadowTip && !hideShadows && _react2['default'].createElement('div', { style: styles.shadowTip }),
4163+
!isOpen && scrollTopAtClose && !hiddenWhenClosed && _react2['default'].createElement(_ScrollToTop2['default'], { element: function () {
4164+
return _this.bodyElt;
4165+
} })
40754166
);
40764167
}
40774168
}]);
@@ -4086,11 +4177,14 @@ SwipeableBottomSheet.propTypes = {
40864177
children: _propTypes2['default'].node.isRequired,
40874178
defaultOpen: _propTypes2['default'].bool,
40884179
fullScreen: _propTypes2['default'].bool,
4180+
marginTop: _propTypes2['default'].number,
40894181
onChange: _propTypes2['default'].func,
4182+
onTransitionEnd: _propTypes2['default'].func,
40904183
open: _propTypes2['default'].bool,
40914184
overflowHeight: _propTypes2['default'].number,
40924185
overlay: _propTypes2['default'].bool,
40934186
overlayStyle: _propTypes2['default'].object,
4187+
scrollTopAtClose: _propTypes2['default'].bool,
40944188
shadowTip: _propTypes2['default'].bool,
40954189
style: _propTypes2['default'].object,
40964190
swipeableViewsProps: _propTypes2['default'].object,
@@ -4100,8 +4194,10 @@ SwipeableBottomSheet.propTypes = {
41004194
SwipeableBottomSheet.defaultProps = {
41014195
defaultOpen: false,
41024196
fullScreen: false,
4197+
marginTop: 0,
41034198
overflowHeight: 0,
41044199
overlay: true,
4200+
scrollTopAtClose: true,
41054201
shadowTip: true,
41064202
swipeableViewsProps: {},
41074203
topShadow: true
@@ -4111,5 +4207,5 @@ exports['default'] = SwipeableBottomSheet;
41114207
module.exports = exports['default'];
41124208

41134209
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
4114-
},{"./HeightUpdater":114,"prop-types":100,"react-swipeable-views":112}]},{},[115])(115)
4210+
},{"./HeightUpdater":114,"./ScrollToTop":115,"prop-types":100,"react-swipeable-views":112}]},{},[116])(116)
41154211
});

dist/react-swipeable-bottom-sheet.min.js

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example/src/controlled.html

+3-1
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ <h2><a href="https://github.com/manufont/react-swipeable-bottom-sheet">View proj
1212
<div id="app"></div>
1313
<div class="hint">
1414
This example shows a controlled Swipeable Bottom Sheet.<br/>
15+
<a href="https://github.com/manufont/react-swipeable-bottom-sheet/blob/master/example/src/controlled.js">Show me the code</a><br/><br/>
1516
<a href="index.html">See uncontrolled example</a><br/>
16-
<a href="fullscreen.html">See fullscreen example</a>
17+
<a href="fullscreen.html">See fullscreen example</a><br/>
18+
<a href="scroll.html">See scrollable example</a>
1719
</div>
1820
</div>
1921
<script src="common.js"></script>

example/src/fullscreen.html

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ <h2><a href="https://github.com/manufont/react-swipeable-bottom-sheet">View proj
1212
<div id="app"></div>
1313
<div class="hint">
1414
This example shows a fullscreen, controlled Swipeable Bottom Sheet.<br/>
15-
BottomTip is disabled and no overflow height is specified.<br/>
15+
<a href="https://github.com/manufont/react-swipeable-bottom-sheet/blob/master/example/src/fullscreen.js">Show me the code</a><br/><br/>
1616
<a href="index.html">See uncontrolled example</a><br/>
17-
<a href="controlled.html">See controlled example</a>
17+
<a href="controlled.html">See controlled example</a><br/>
18+
<a href="scroll.html">See scrollable example</a>
1819
</div>
1920
</div>
2021
<script src="common.js"></script>

example/src/fullscreen.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,9 @@ class App extends React.Component {
4242
open={this.state.open}
4343
onChange={this.openBottomSheet.bind(this)}
4444
fullScreen
45-
shadowTip={false}
46-
topShadow={false}
4745
>
4846
<div style={styles.title}>
49-
Controlled fullscreen bottom sheet
47+
Fullscreen bottom sheet
5048
</div>
5149
<div style={styles.text}>
5250
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et

example/src/index.html

+3-1
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ <h2><a href="https://github.com/manufont/react-swipeable-bottom-sheet">View proj
1313
<div class="hint">
1414
This example shows a basic, uncontrolled Swipeable Bottom Sheet.<br/>
1515
Here, the bottom sheet height scales automatically with its content.<br/>
16+
<a href="https://github.com/manufont/react-swipeable-bottom-sheet/blob/master/example/src/uncontrolled.js">Show me the code</a><br/><br/>
1617
<a href="controlled.html">See controlled example</a><br/>
17-
<a href="fullscreen.html">See fullscreen example</a>
18+
<a href="fullscreen.html">See fullscreen example</a><br/>
19+
<a href="scroll.html">See scrollable example</a>
1820
</div>
1921
</div>
2022
<script src="common.js"></script>

example/src/scroll.html

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<!doctype html>
2+
<head>
3+
<title>Swipeable Bottom Sheet</title>
4+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
5+
<link rel="stylesheet" href="example.css">
6+
</head>
7+
<body>
8+
<div class="container">
9+
<h1>Swipeable Bottom Sheet</h1>
10+
<h2><a href="https://github.com/manufont/react-swipeable-bottom-sheet">View project on GitHub</a></h2>
11+
<!-- the example app is rendered into this div -->
12+
<div id="app"></div>
13+
<div class="hint">
14+
This example shows how large content overflows the bottom sheet. Here, a margin is applied to the top of the sheet using <i>marginTop</i> prop.<br/>
15+
<a href="https://github.com/manufont/react-swipeable-bottom-sheet/blob/master/example/src/scroll.js">Show me the code</a><br/><br/>
16+
<a href="index.html">See uncontrolled example</a><br/>
17+
<a href="controlled.html">See controlled example</a><br/>
18+
<a href="fullscreen.html">See fullscreen example</a>
19+
</div>
20+
</div>
21+
<script src="common.js"></script>
22+
<script src="bundle.js"></script>
23+
<script src="scroll.js"></script>
24+
</body>

0 commit comments

Comments
 (0)