-
Notifications
You must be signed in to change notification settings - Fork 3
/
index.tsx
299 lines (286 loc) · 11.7 KB
/
index.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
import * as React from 'react'
import {View, Text, TouchableOpacity} from 'react-native'
import {Animate} from 'react-move'
import {easeQuadIn} from 'd3-ease'
import {interpolate} from 'd3-interpolate'
export type IProps = {
animationDuration?: number
borderColor?: string
borderWidth?: number
buttonColor?: string
buttonSize?: number
buttonOffsetLeft?: number
buttonOffsetRight?: number
colorSwitchOff?: string
colorSwitchOn?: string
colorTextOff?: string
colorTextOn?: string
disabled?: boolean
easingFunction?: () => void
icon?: any
onChange: () => void
paddingTextOff?: number
paddingTextOn?: number
shape: string
showText?: boolean
sliderHeight?: number
sliderWidth?: number
spaceBetween?: number
testID?: string
textFont?: string
textOff?: string
textOn?: string
textSize?: number
value: boolean
}
enum Shapes {
pill = 'pill',
line = 'line'
}
export type IState = {}
const defaultBorderColor = '#D3D5DA'
const defaultBorderWidth = 1
const defaultButtonOffsetLine = 0
const defaultButtonOffsetPill = 2
const defaultButtonSizeLine = 20
const defaultButtonSizePill = 32
const defaultButtonColorLine = '#96CBCE'
const defaultButtonColorPill = '#FFF'
const defaultColorSwitch = '#E8EAEC'
const defaultColorSwitchOff = '#D3D5DA'
const defaultColorSwitchOn = '#96CBCE'
const defaultColorTextOffLine = '#E8EAEC'
const defaultColorTextOnLine = '#7BCDD0'
const defaultColorTextOffPill = '#445878'
const defaultColorTextOnPill = '#FFF'
const defaultDisabledValue = false
const defaultDuration = 300
const defaultEasingFunction = easeQuadIn
const defaultPaddingTextOff = 0
const defaultPaddingTextOn = 0
const defaultShowText = true
const defaultSpaceBetweenLine = 10
const defaultSpaceBetweenPill = 10
const defaultSwitchHeightLine = 6
const defaultSwitchHeightPill = 36
const defaultSwitchWidthLine = 30
const defaultSwitchWidthPill = 70
const defaultTestID = 'reactNativeSwitches'
const defaultTextFont = 'courier'
const defaultTextOffLine = 'No'
const defaultTextOnLine = 'Yes'
const defaultTextOffPill = 'off'
const defaultTextOnPill = 'on'
const defaultTextSize = 14
class Switches extends React.PureComponent<IProps, IState> {
constructor(props: IProps) {
super(props)
this.handleSwitch = this.handleSwitch.bind(this)
}
handleSwitch = () => {
this.props.onChange()
}
renderLineSwitch = () => {
const buttonOffsetLeft = this.props.buttonOffsetLeft || defaultButtonOffsetLine
const buttonOffsetRight = this.props.buttonOffsetRight || defaultButtonOffsetLine
const easingFunction = this.props.easingFunction || defaultEasingFunction
const buttonSize = this.props.buttonSize || defaultButtonSizeLine
const duration = this.props.animationDuration || defaultDuration
const colorTextOn = this.props.colorTextOn || defaultColorTextOnLine
const disabled = this.props.disabled || defaultDisabledValue
const colorTextOff = this.props.colorTextOff || defaultColorTextOffLine
const textFont = this.props.textFont || defaultTextFont
const textOn = this.props.textOn || defaultTextOnLine
const textOff = this.props.textOff || defaultTextOffLine
const sliderHeight = this.props.sliderHeight || defaultSwitchHeightLine
const sliderWidth = this.props.sliderWidth || defaultSwitchWidthLine
const spaceBetween = this.props.spaceBetween || defaultSpaceBetweenLine
const buttonColor = this.props.buttonColor || defaultButtonColorLine
const colorSwitchOn = this.props.colorSwitchOn || defaultColorSwitch
const colorSwitchOff = this.props.colorSwitchOff || defaultColorSwitch
const showText = this.props.showText === false ? this.props.showText : defaultShowText
const borderWidth = this.props.borderWidth ? this.props.borderWidth : defaultBorderWidth
const borderColor = this.props.borderColor ? this.props.borderColor : defaultBorderColor
return (
<Animate
show={true}
start={{
colorNo: this.props.value ? colorTextOff : colorTextOn,
colorYes: this.props.value ? colorTextOn : colorTextOff,
positionButton: this.props.value ? sliderWidth - buttonOffsetRight - buttonSize / 2 : buttonOffsetLeft,
opacityChildren: this.props.value ? 1 : 0
}}
update={{
colorNo: [this.props.value ? colorTextOff : colorTextOn],
colorYes: [this.props.value ? colorTextOn : colorTextOff],
positionButton: [this.props.value ? sliderWidth - buttonOffsetRight - buttonSize / 2 : buttonOffsetLeft],
opacityChildren: this.props.value ? [1] : [0],
timing: {duration: duration, ease: easingFunction}
}}
interpolation={(begValue, endValue, attr) => interpolate(begValue, endValue)}>
{(state: any) => (
<View>
<View style={{alignItems: 'center', flexDirection: 'row'}}>
{showText && <Text style={{fontFamily: textFont, color: state.colorNo, marginRight: spaceBetween / 2}}>
{textOff}
</Text>}
<View style={{paddingRight: spaceBetween / 2, paddingLeft: spaceBetween / 2}}>
<View style={{
height: sliderHeight,
width: sliderWidth,
backgroundColor: this.props.value ? colorSwitchOn : colorSwitchOff,
borderRadius: sliderHeight / 2
}}/>
<TouchableOpacity activeOpacity={1} disabled={disabled}
style={{
left: state.positionButton,
position: 'absolute',
top: (sliderHeight - buttonSize) / 2,
width: buttonSize,
height: buttonSize,
borderRadius: buttonSize / 2,
backgroundColor: buttonColor,
borderWidth: borderWidth,
borderColor: borderColor
}} onPress={() => this.handleSwitch()}/>
</View>
{showText && <Text style={{fontFamily: textFont, color: state.colorYes, marginLeft: spaceBetween / 2}}>
{textOn}
</Text>}
</View>
<View style={{opacity: state.opacityChildren}}>
{this.props.children}
</View>
</View>
)}
</Animate>
)
}
renderPillSwitch = () => {
const buttonOffSetRight = this.props.buttonOffsetRight || defaultButtonOffsetPill
const buttonSize = this.props.buttonSize || defaultButtonSizePill
const leftPosition = this.props.buttonOffsetLeft || defaultButtonOffsetPill
const offColor = this.props.colorSwitchOff || defaultColorSwitchOff
const onColor = this.props.colorSwitchOn || defaultColorSwitchOn
const sliderHeight = this.props.sliderHeight || defaultSwitchHeightPill
const sliderWidth = this.props.sliderWidth || defaultSwitchWidthPill
const rightPosition = sliderWidth - buttonSize - buttonOffSetRight
const duration = this.props.animationDuration || defaultDuration
const disabled = this.props.disabled || defaultDisabledValue
const easingFunction = this.props.easingFunction || defaultEasingFunction
const textFont = this.props.textFont || defaultTextFont
const textSize = this.props.textSize || defaultTextSize
const colorTextOn = this.props.colorTextOn || defaultColorTextOnPill
const colorTextOff = this.props.colorTextOff || defaultColorTextOffPill
const textOn = this.props.textOn || defaultTextOnPill
const textOff = this.props.textOff || defaultTextOffPill
const spaceBetween = this.props.spaceBetween || defaultSpaceBetweenPill
const buttonColor = this.props.buttonColor || defaultButtonColorPill
const showText = this.props.showText === false ? this.props.showText : defaultShowText
const borderWidth = this.props.borderWidth ? this.props.borderWidth : defaultBorderWidth
const borderColor = this.props.borderColor ? this.props.borderColor : defaultBorderColor
const icon = this.props.icon ? this.props.icon : null
const paddingTextOn = this.props.paddingTextOn || defaultPaddingTextOn
const paddingTextOff = this.props.paddingTextOff || defaultPaddingTextOff
return (<Animate
show={true}
start={{
color: `${this.props.value ? onColor : offColor}`,
positionButton: this.props.value ? rightPosition : leftPosition,
opacityChildren: this.props.value ? 1 : 0,
opacityTextOn: this.props.value ? 1 : 0,
opacityTextOff: this.props.value ? 0 : 1
}}
update={{
color: [`${this.props.value ? onColor : offColor}`],
positionButton: [this.props.value ? rightPosition : leftPosition],
opacityChildren: [this.props.value ? 1 : 0],
opacityTextOn: [this.props.value ? 1 : 0],
opacityTextOff: [this.props.value ? 0 : 1],
timing: {duration: duration, ease: easingFunction}
}}
interpolation={(begValue, endValue, attr) => interpolate(begValue, endValue)}>
{(state: any) => (
<View>
<View>
<TouchableOpacity activeOpacity={1} onPress={() => this.handleSwitch()} disabled={disabled}
style={{
backgroundColor: state.color,
height: sliderHeight,
width: sliderWidth,
borderRadius: sliderHeight / 2,
justifyContent: 'center',
alignItems: 'center',
borderWidth: borderWidth,
borderColor: borderColor
}}>
{showText &&
<View style={{
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
paddingLeft: paddingTextOn,
paddingRight: paddingTextOff
}}>
<Text
style={{
fontFamily: textFont,
fontSize: textSize,
color: colorTextOn,
marginRight: spaceBetween / 2,
opacity: state.opacityTextOn
}}>
{textOn}
</Text>
<Text
style={{
fontFamily: textFont,
fontSize: textSize,
color: colorTextOff,
marginLeft: spaceBetween / 2,
opacity: state.opacityTextOff
}}>
{textOff}
</Text>
</View>}
<View style={{
left: state.positionButton,
position: 'absolute',
backgroundColor: buttonColor,
width: buttonSize,
height: buttonSize,
borderRadius: buttonSize / 2,
alignItems: 'center',
justifyContent: 'center'
}}>
{icon}
</View>
</TouchableOpacity>
</View>
<View style={{opacity: state.opacityChildren}}>
{this.props.children}
</View>
</View>
)}
</Animate>)
}
renderSwitches = () => {
switch (this.props.shape) {
case Shapes.line.toString():
return this.renderLineSwitch()
case Shapes.pill.toString():
return this.renderPillSwitch()
default:
return null
}
}
render() {
const testID = this.props.testID || defaultTestID
return (
<View testID={testID}>
{this.renderSwitches()}
</View>
)
}
}
export default Switches