@hero-design/rn 8.16.1 → 8.17.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,134 @@
1
+ import LinearGradient from 'react-native-linear-gradient';
2
+ import React, {
3
+ useEffect,
4
+ useMemo,
5
+ useState,
6
+ useCallback,
7
+ useRef,
8
+ } from 'react';
9
+ import {
10
+ Animated,
11
+ Easing,
12
+ LayoutChangeEvent,
13
+ ViewProps,
14
+ Platform,
15
+ StyleSheet,
16
+ } from 'react-native';
17
+ import { Theme, useTheme } from '../../theme';
18
+ import { StyledContainer, StyledGradientContainer } from './StyledSkeleton';
19
+
20
+ export interface SkeletonProps extends ViewProps {
21
+ /**
22
+ * Intent of the component.
23
+ */
24
+ intent?: 'light' | 'dark';
25
+ /**
26
+ * Variant of the component.
27
+ */
28
+ variant?: 'circular' | 'rectangular' | 'rounded';
29
+ }
30
+
31
+ const AnimatedLinearGradient = Animated.createAnimatedComponent(LinearGradient);
32
+
33
+ const gradientPositions = {
34
+ start: { x: 0, y: 0 },
35
+ end: { x: 1, y: 0 },
36
+ };
37
+
38
+ const getGradientColors = (theme: Theme, intent: 'light' | 'dark') => {
39
+ switch (intent) {
40
+ case 'light': {
41
+ return [
42
+ theme.__hd__.skeleton.colors.lightGradientStart,
43
+ theme.__hd__.skeleton.colors.lightGradientEnd,
44
+ theme.__hd__.skeleton.colors.lightGradientStart,
45
+ ];
46
+ }
47
+ case 'dark': {
48
+ return [
49
+ theme.__hd__.skeleton.colors.darkGradientStart,
50
+ theme.__hd__.skeleton.colors.darkGradientEnd,
51
+ theme.__hd__.skeleton.colors.darkGradientStart,
52
+ ];
53
+ }
54
+ }
55
+ };
56
+
57
+ const Skeleton = ({
58
+ intent = 'light',
59
+ variant = 'rounded',
60
+ style,
61
+ onLayout,
62
+ ...props
63
+ }: SkeletonProps) => {
64
+ const theme = useTheme();
65
+ const colors = useMemo(
66
+ () => getGradientColors(theme, intent),
67
+ [theme, intent]
68
+ );
69
+ const [containerWidth, setContainerWidth] = useState(
70
+ Number(StyleSheet.flatten(style)?.width) || 0
71
+ );
72
+ const [containerHeight, setContainerHeight] = useState(
73
+ Number(StyleSheet.flatten(style)?.height) || 0
74
+ );
75
+
76
+ const [shouldStartAnimation, setShouldStartAnimation] = useState(false);
77
+
78
+ const animatedValue = useRef(new Animated.Value(0)).current;
79
+
80
+ useEffect(() => {
81
+ if (shouldStartAnimation) {
82
+ Animated.loop(
83
+ Animated.timing(animatedValue, {
84
+ toValue: 1,
85
+ duration: 1000,
86
+ easing: Easing.linear,
87
+ useNativeDriver: Platform.OS === 'ios' || Platform.OS === 'android',
88
+ })
89
+ ).start();
90
+ }
91
+ }, [shouldStartAnimation]);
92
+
93
+ const translateX = animatedValue.interpolate({
94
+ inputRange: [0, 1],
95
+ outputRange: [-containerWidth, containerWidth],
96
+ });
97
+
98
+ const onContainerLayout = useCallback((e: LayoutChangeEvent) => {
99
+ const { width, height } = e.nativeEvent.layout;
100
+ setContainerHeight(height);
101
+ setContainerWidth(width);
102
+
103
+ if (!shouldStartAnimation) {
104
+ setShouldStartAnimation(true);
105
+ }
106
+
107
+ onLayout?.(e);
108
+ }, []);
109
+
110
+ return (
111
+ <StyledContainer
112
+ style={style}
113
+ themeVariant={variant}
114
+ themeIntent={intent}
115
+ onLayout={onContainerLayout}
116
+ {...props}
117
+ >
118
+ <StyledGradientContainer themeVariant={variant}>
119
+ <AnimatedLinearGradient
120
+ start={gradientPositions.start}
121
+ end={gradientPositions.end}
122
+ style={{
123
+ width: containerWidth,
124
+ height: containerHeight,
125
+ transform: [{ translateX }],
126
+ }}
127
+ colors={colors}
128
+ />
129
+ </StyledGradientContainer>
130
+ </StyledContainer>
131
+ );
132
+ };
133
+
134
+ export default Skeleton;
package/src/index.ts CHANGED
@@ -45,6 +45,7 @@ import Swipeable from './components/Swipeable';
45
45
  import Radio from './components/Radio';
46
46
  import SectionHeading from './components/SectionHeading';
47
47
  import Select from './components/Select';
48
+ import Skeleton from './components/Skeleton';
48
49
  import Switch from './components/Switch';
49
50
  import Tabs from './components/Tabs';
50
51
  import Tag from './components/Tag';
@@ -99,6 +100,7 @@ export {
99
100
  PinInput,
100
101
  Progress,
101
102
  PageControl,
103
+ Skeleton,
102
104
  Slider,
103
105
  Spinner,
104
106
  Swipeable,
@@ -737,6 +737,21 @@ Object {
737
737
  "suffixMarginRight": 12,
738
738
  },
739
739
  },
740
+ "skeleton": Object {
741
+ "colors": Object {
742
+ "darkBackground": "#ffffff",
743
+ "darkGradientEnd": "#f1f2f3",
744
+ "darkGradientStart": "#ffffff",
745
+ "lightBackground": "#f6f6f7",
746
+ "lightGradientEnd": "#f1f2f3",
747
+ "lightGradientStart": "#f6f6f7",
748
+ },
749
+ "radii": Object {
750
+ "circular": 999,
751
+ "rectangular": 0,
752
+ "rounded": 16,
753
+ },
754
+ },
740
755
  "slider": Object {
741
756
  "colors": Object {
742
757
  "maximumTrackTint": "#ece8ef",
@@ -0,0 +1,22 @@
1
+ import type { GlobalTheme } from '../global';
2
+
3
+ const getSkeletonTheme = (theme: GlobalTheme) => {
4
+ const colors = {
5
+ lightBackground: theme.colors.neutralGlobalSurface,
6
+ darkBackground: theme.colors.defaultGlobalSurface,
7
+ lightGradientStart: theme.colors.neutralGlobalSurface,
8
+ lightGradientEnd: theme.colors.archivedSurface,
9
+ darkGradientStart: theme.colors.defaultGlobalSurface,
10
+ darkGradientEnd: theme.colors.archivedSurface,
11
+ };
12
+
13
+ const radii = {
14
+ rectangular: 0,
15
+ circular: theme.radii.rounded,
16
+ rounded: theme.radii.xlarge,
17
+ };
18
+
19
+ return { colors, radii };
20
+ };
21
+
22
+ export default getSkeletonTheme;
@@ -31,6 +31,7 @@ import getRefreshControlTheme from './components/refreshControl';
31
31
  import getRichTextEditorTheme from './components/richTextEditor';
32
32
  import getSectionHeadingTheme from './components/sectionHeading';
33
33
  import getSelectTheme from './components/select';
34
+ import getSkeletonTheme from './components/skeleton';
34
35
  import getSliderTheme from './components/slider';
35
36
  import getSpinnerTheme from './components/spinner';
36
37
  import getSwipeableTheme from './components/swipeable';
@@ -78,6 +79,7 @@ type Theme = GlobalTheme & {
78
79
  richTextEditor: ReturnType<typeof getRichTextEditorTheme>;
79
80
  sectionHeading: ReturnType<typeof getSectionHeadingTheme>;
80
81
  select: ReturnType<typeof getSelectTheme>;
82
+ skeleton: ReturnType<typeof getSkeletonTheme>;
81
83
  slider: ReturnType<typeof getSliderTheme>;
82
84
  spinner: ReturnType<typeof getSpinnerTheme>;
83
85
  swipeable: ReturnType<typeof getSwipeableTheme>;
@@ -131,6 +133,7 @@ const getTheme = (
131
133
  richTextEditor: getRichTextEditorTheme(globalTheme),
132
134
  sectionHeading: getSectionHeadingTheme(globalTheme),
133
135
  select: getSelectTheme(globalTheme),
136
+ skeleton: getSkeletonTheme(globalTheme),
134
137
  slider: getSliderTheme(globalTheme),
135
138
  spinner: getSpinnerTheme(globalTheme),
136
139
  swipeable: getSwipeableTheme(globalTheme),
@@ -0,0 +1,17 @@
1
+ /// <reference types="react" />
2
+ declare type ThemeIntent = 'light' | 'dark';
3
+ declare type ThemeVariant = 'circular' | 'rectangular' | 'rounded';
4
+ declare const StyledContainer: import("@emotion/native").StyledComponent<import("../Box").BoxProps & {
5
+ theme?: import("@emotion/react").Theme | undefined;
6
+ as?: import("react").ElementType<any> | undefined;
7
+ } & {
8
+ themeIntent: ThemeIntent;
9
+ themeVariant: ThemeVariant;
10
+ }, {}, {}>;
11
+ declare const StyledGradientContainer: import("@emotion/native").StyledComponent<import("../Box").BoxProps & {
12
+ theme?: import("@emotion/react").Theme | undefined;
13
+ as?: import("react").ElementType<any> | undefined;
14
+ } & {
15
+ themeVariant: ThemeVariant;
16
+ }, {}, {}>;
17
+ export { StyledContainer, StyledGradientContainer };
@@ -0,0 +1,13 @@
1
+ import { ViewProps } from 'react-native';
2
+ export interface SkeletonProps extends ViewProps {
3
+ /**
4
+ * Intent of the component.
5
+ */
6
+ intent?: 'light' | 'dark';
7
+ /**
8
+ * Variant of the component.
9
+ */
10
+ variant?: 'circular' | 'rectangular' | 'rounded';
11
+ }
12
+ declare const Skeleton: ({ intent, variant, style, onLayout, ...props }: SkeletonProps) => JSX.Element;
13
+ export default Skeleton;
package/types/index.d.ts CHANGED
@@ -32,6 +32,7 @@ import Swipeable from './components/Swipeable';
32
32
  import Radio from './components/Radio';
33
33
  import SectionHeading from './components/SectionHeading';
34
34
  import Select from './components/Select';
35
+ import Skeleton from './components/Skeleton';
35
36
  import Switch from './components/Switch';
36
37
  import Tabs from './components/Tabs';
37
38
  import Tag from './components/Tag';
@@ -43,5 +44,5 @@ import Typography from './components/Typography';
43
44
  import RefreshControl from './components/RefreshControl';
44
45
  import RichTextEditor from './components/RichTextEditor';
45
46
  import PageControl from './components/PageControl';
46
- export { theme, getTheme, useTheme, scale, ThemeProvider, ThemeSwitcher, withTheme, swagSystemPalette, swagDarkSystemPalette, workSystemPalette, jobsSystemPalette, walletSystemPalette, eBensSystemPalette, Accordion, Alert, Attachment, Avatar, useAvatarColors, Badge, BottomNavigation, BottomSheet, Box, Button, Calendar, Card, Carousel, Collapse, Checkbox, ContentNavigator, DatePicker, Divider, Drawer, Empty, Error, FAB, Icon, Image, List, PinInput, Progress, PageControl, Slider, Spinner, Swipeable, Radio, SectionHeading, Select, Switch, Tabs, Tag, TextInput, TimePicker, Toast, Toolbar, Typography, RefreshControl, RichTextEditor, };
47
+ export { theme, getTheme, useTheme, scale, ThemeProvider, ThemeSwitcher, withTheme, swagSystemPalette, swagDarkSystemPalette, workSystemPalette, jobsSystemPalette, walletSystemPalette, eBensSystemPalette, Accordion, Alert, Attachment, Avatar, useAvatarColors, Badge, BottomNavigation, BottomSheet, Box, Button, Calendar, Card, Carousel, Collapse, Checkbox, ContentNavigator, DatePicker, Divider, Drawer, Empty, Error, FAB, Icon, Image, List, PinInput, Progress, PageControl, Skeleton, Slider, Spinner, Swipeable, Radio, SectionHeading, Select, Switch, Tabs, Tag, TextInput, TimePicker, Toast, Toolbar, Typography, RefreshControl, RichTextEditor, };
47
48
  export * from './types';
@@ -0,0 +1,17 @@
1
+ import type { GlobalTheme } from '../global';
2
+ declare const getSkeletonTheme: (theme: GlobalTheme) => {
3
+ colors: {
4
+ lightBackground: string;
5
+ darkBackground: string;
6
+ lightGradientStart: string;
7
+ lightGradientEnd: string;
8
+ darkGradientStart: string;
9
+ darkGradientEnd: string;
10
+ };
11
+ radii: {
12
+ rectangular: number;
13
+ circular: number;
14
+ rounded: number;
15
+ };
16
+ };
17
+ export default getSkeletonTheme;
@@ -29,6 +29,7 @@ import getRefreshControlTheme from './components/refreshControl';
29
29
  import getRichTextEditorTheme from './components/richTextEditor';
30
30
  import getSectionHeadingTheme from './components/sectionHeading';
31
31
  import getSelectTheme from './components/select';
32
+ import getSkeletonTheme from './components/skeleton';
32
33
  import getSliderTheme from './components/slider';
33
34
  import getSpinnerTheme from './components/spinner';
34
35
  import getSwipeableTheme from './components/swipeable';
@@ -74,6 +75,7 @@ declare type Theme = GlobalTheme & {
74
75
  richTextEditor: ReturnType<typeof getRichTextEditorTheme>;
75
76
  sectionHeading: ReturnType<typeof getSectionHeadingTheme>;
76
77
  select: ReturnType<typeof getSelectTheme>;
78
+ skeleton: ReturnType<typeof getSkeletonTheme>;
77
79
  slider: ReturnType<typeof getSliderTheme>;
78
80
  spinner: ReturnType<typeof getSpinnerTheme>;
79
81
  swipeable: ReturnType<typeof getSwipeableTheme>;