Skip to content
This repository was archived by the owner on Nov 1, 2018. It is now read-only.

Commit 4067e32

Browse files
committed
✨ Added swipe actions to the transition pages component
1 parent 6dc4cd9 commit 4067e32

File tree

9 files changed

+167
-33
lines changed

9 files changed

+167
-33
lines changed

packages/Sidenav/src/overlay.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ import styled, { lightTheme } from '@slup/theming'
33
export const Drawer = styled.div`
44
z-index: 1000;
55
overflow-y: auto;
6-
transition: max-width 150ms linear, transform 320ms cubic-bezier(0.4, 0.0, 0.2, 1);
6+
transition: max-width 150ms linear,
7+
transform 320ms ${props => props.opened
8+
? 'cubic-bezier(0.0, 0.0, 0.2, 1)'
9+
: 'cubic-bezier(0.4, 0.0, 0.6, 1)'
10+
};
711
height: 100%;
812
width: calc(100% - 64px);
913
max-width: 320px;

packages/Site/src/components/demo.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,6 @@ export class Demo extends Component<{ module: string }, IState> {
158158
.replace(']', '')
159159
.replace(',', '')
160160
.replace('/', '')
161-
.replace('--', '')
162161

163162
/**
164163
* Load the README and parse its contents

packages/Site/src/components/icons.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const Path = styled.path`
1515
stroke-width: 40;
1616
stroke-dasharray: 10000;
1717
stroke-dashoffset: 10000;
18-
animation: ${DASH} 5s linear forwards;
18+
animation: ${DASH} 6s linear forwards;
1919
`
2020

2121
const Line = Path.withComponent('line')

packages/Tabs/README.md

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ npm install --save @slup/tabs
1616

1717
## Usage
1818
```js
19-
import { Tabs, Tab } from '@slup/tabs'
19+
import { Tabs, Tab, TransitionPages, Page } from '@slup/tabs'
2020

2121
export class Test extends Component {
2222
tabs = [
@@ -27,24 +27,34 @@ export class Test extends Component {
2727

2828
state = { selected: 0 }
2929

30-
handleClick(i) {
30+
handleSelectionChange(i) {
3131
this.setState({ selected: i })
3232
}
3333

3434
render() {
3535
return (
36-
<Tabs selected={this.state.selected}>
37-
{this.tabs.map((item, i) => {
38-
return (
39-
<Tab
40-
onClick={() => this.handleClick(i)}
41-
selected={this.state.selected === i}
42-
>
43-
{item}
44-
</Tab>
45-
)
46-
})}
47-
</Tabs>
36+
<div style={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
37+
<Tabs selected={this.state.selected}>
38+
{this.tabs.map((item, i) => {
39+
return (
40+
<Tab
41+
onClick={() => this.handleSelectionChange(i)}
42+
selected={this.state.selected === i}
43+
>
44+
{item}
45+
</Tab>
46+
)
47+
})}
48+
</Tabs>
49+
<TransitionPages
50+
onSwipe={this.handleSelectionChange.bind(this)}
51+
selected={this.state.selected}
52+
>
53+
<Page>1</Page>
54+
<Page>2</Page>
55+
<Page>3</Page>
56+
</TransitionPages>
57+
</div>
4858
)
4959
}
5060
}

packages/Tabs/src/container.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export class Tabs extends Component<IProps, IState> {
6666
* from the props as a fallback
6767
*
6868
* We check if the value is NOT a number, becuase
69-
* 0 is still an acceptable number but would be fals
69+
* 0 is still an acceptable number but would be false
7070
* in an ipothetical if statement
7171
*/
7272
const selected = !newProps
@@ -94,16 +94,16 @@ export class Tabs extends Component<IProps, IState> {
9494
self.scroll.scrollLeft += 1
9595

9696
if(count == 100) clearInterval(id)
97-
}, 0.05)
97+
}, 0.03)
9898
break
9999

100100
case 'left':
101101
id = setInterval(() => {
102102
count++
103103
self.scroll.scrollLeft -= 1
104104

105-
if (count == 100) clearInterval(id)
106-
}, 0.05)
105+
if(count == 100) clearInterval(id)
106+
}, 0.03)
107107
break
108108
}
109109
}
@@ -155,7 +155,8 @@ export class Tabs extends Component<IProps, IState> {
155155
children={[
156156
...children,
157157
<Indicator
158-
{...props}
158+
secondaryIndicator={secondaryIndicator}
159+
scrollable={scrollable}
159160
translate={translate}
160161
style={style}
161162
/>

packages/Tabs/src/indicator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import styled, { lightTheme } from '@slup/theming'
22

33
export const Indicator = styled.div`
44
position: absolute;
5-
transition: width 150ms, left 150ms;
5+
transition: width 200ms, left 200ms;
66
height: 2px;
77
bottom: ${props => props.translate && props.scrollable ? 14 : 0}px;
88
background: ${props => props.secondaryIndicator

packages/Tabs/src/scroll.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import styled, { lightTheme, darken } from '@slup/theming'
22

33
export const Scroll = styled.div`
44
position: absolute;
5+
height: 100%;
6+
width: 100%;
57
display: flex;
68
align-items: center;
79
overflow-x: ${props => props.center ? 'hidden' : 'auto'};
@@ -12,7 +14,6 @@ export const Scroll = styled.div`
1214
transform: ${props => props.translate && props.scrollable
1315
? 'translateY(16px)'
1416
: null};
15-
width: ${props => props.scrollable ? '100%' : 'auto'};
1617
left: ${props => props.scrollable ? '80px' : 'auto'};
1718
right: ${props => props.scrollable ? '80px' : 'auto'};
1819
background: ${props => props.primary
@@ -22,7 +23,7 @@ export const Scroll = styled.div`
2223
2324
div:not(:last-child) {
2425
width: ${props => props.fit
25-
? `calc(100vw / ${props.childCount})`
26+
? `calc(100% / ${props.childCount})`
2627
: 'auto'
2728
};
2829
}

packages/Tabs/src/tab.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import styled, { lightTheme, rgba } from '@slup/theming'
55

66
const Item = styled.div`
77
-webkit-tap-highlight-color: transparent;
8+
text-align: center;
89
box-sizing: border-box;
910
min-height: 48px;
1011
max-height: 72px;
Lines changed: 126 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,142 @@
1-
import styled, { lightTheme } from '@slup/theming'
1+
import Inferno, { linkEvent } from 'inferno'
2+
import Component from 'inferno-component'
3+
import styled from '@slup/theming'
24

35
const Scroll = styled.div`
46
overflow-x: hidden;
7+
height: 100%;
58
`
69

710
export const Pages = styled.div`
811
height: 100%;
912
width: auto;
1013
display: flex;
11-
transition: transform 300ms cubic-bezier(0.4, 0.0, 0.2, 1);
12-
transform: ${props => `translateX(-${props.selected * 100}%)`}
14+
transition: transform 200ms ${props => !props.touched
15+
? 'cubic-bezier(0.4, 0.0, 0.2, 1)'
16+
: 'none'
17+
};
1318
`
1419

1520
export const Page = styled.div`
1621
flex-shrink: 0;
17-
height: 100%;
1822
width: 100%;
1923
`
2024

21-
export const TransitionPages = props =>
22-
<Scroll>
23-
<Pages {...props} />
24-
</Scroll>
25+
interface IProps {
26+
selected: number
27+
onSwipe: (index: number) => void
28+
}
29+
30+
interface IState {
31+
touched: boolean
32+
startX: number
33+
translate: number
34+
}
35+
36+
export class TransitionPages extends Component<IProps, IState> {
37+
private container: HTMLDivElement
38+
39+
public state: IState = {
40+
touched: false,
41+
startX: 0,
42+
translate: 0
43+
}
44+
45+
public componentWillReceiveProps(nextProps: IProps) {
46+
const stateSelection = Math.round(this.state.translate / 100)
47+
const DID_PROP_CHANGE = this.props.selected !== nextProps.selected
48+
49+
if(nextProps.selected !== stateSelection && DID_PROP_CHANGE) {
50+
this.setState({ translate: nextProps.selected * 100 })
51+
this.emitSwipe(nextProps.selected)
52+
}
53+
}
54+
55+
/**
56+
* Emit the new selected index to a possible onSwipe listener
57+
*
58+
* @param index the new index
59+
*/
60+
private emitSwipe(index: number) {
61+
if(this.props.onSwipe && typeof this.props.onSwipe == 'function') {
62+
this.props.onSwipe(index)
63+
}
64+
}
65+
66+
/**
67+
* Saves the latest touch on the x axis
68+
*
69+
* @param self The local class
70+
* @param event The data from the fired event
71+
*/
72+
private handleTouchStart(self, { targetTouches }) {
73+
const { translate } = self.state
74+
const { clientX } = targetTouches[0]
75+
const { clientWidth } = self.container
76+
77+
const increment = (translate * clientWidth) / 100
78+
79+
self.setState({
80+
touched: true,
81+
startX: clientX + increment
82+
})
83+
}
84+
85+
/**
86+
* Creates a percentage to move the container
87+
* using the current touch and the saved one
88+
* on the x axis
89+
*
90+
* @param self The local class
91+
* @param event The data from the fired event
92+
*/
93+
private handleTouchMove(self, { targetTouches }) {
94+
const { startX } = self.state
95+
const { clientX } = targetTouches[0]
96+
const { clientWidth } = self.container
97+
const childrenCount = self.container.children[0].children.length
98+
99+
let percentage = ((startX - clientX) / clientWidth) * 100
100+
101+
if (percentage < 0)
102+
percentage = 0
103+
else if (percentage > ((childrenCount - 1) * 100))
104+
percentage = (childrenCount - 1) * 100
105+
106+
self.setState({ translate: percentage })
107+
}
108+
109+
/**
110+
* Rounds the percentage
111+
*
112+
* @param self The local class
113+
*/
114+
private handleTouchEnd(self) {
115+
self.setState({
116+
touched: false,
117+
translate: Math.round(self.state.translate / 100) * 100
118+
})
119+
120+
self.emitSwipe(Math.round(self.state.translate / 100))
121+
}
122+
123+
public render(props, { translate, touched }) {
124+
return(
125+
<Scroll
126+
{...props}
127+
innerRef={e => this.container = e}
128+
onTouchStart={linkEvent(this, this.handleTouchStart)}
129+
onTouchMove={linkEvent(this, this.handleTouchMove)}
130+
onTouchEnd={linkEvent(this, this.handleTouchEnd)}
131+
>
132+
<Pages
133+
selected={props.selected}
134+
touched={touched}
135+
style={`transform: translateX(-${translate}%)`}
136+
>
137+
{props.children}
138+
</Pages>
139+
</Scroll>
140+
)
141+
}
142+
}

0 commit comments

Comments
 (0)