@shoutem/ui 6.4.3 → 6.5.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { Animated } from 'react-native';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import { connectStyle } from '@shoutem/theme';
|
|
5
|
+
import { ScrollView } from './ScrollView';
|
|
6
|
+
import { Text } from './Text';
|
|
7
|
+
|
|
8
|
+
const DEFAULT_CONFIG = {
|
|
9
|
+
animationDuration: widthDiff => Math.max(widthDiff * 50, 2000),
|
|
10
|
+
waitDuration: 2000,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const AnimatedScrollingText = ({ text, config, style }) => {
|
|
14
|
+
const translateX = useRef(new Animated.Value(0)).current;
|
|
15
|
+
|
|
16
|
+
const [containerWidth, setContainerWidth] = useState();
|
|
17
|
+
const [textWidth, setTextWidth] = useState();
|
|
18
|
+
|
|
19
|
+
const widthDiff = textWidth - containerWidth;
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
let animation;
|
|
23
|
+
|
|
24
|
+
if (widthDiff > 0) {
|
|
25
|
+
animation = Animated.loop(
|
|
26
|
+
Animated.sequence([
|
|
27
|
+
// Animate scroll to the end of the text
|
|
28
|
+
Animated.timing(translateX, {
|
|
29
|
+
toValue: -widthDiff,
|
|
30
|
+
duration: config.animationDuration(widthDiff),
|
|
31
|
+
useNativeDriver: true,
|
|
32
|
+
}),
|
|
33
|
+
// Animate scroll back to start of the text
|
|
34
|
+
Animated.timing(translateX, {
|
|
35
|
+
toValue: 0,
|
|
36
|
+
duration: config.animationDuration(widthDiff),
|
|
37
|
+
useNativeDriver: true,
|
|
38
|
+
}),
|
|
39
|
+
// Wait X sec before starting animation again
|
|
40
|
+
Animated.timing(translateX, {
|
|
41
|
+
toValue: 0,
|
|
42
|
+
duration: config.waitDuration,
|
|
43
|
+
useNativeDriver: true,
|
|
44
|
+
}),
|
|
45
|
+
]),
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
animation.start();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return () => animation?.stop();
|
|
52
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
53
|
+
}, [widthDiff]);
|
|
54
|
+
|
|
55
|
+
const handleContainerLayout = e => {
|
|
56
|
+
setContainerWidth(e.nativeEvent.layout.width);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const handleTextLayout = e => {
|
|
60
|
+
setTextWidth(e.nativeEvent.layout.width);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<ScrollView
|
|
65
|
+
onLayout={handleContainerLayout}
|
|
66
|
+
horizontal
|
|
67
|
+
showsHorizontalScrollIndicator={false}
|
|
68
|
+
style={style.scrollContainer}
|
|
69
|
+
contentContainerStyle={style.scrollContentContainer}
|
|
70
|
+
>
|
|
71
|
+
<Animated.View
|
|
72
|
+
style={[
|
|
73
|
+
style.textContainer,
|
|
74
|
+
widthDiff > 0 ? { transform: [{ translateX }] } : {},
|
|
75
|
+
]}
|
|
76
|
+
>
|
|
77
|
+
<Text onLayout={handleTextLayout} style={style.text}>
|
|
78
|
+
{text}
|
|
79
|
+
</Text>
|
|
80
|
+
</Animated.View>
|
|
81
|
+
</ScrollView>
|
|
82
|
+
);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
AnimatedScrollingText.propTypes = {
|
|
86
|
+
text: PropTypes.string.isRequired,
|
|
87
|
+
config: PropTypes.object,
|
|
88
|
+
style: PropTypes.object,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
AnimatedScrollingText.defaultProps = {
|
|
92
|
+
config: DEFAULT_CONFIG,
|
|
93
|
+
style: {},
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const StyledAnimatedScrollingText = connectStyle(
|
|
97
|
+
'shoutem.ui.AnimatedScrollingText',
|
|
98
|
+
)(AnimatedScrollingText);
|
|
99
|
+
export { StyledAnimatedScrollingText as AnimatedScrollingText };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import Svg, { Path } from 'react-native-svg';
|
|
4
|
+
import PropTypes from 'prop-types';
|
|
5
|
+
import { connectStyle } from '@shoutem/theme';
|
|
6
|
+
|
|
7
|
+
const SkipTrackIcon = ({ style }) => {
|
|
8
|
+
const { container, icon = {} } = style;
|
|
9
|
+
|
|
10
|
+
const {
|
|
11
|
+
size = 0,
|
|
12
|
+
color,
|
|
13
|
+
strokeWidth = 0,
|
|
14
|
+
triangleHeight = 0,
|
|
15
|
+
triangleWidth = 0,
|
|
16
|
+
} = icon;
|
|
17
|
+
|
|
18
|
+
const halfTriangleHeight = triangleHeight / 2;
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<View style={container}>
|
|
22
|
+
<Svg width={size} height={size} viewBox="0 0 24 24">
|
|
23
|
+
<Path
|
|
24
|
+
d={`M0 ${12 -
|
|
25
|
+
halfTriangleHeight} l${triangleWidth} ${halfTriangleHeight} l-${triangleWidth} ${halfTriangleHeight} Z`}
|
|
26
|
+
fill={color}
|
|
27
|
+
/>
|
|
28
|
+
<Path
|
|
29
|
+
d={`M${triangleWidth} ${12 - halfTriangleHeight} v${triangleHeight}`}
|
|
30
|
+
stroke={color}
|
|
31
|
+
strokeWidth={strokeWidth}
|
|
32
|
+
/>
|
|
33
|
+
</Svg>
|
|
34
|
+
</View>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
SkipTrackIcon.propTypes = {
|
|
39
|
+
style: PropTypes.object,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
SkipTrackIcon.defaultProps = {
|
|
43
|
+
style: {},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const StyledSkipTrackIcon = connectStyle('shoutem.ui.SkipTrackIcon')(
|
|
47
|
+
SkipTrackIcon,
|
|
48
|
+
);
|
|
49
|
+
export { StyledSkipTrackIcon as SkipTrackIcon };
|
|
@@ -9,7 +9,7 @@ New component used for multiple types of alerts, or simple action prompts. The c
|
|
|
9
9
|
Most of the time, you will want to use one of the four standard methods of showing a toast using this package.
|
|
10
10
|
|
|
11
11
|
- Toast.showInfo
|
|
12
|
-
- Toast.
|
|
12
|
+
- Toast.showAction
|
|
13
13
|
- Toast.showError
|
|
14
14
|
- Toast.showSuccess
|
|
15
15
|
|
|
@@ -33,7 +33,7 @@ Toast.showInfo({
|
|
|
33
33
|
```jsx
|
|
34
34
|
import { Toast } from '@shoutem/ui';
|
|
35
35
|
...
|
|
36
|
-
Toast.
|
|
36
|
+
Toast.showAction({
|
|
37
37
|
title: 'Stop',
|
|
38
38
|
message: `Hammer time`,
|
|
39
39
|
iconSource: require('../assets/actionIcon.png'),
|
package/index.js
CHANGED
|
@@ -25,6 +25,7 @@ export {
|
|
|
25
25
|
|
|
26
26
|
// Components
|
|
27
27
|
export { ActionSheet } from './components/ActionSheet';
|
|
28
|
+
export { AnimatedScrollingText } from './components/AnimatedScrollingText';
|
|
28
29
|
export { Button } from './components/Button';
|
|
29
30
|
export { Card } from './components/Card';
|
|
30
31
|
export { CategoryPicker } from './components/CategoryPicker';
|
|
@@ -60,6 +61,7 @@ export { ScrollView } from './components/ScrollView';
|
|
|
60
61
|
export { SearchField } from './components/SearchField';
|
|
61
62
|
export { ShareButton } from './components/ShareButton';
|
|
62
63
|
export { Spinner } from './components/Spinner';
|
|
64
|
+
export { SkipTrackIcon } from './components/SvgIcons/SkipTrackIcon';
|
|
63
65
|
export { Switch } from './components/Switch';
|
|
64
66
|
export { TabMenu } from './components/TabMenu';
|
|
65
67
|
export { Caption, Heading, Subtitle, Text, Title } from './components/Text';
|
package/package.json
CHANGED
package/theme.js
CHANGED
|
@@ -3225,5 +3225,29 @@ export default () => {
|
|
|
3225
3225
|
color: '#88C242',
|
|
3226
3226
|
},
|
|
3227
3227
|
},
|
|
3228
|
+
'shoutem.ui.AnimatedScrollingText': {
|
|
3229
|
+
text: {
|
|
3230
|
+
color: resolveVariable('text'),
|
|
3231
|
+
fontSize: responsiveHeight(15),
|
|
3232
|
+
fontWeight: resolveFontWeight('600'),
|
|
3233
|
+
flexWrap: 'nowrap',
|
|
3234
|
+
},
|
|
3235
|
+
scrollContainer: {
|
|
3236
|
+
maxHeight: responsiveHeight(20),
|
|
3237
|
+
},
|
|
3238
|
+
scrollContentContainer: {
|
|
3239
|
+
maxHeight: responsiveHeight(20),
|
|
3240
|
+
},
|
|
3241
|
+
},
|
|
3242
|
+
'shoutem.ui.SkipTrackIcon': {
|
|
3243
|
+
rotated: { transform: [{ rotate: '180deg' }] },
|
|
3244
|
+
icon: {
|
|
3245
|
+
size: responsiveHeight(24),
|
|
3246
|
+
color: '#FFF',
|
|
3247
|
+
strokeWidth: 2,
|
|
3248
|
+
triangleHeight: responsiveHeight(16),
|
|
3249
|
+
triangleWidth: responsiveWidth(12),
|
|
3250
|
+
},
|
|
3251
|
+
},
|
|
3228
3252
|
};
|
|
3229
3253
|
};
|