Skip to content

Commit fd3aa5b

Browse files
committed
feat: add spacing and rtl props
1 parent 0567c8b commit fd3aa5b

File tree

4 files changed

+86
-8
lines changed

4 files changed

+86
-8
lines changed

README.md

+25
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,31 @@ only render the active view.
6969
The index of the view that should be showing. Whenever you change this, `ViewSlider` will animate a horizontal slide
7070
transition to the view at the new index.
7171

72+
##### `spacing: number` (default: `1`)
73+
74+
How much horizontal space to put between the views. `spacing={1.5}` will space
75+
the views apart by 50% of the width, `spacing={2}` will space the views apart
76+
by 100% of the width, etc.
77+
78+
Views without much horizontal padding or margin of their own will look jammed
79+
together during transitions with a default `spacing` of 1, so in that case
80+
you'll want to increase the `spacing`.
81+
82+
A negative number will reverse the view order;
83+
`spacing={-1.5}` will arrange views from right to left with 50% width view
84+
spacing. You can also use the `rtl` property for this, especially if you want
85+
the views to inherit `direction: rtl` for their own content layout.
86+
87+
##### `rtl: boolean` (default: false)
88+
89+
Whether to use right-to-left layout. This will reverse the view order and apply
90+
`direction: rtl` to the viewport style, and each view will inherit that layout
91+
direction for its own content as well.
92+
93+
To reverse the view order without
94+
changing layout direction of each view's content, you can use a negative number
95+
for `spacing`.
96+
7297
##### `keepViewsMounted: boolean` (default: `false`)
7398

7499
If `true`, `ViewSlider` will keep all views mounted after transitioning, not just the active view.

demo/examples/#Demo.js

+37-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
import * as React from 'react'
7+
import Link from '@material-ui/core/Link'
78
import Button from '@material-ui/core/Button'
89
import TextField from '@material-ui/core/TextField'
910
import Typography from '@material-ui/core/Typography'
@@ -81,7 +82,9 @@ const #Demo = ({ classes }: Props): React.Node => {
8182
</Button>
8283
<div className={classes.contentHolder}>
8384
<Paper className={classes.paper}>
84-
<ViewSlider animateHeight>{content}</ViewSlider>
85+
<ViewSlider animateHeight spacing={1.2}>
86+
{content}
87+
</ViewSlider>
8588
</Paper>
8689
</div>
8790
</div>
@@ -194,7 +197,39 @@ const PasswordForm = ({ classes, onSubmit }: FormProps): React.Node => {
194197
const DoneForm = ({ classes, onSubmit }: FormProps): React.Node => (
195198
<div className={classes.form}>
196199
<Typography variant="h5" className={classes.h5}>
197-
<em>End of Demo</em>
200+
<em>Thank you</em> for viewing the demo!
201+
</Typography>
202+
<Typography variant="h6">Additional libraries to check out:</Typography>
203+
<Typography variant="h5">
204+
<Link href="https://github.com/jcoreio/react-router-drilldown">
205+
<code>react-router-drilldown</code>
206+
</Link>
207+
</Typography>
208+
<Typography variant="body1" component="p">
209+
uses <code>react-view-slider</code> to animate transitions between routes
210+
in <code>react-router</code>.
211+
</Typography>
212+
<Typography variant="h5">
213+
<Link href="https://github.com/jcoreio/react-fader">
214+
<code>react-fader</code>
215+
</Link>
216+
</Typography>
217+
<Typography variant="body1" component="p">
218+
component that fades out its old child, then fades in its new child when
219+
its children change. It can also optionally animate its height and/or
220+
width from one child{"'"}s size to the other. Also works well with{' '}
221+
<code>react-router</code>!
222+
</Typography>
223+
<Typography variant="h5">
224+
<Link href="https://github.com/jcoreio/react-transition-context">
225+
<code>react-transition-context</code>
226+
</Link>
227+
</Typography>
228+
<Typography variant="body1" component="p">
229+
Allows you to perform effects when transitions in an ancestor component
230+
start or end (used to automatically focus the inputs in this demo). Also
231+
works with <code>react-router-drilldown</code> and{' '}
232+
<code>react-fader</code>!
198233
</Typography>
199234
</div>
200235
)

src/index.js

+17-4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export type DefaultProps = {
2121
prefixer: Prefixer,
2222
style: Object,
2323
viewportStyle: Object,
24+
rtl: boolean,
25+
spacing: number,
2426
}
2527

2628
export type Props = {
@@ -39,6 +41,8 @@ export type Props = {
3941
viewportStyle: Object,
4042
rootRef?: (node: ?React.ElementRef<'div'>) => mixed,
4143
viewportRef?: (node: ?React.ElementRef<'div'>) => mixed,
44+
rtl: boolean,
45+
spacing: number,
4246
}
4347

4448
export type State = {
@@ -57,7 +61,6 @@ const fillStyle = {
5761
}
5862

5963
const viewStyle = {
60-
position: 'relative',
6164
display: 'inline-block',
6265
verticalAlign: 'top',
6366
whiteSpace: 'normal',
@@ -73,6 +76,8 @@ export default class ViewSlider extends React.Component<Props, State> {
7376
prefixer: new Prefixer(),
7477
style: {},
7578
viewportStyle: {},
79+
rtl: false,
80+
spacing: 1,
7681
}
7782
state: State = {
7883
height: undefined,
@@ -167,14 +172,18 @@ export default class ViewSlider extends React.Component<Props, State> {
167172
}
168173

169174
renderView = (index: number): React.Node => {
170-
const { fillParent, prefixer, keepViewsMounted } = this.props
175+
const { fillParent, prefixer, keepViewsMounted, spacing, rtl } = this.props
171176
const { activeView, transitioning } = this.state
172177

173178
const style: Object = { display: 'flex', ...viewStyle }
174179
if (fillParent) {
175180
Object.assign(style, fillStyle)
176181
style.overflow = 'auto'
177-
style.left = `${index * 100}%`
182+
if (rtl) style.right = `${index * spacing * 100}%`
183+
else style.left = `${index * spacing * 100}%`
184+
} else if (index > 0) {
185+
if (rtl) style.marginRight = `${(spacing - 1) * 100}%`
186+
else style.marginLeft = `${(spacing - 1) * 100}%`
178187
}
179188

180189
// when not transitioning, render empty placeholder divs before the active view to push it into the right
@@ -229,6 +238,8 @@ export default class ViewSlider extends React.Component<Props, State> {
229238
transitionDuration,
230239
transitionTimingFunction,
231240
keepViewsMounted,
241+
rtl,
242+
spacing,
232243
} = this.props
233244
const animateHeight = this.animateHeight()
234245
const { activeView, height, transitioning } = this.state
@@ -243,9 +254,11 @@ export default class ViewSlider extends React.Component<Props, State> {
243254
}
244255

245256
const finalViewportStyle = {
246-
transform: `translateX(-${activeView * 100}%)`,
257+
position: 'relative',
258+
transform: `translateX(${activeView * spacing * (rtl ? 100 : -100)}%)`,
247259
whiteSpace: 'nowrap',
248260
minHeight: '100%',
261+
direction: rtl ? 'rtl' : 'ltr',
249262
transition: transitioning
250263
? `transform ${transitionTimingFunction} ${transitionDuration}ms`
251264
: undefined,

src/simple.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import * as React from 'react'
55
import Prefixer from 'inline-style-prefixer'
66
import ViewSlider from './index'
7-
87
import type { Props as ViewSliderProps, ViewProps } from './index'
98

109
export type Props = {
@@ -21,6 +20,8 @@ export type Props = {
2120
viewportStyle?: Object,
2221
rootRef?: (node: ?React.ElementRef<'div'>) => mixed,
2322
viewportRef?: (node: ?React.ElementRef<'div'>) => mixed,
23+
rtl?: ?boolean,
24+
spacing?: ?number,
2425
}
2526

2627
export type State = {
@@ -37,7 +38,6 @@ export function createSimpleViewSlider(
3738
renderView: (props: ViewProps) => React.Node = defaultRenderView
3839
): Class<React.Component<Props, State>> {
3940
return class SimpleViewSlider extends React.Component<Props, State> {
40-
static defaultProps: Props
4141
state: State
4242

4343
constructor(props: Props) {
@@ -70,12 +70,17 @@ export function createSimpleViewSlider(
7070
render(): React.Node {
7171
const {
7272
children, // eslint-disable-line no-unused-vars
73+
// Flow's React.ComponentType + defaultProps is foobar...
74+
spacing,
75+
rtl,
7376
...props
7477
} = this.props
7578
const { activeView, views } = this.state
7679
return (
7780
<ViewSlider
7881
{...props}
82+
spacing={(spacing: any)}
83+
rtl={(rtl: any)}
7984
renderView={this.renderView}
8085
numViews={views.length}
8186
activeView={activeView}

0 commit comments

Comments
 (0)