react-native-skelo 0.0.2 → 0.0.5
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.
- package/LICENSE +1 -1
- package/README.md +86 -90
- package/lib/commonjs/animations/PulseAnimation.js +17 -42
- package/lib/commonjs/animations/PulseAnimation.js.map +1 -1
- package/lib/commonjs/animations/ShimmerAnimation.js +54 -65
- package/lib/commonjs/animations/ShimmerAnimation.js.map +1 -1
- package/lib/commonjs/components/Skeleton.js +22 -16
- package/lib/commonjs/components/Skeleton.js.map +1 -1
- package/lib/commonjs/core/parser/expandLists.js +67 -0
- package/lib/commonjs/core/parser/expandLists.js.map +1 -0
- package/lib/commonjs/index.js +1 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/animations/PulseAnimation.js +18 -43
- package/lib/module/animations/PulseAnimation.js.map +1 -1
- package/lib/module/animations/ShimmerAnimation.js +55 -66
- package/lib/module/animations/ShimmerAnimation.js.map +1 -1
- package/lib/module/components/Skeleton.js +22 -16
- package/lib/module/components/Skeleton.js.map +1 -1
- package/lib/module/core/parser/expandLists.js +61 -0
- package/lib/module/core/parser/expandLists.js.map +1 -0
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/animations/PulseAnimation.d.ts +0 -44
- package/lib/typescript/animations/PulseAnimation.d.ts.map +1 -1
- package/lib/typescript/animations/ShimmerAnimation.d.ts +0 -44
- package/lib/typescript/animations/ShimmerAnimation.d.ts.map +1 -1
- package/lib/typescript/components/Skeleton.d.ts +1 -1
- package/lib/typescript/components/Skeleton.d.ts.map +1 -1
- package/lib/typescript/core/parser/expandLists.d.ts +3 -0
- package/lib/typescript/core/parser/expandLists.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/types/skeleton.d.ts +8 -0
- package/lib/typescript/types/skeleton.d.ts.map +1 -1
- package/package.json +5 -12
- package/src/animations/PulseAnimation.tsx +17 -89
- package/src/animations/ShimmerAnimation.tsx +39 -118
- package/src/components/Skeleton.tsx +24 -18
- package/src/core/parser/expandLists.tsx +77 -0
- package/src/index.ts +4 -0
- package/src/types/skeleton.ts +9 -0
|
@@ -1,59 +1,15 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { DimensionValue, StyleProp, ViewStyle } from 'react-native';
|
|
3
3
|
interface PulseProps {
|
|
4
|
-
/**
|
|
5
|
-
* Width of the pulse container
|
|
6
|
-
*/
|
|
7
4
|
width?: DimensionValue;
|
|
8
|
-
/**
|
|
9
|
-
* Height of the pulse container
|
|
10
|
-
*/
|
|
11
5
|
height?: DimensionValue;
|
|
12
|
-
/**
|
|
13
|
-
* Base color of the skeleton
|
|
14
|
-
* @default '#E1E9EE'
|
|
15
|
-
*/
|
|
16
6
|
baseColor?: string;
|
|
17
|
-
/**
|
|
18
|
-
* Highlight color for pulse
|
|
19
|
-
* @default '#F2F8FC'
|
|
20
|
-
*/
|
|
21
7
|
highlightColor?: string;
|
|
22
|
-
/**
|
|
23
|
-
* Animation duration in milliseconds
|
|
24
|
-
* @default 1000
|
|
25
|
-
*/
|
|
26
8
|
duration?: number;
|
|
27
|
-
/**
|
|
28
|
-
* Border radius
|
|
29
|
-
*/
|
|
30
9
|
borderRadius?: number;
|
|
31
|
-
/**
|
|
32
|
-
* Additional styles
|
|
33
|
-
*/
|
|
34
10
|
style?: StyleProp<ViewStyle>;
|
|
35
|
-
/**
|
|
36
|
-
* Child content (rendered inside pulse)
|
|
37
|
-
*/
|
|
38
11
|
children?: React.ReactNode;
|
|
39
12
|
}
|
|
40
|
-
/**
|
|
41
|
-
* Pulse animation component using Reanimated 3
|
|
42
|
-
*
|
|
43
|
-
* Creates a subtle breathing/pulsing effect using:
|
|
44
|
-
* - Shared values for performance
|
|
45
|
-
* - Worklets for 60 FPS on UI thread
|
|
46
|
-
* - Opacity animation for pulse effect
|
|
47
|
-
*
|
|
48
|
-
* @example
|
|
49
|
-
* ```tsx
|
|
50
|
-
* <PulseAnimation
|
|
51
|
-
* width={200}
|
|
52
|
-
* height={20}
|
|
53
|
-
* borderRadius={4}
|
|
54
|
-
* />
|
|
55
|
-
* ```
|
|
56
|
-
*/
|
|
57
13
|
export declare function PulseAnimation({ width, height, baseColor, duration, borderRadius, style, children, }: PulseProps): React.JSX.Element;
|
|
58
14
|
export {};
|
|
59
15
|
//# sourceMappingURL=PulseAnimation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PulseAnimation.d.ts","sourceRoot":"","sources":["../../../src/animations/PulseAnimation.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"PulseAnimation.d.ts","sourceRoot":"","sources":["../../../src/animations/PulseAnimation.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzE,UAAU,UAAU;IAClB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAGD,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,MAAM,EACN,SAAqB,EACrB,QAAe,EACf,YAAgB,EAChB,KAAK,EACL,QAAQ,GACT,EAAE,UAAU,qBAmCZ"}
|
|
@@ -1,59 +1,15 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { DimensionValue, StyleProp, ViewStyle } from 'react-native';
|
|
3
3
|
interface ShimmerProps {
|
|
4
|
-
/**
|
|
5
|
-
* Width of the shimmer container
|
|
6
|
-
*/
|
|
7
4
|
width?: DimensionValue;
|
|
8
|
-
/**
|
|
9
|
-
* Height of the shimmer container
|
|
10
|
-
*/
|
|
11
5
|
height?: DimensionValue;
|
|
12
|
-
/**
|
|
13
|
-
* Base color of the skeleton
|
|
14
|
-
* @default '#E1E9EE'
|
|
15
|
-
*/
|
|
16
6
|
baseColor?: string;
|
|
17
|
-
/**
|
|
18
|
-
* Highlight color that shimmers across
|
|
19
|
-
* @default '#F2F8FC'
|
|
20
|
-
*/
|
|
21
7
|
highlightColor?: string;
|
|
22
|
-
/**
|
|
23
|
-
* Animation duration in milliseconds
|
|
24
|
-
* @default 1500
|
|
25
|
-
*/
|
|
26
8
|
duration?: number;
|
|
27
|
-
/**
|
|
28
|
-
* Border radius
|
|
29
|
-
*/
|
|
30
9
|
borderRadius?: number;
|
|
31
|
-
/**
|
|
32
|
-
* Additional styles
|
|
33
|
-
*/
|
|
34
10
|
style?: StyleProp<ViewStyle>;
|
|
35
|
-
/**
|
|
36
|
-
* Child content (rendered on top of shimmer)
|
|
37
|
-
*/
|
|
38
11
|
children?: React.ReactNode;
|
|
39
12
|
}
|
|
40
|
-
/**
|
|
41
|
-
* Shimmer animation component using Reanimated 3
|
|
42
|
-
*
|
|
43
|
-
* Creates a smooth left-to-right shimmer effect using:
|
|
44
|
-
* - Shared values for performance
|
|
45
|
-
* - Worklets for 60 FPS on UI thread
|
|
46
|
-
* - Linear gradient for shimmer effect
|
|
47
|
-
*
|
|
48
|
-
* @example
|
|
49
|
-
* ```tsx
|
|
50
|
-
* <ShimmerAnimation
|
|
51
|
-
* width={200}
|
|
52
|
-
* height={20}
|
|
53
|
-
* borderRadius={4}
|
|
54
|
-
* />
|
|
55
|
-
* ```
|
|
56
|
-
*/
|
|
57
13
|
export declare function ShimmerAnimation({ width, height, baseColor, highlightColor, duration, borderRadius, style, children, }: ShimmerProps): React.JSX.Element;
|
|
58
14
|
export {};
|
|
59
15
|
//# sourceMappingURL=ShimmerAnimation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ShimmerAnimation.d.ts","sourceRoot":"","sources":["../../../src/animations/ShimmerAnimation.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"ShimmerAnimation.d.ts","sourceRoot":"","sources":["../../../src/animations/ShimmerAnimation.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAqB,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAG5F,UAAU,YAAY;IACpB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAKD,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,MAAM,EACN,SAAqB,EACrB,cAA0B,EAC1B,QAAe,EACf,YAAgB,EAChB,KAAK,EACL,QAAQ,GACT,EAAE,YAAY,qBA+Cd"}
|
|
@@ -29,7 +29,7 @@ import { SkeletonIgnore } from './SkeletonIgnore';
|
|
|
29
29
|
* </Skeleton>
|
|
30
30
|
* ```
|
|
31
31
|
*/
|
|
32
|
-
export declare function Skeleton({ loading, children, styles, excludeStyles, deep, animation, duration, baseColor, highlightColor, borderRadius, accessible, accessibilityLabel, debug, }: SkeletonProps): React.JSX.Element;
|
|
32
|
+
export declare function Skeleton({ loading, children, styles, excludeStyles, deep, count, animation, duration, baseColor, highlightColor, borderRadius, accessible, accessibilityLabel, debug, }: SkeletonProps): React.JSX.Element;
|
|
33
33
|
export declare namespace Skeleton {
|
|
34
34
|
var displayName: string;
|
|
35
35
|
var Ignore: typeof SkeletonIgnore;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Skeleton.d.ts","sourceRoot":"","sources":["../../../src/components/Skeleton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAG9C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"Skeleton.d.ts","sourceRoot":"","sources":["../../../src/components/Skeleton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAG9C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAMlD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,QAAQ,CAAC,EACvB,OAAO,EACP,QAAQ,EACR,MAAM,EACN,aAAa,EACb,IAAI,EACJ,KAAS,EACT,SAAoC,EACpC,QAAkC,EAClC,SAAoC,EACpC,cAA8C,EAC9C,YAA0C,EAC1C,UAAiB,EACjB,kBAAsC,EACtC,KAAa,GACd,EAAE,aAAa,qBA6Ff;yBA5Ge,QAAQ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expandLists.d.ts","sourceRoot":"","sources":["../../../../src/core/parser/expandLists.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAgB,SAAS,EAAE,MAAM,OAAO,CAAC;AAqDrD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAsBpF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,QAAQ,CAAC;AAGhB,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,YAAY,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC/D,YAAY,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAGjE,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGhC,YAAY,EACV,aAAa,EACb,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,eAAe,GAChB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -69,6 +69,14 @@ export interface SkeletonProps {
|
|
|
69
69
|
* When using `styles`, style keys to skip (e.g. layout containers).
|
|
70
70
|
*/
|
|
71
71
|
excludeStyles?: string[];
|
|
72
|
+
/**
|
|
73
|
+
* Number of placeholder rows to render for a `FlatList` / `SectionList`
|
|
74
|
+
* while its data is still loading (its rows don't exist yet, so Skelo calls
|
|
75
|
+
* `renderItem` with a placeholder and repeats it `count` times).
|
|
76
|
+
*
|
|
77
|
+
* @default 6
|
|
78
|
+
*/
|
|
79
|
+
count?: number;
|
|
72
80
|
/**
|
|
73
81
|
* Deep mode: expand opaque (custom) child components into their real
|
|
74
82
|
* host-element tree via offline rendering, producing a structured skeleton
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skeleton.d.ts","sourceRoot":"","sources":["../../../src/types/skeleton.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElE;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;IAEzC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE,CAAC;IAE7C;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB;;;;;;;;;;;;;OAaG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;IAEzC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IACjC,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,cAAc,CAAC,EACb,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,eAAe,GAAG,cAAc,GAAG,cAAc,CAAC;CAC5F;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,GAAG,CAAC;IACX,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB"}
|
|
1
|
+
{"version":3,"file":"skeleton.d.ts","sourceRoot":"","sources":["../../../src/types/skeleton.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElE;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;IAEzC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE,CAAC;IAE7C;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;;;;;;;;;;;OAaG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;IAEzC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IACjC,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,cAAc,CAAC,EACb,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,eAAe,GAAG,cAAc,GAAG,cAAc,CAAC;CAC5F;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,GAAG,CAAC;IACX,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-skelo",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Automatic skeleton loading for React Native. Write your UI once, Skelo builds the loading state automatically.",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -87,15 +87,10 @@
|
|
|
87
87
|
},
|
|
88
88
|
"peerDependencies": {
|
|
89
89
|
"react": "*",
|
|
90
|
-
"react-native": "*"
|
|
91
|
-
"react-native-linear-gradient": ">=2.8.0",
|
|
92
|
-
"react-native-reanimated": ">=3.0.0",
|
|
93
|
-
"react-reconciler": ">=0.29.0"
|
|
90
|
+
"react-native": "*"
|
|
94
91
|
},
|
|
95
|
-
"
|
|
96
|
-
"react-reconciler":
|
|
97
|
-
"optional": true
|
|
98
|
-
}
|
|
92
|
+
"dependencies": {
|
|
93
|
+
"react-reconciler": "^0.31.0"
|
|
99
94
|
},
|
|
100
95
|
"devDependencies": {
|
|
101
96
|
"@commitlint/config-conventional": "^18.4.3",
|
|
@@ -113,8 +108,6 @@
|
|
|
113
108
|
"react": "18.2.0",
|
|
114
109
|
"react-native": "0.73.1",
|
|
115
110
|
"react-native-builder-bob": "^0.23.2",
|
|
116
|
-
"react-native-linear-gradient": "^2.8.3",
|
|
117
|
-
"react-native-reanimated": "^3.6.1",
|
|
118
111
|
"react-reconciler": "^0.29.2",
|
|
119
112
|
"react-test-renderer": "18.2.0",
|
|
120
113
|
"release-it": "^17.0.1",
|
|
@@ -129,7 +122,7 @@
|
|
|
129
122
|
"<rootDir>/lib/"
|
|
130
123
|
],
|
|
131
124
|
"transformIgnorePatterns": [
|
|
132
|
-
"node_modules/(?!(@react-native|react-native
|
|
125
|
+
"node_modules/(?!(@react-native|react-native)/)"
|
|
133
126
|
],
|
|
134
127
|
"collectCoverageFrom": [
|
|
135
128
|
"src/**/*.{ts,tsx}",
|
|
@@ -1,77 +1,19 @@
|
|
|
1
|
-
import React, { useEffect } from 'react';
|
|
1
|
+
import React, { useEffect, useRef } from 'react';
|
|
2
2
|
import type { DimensionValue, StyleProp, ViewStyle } from 'react-native';
|
|
3
|
-
import { StyleSheet } from 'react-native';
|
|
4
|
-
import Animated, {
|
|
5
|
-
useSharedValue,
|
|
6
|
-
useAnimatedStyle,
|
|
7
|
-
withRepeat,
|
|
8
|
-
withSequence,
|
|
9
|
-
withTiming,
|
|
10
|
-
Easing,
|
|
11
|
-
} from 'react-native-reanimated';
|
|
3
|
+
import { Animated, Easing, StyleSheet } from 'react-native';
|
|
12
4
|
|
|
13
5
|
interface PulseProps {
|
|
14
|
-
/**
|
|
15
|
-
* Width of the pulse container
|
|
16
|
-
*/
|
|
17
6
|
width?: DimensionValue;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Height of the pulse container
|
|
21
|
-
*/
|
|
22
7
|
height?: DimensionValue;
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Base color of the skeleton
|
|
26
|
-
* @default '#E1E9EE'
|
|
27
|
-
*/
|
|
28
8
|
baseColor?: string;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Highlight color for pulse
|
|
32
|
-
* @default '#F2F8FC'
|
|
33
|
-
*/
|
|
34
9
|
highlightColor?: string;
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Animation duration in milliseconds
|
|
38
|
-
* @default 1000
|
|
39
|
-
*/
|
|
40
10
|
duration?: number;
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Border radius
|
|
44
|
-
*/
|
|
45
11
|
borderRadius?: number;
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Additional styles
|
|
49
|
-
*/
|
|
50
12
|
style?: StyleProp<ViewStyle>;
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Child content (rendered inside pulse)
|
|
54
|
-
*/
|
|
55
13
|
children?: React.ReactNode;
|
|
56
14
|
}
|
|
57
15
|
|
|
58
|
-
|
|
59
|
-
* Pulse animation component using Reanimated 3
|
|
60
|
-
*
|
|
61
|
-
* Creates a subtle breathing/pulsing effect using:
|
|
62
|
-
* - Shared values for performance
|
|
63
|
-
* - Worklets for 60 FPS on UI thread
|
|
64
|
-
* - Opacity animation for pulse effect
|
|
65
|
-
*
|
|
66
|
-
* @example
|
|
67
|
-
* ```tsx
|
|
68
|
-
* <PulseAnimation
|
|
69
|
-
* width={200}
|
|
70
|
-
* height={20}
|
|
71
|
-
* borderRadius={4}
|
|
72
|
-
* />
|
|
73
|
-
* ```
|
|
74
|
-
*/
|
|
16
|
+
// Breathing opacity loop using React Native's built-in Animated (native driver).
|
|
75
17
|
export function PulseAnimation({
|
|
76
18
|
width,
|
|
77
19
|
height,
|
|
@@ -81,48 +23,34 @@ export function PulseAnimation({
|
|
|
81
23
|
style,
|
|
82
24
|
children,
|
|
83
25
|
}: PulseProps) {
|
|
84
|
-
|
|
85
|
-
const opacity = useSharedValue(1);
|
|
26
|
+
const opacity = useRef(new Animated.Value(1)).current;
|
|
86
27
|
|
|
87
28
|
useEffect(() => {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
withTiming(0.5, {
|
|
29
|
+
const loop = Animated.loop(
|
|
30
|
+
Animated.sequence([
|
|
31
|
+
Animated.timing(opacity, {
|
|
32
|
+
toValue: 0.5,
|
|
93
33
|
duration: duration / 2,
|
|
94
34
|
easing: Easing.inOut(Easing.ease),
|
|
35
|
+
useNativeDriver: true,
|
|
95
36
|
}),
|
|
96
|
-
|
|
37
|
+
Animated.timing(opacity, {
|
|
38
|
+
toValue: 1,
|
|
97
39
|
duration: duration / 2,
|
|
98
40
|
easing: Easing.inOut(Easing.ease),
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
false // Don't reverse
|
|
41
|
+
useNativeDriver: true,
|
|
42
|
+
}),
|
|
43
|
+
])
|
|
103
44
|
);
|
|
45
|
+
loop.start();
|
|
46
|
+
return () => loop.stop();
|
|
104
47
|
}, [duration, opacity]);
|
|
105
48
|
|
|
106
|
-
// Animated style for pulse effect
|
|
107
|
-
const animatedStyle = useAnimatedStyle(() => {
|
|
108
|
-
'worklet';
|
|
109
|
-
|
|
110
|
-
return {
|
|
111
|
-
opacity: opacity.value,
|
|
112
|
-
};
|
|
113
|
-
}, []);
|
|
114
|
-
|
|
115
49
|
return (
|
|
116
50
|
<Animated.View
|
|
117
51
|
style={[
|
|
118
52
|
styles.container,
|
|
119
|
-
{
|
|
120
|
-
width,
|
|
121
|
-
height,
|
|
122
|
-
borderRadius,
|
|
123
|
-
backgroundColor: baseColor,
|
|
124
|
-
},
|
|
125
|
-
animatedStyle,
|
|
53
|
+
{ width, height, borderRadius, backgroundColor: baseColor, opacity },
|
|
126
54
|
style,
|
|
127
55
|
]}
|
|
128
56
|
>
|
|
@@ -1,78 +1,21 @@
|
|
|
1
|
-
import React, { useEffect } from 'react';
|
|
2
|
-
import type { DimensionValue, StyleProp, ViewStyle } from 'react-native';
|
|
3
|
-
import { StyleSheet, View } from 'react-native';
|
|
4
|
-
import Animated, {
|
|
5
|
-
useSharedValue,
|
|
6
|
-
useAnimatedStyle,
|
|
7
|
-
withRepeat,
|
|
8
|
-
withTiming,
|
|
9
|
-
interpolate,
|
|
10
|
-
Easing,
|
|
11
|
-
} from 'react-native-reanimated';
|
|
12
|
-
import { LinearGradient } from 'react-native-linear-gradient';
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import type { DimensionValue, LayoutChangeEvent, StyleProp, ViewStyle } from 'react-native';
|
|
3
|
+
import { Animated, Easing, StyleSheet, View } from 'react-native';
|
|
13
4
|
|
|
14
5
|
interface ShimmerProps {
|
|
15
|
-
/**
|
|
16
|
-
* Width of the shimmer container
|
|
17
|
-
*/
|
|
18
6
|
width?: DimensionValue;
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Height of the shimmer container
|
|
22
|
-
*/
|
|
23
7
|
height?: DimensionValue;
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Base color of the skeleton
|
|
27
|
-
* @default '#E1E9EE'
|
|
28
|
-
*/
|
|
29
8
|
baseColor?: string;
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Highlight color that shimmers across
|
|
33
|
-
* @default '#F2F8FC'
|
|
34
|
-
*/
|
|
35
9
|
highlightColor?: string;
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Animation duration in milliseconds
|
|
39
|
-
* @default 1500
|
|
40
|
-
*/
|
|
41
10
|
duration?: number;
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Border radius
|
|
45
|
-
*/
|
|
46
11
|
borderRadius?: number;
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Additional styles
|
|
50
|
-
*/
|
|
51
12
|
style?: StyleProp<ViewStyle>;
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Child content (rendered on top of shimmer)
|
|
55
|
-
*/
|
|
56
13
|
children?: React.ReactNode;
|
|
57
14
|
}
|
|
58
15
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
* Creates a smooth left-to-right shimmer effect using:
|
|
63
|
-
* - Shared values for performance
|
|
64
|
-
* - Worklets for 60 FPS on UI thread
|
|
65
|
-
* - Linear gradient for shimmer effect
|
|
66
|
-
*
|
|
67
|
-
* @example
|
|
68
|
-
* ```tsx
|
|
69
|
-
* <ShimmerAnimation
|
|
70
|
-
* width={200}
|
|
71
|
-
* height={20}
|
|
72
|
-
* borderRadius={4}
|
|
73
|
-
* />
|
|
74
|
-
* ```
|
|
75
|
-
*/
|
|
16
|
+
// Zero-dependency shimmer: a highlight band (dim/bright/dim segments to fake a
|
|
17
|
+
// soft gradient) sweeps across the base, driven by React Native's built-in
|
|
18
|
+
// Animated native driver. Plain Views only — guaranteed to render and animate.
|
|
76
19
|
export function ShimmerAnimation({
|
|
77
20
|
width,
|
|
78
21
|
height,
|
|
@@ -83,77 +26,49 @@ export function ShimmerAnimation({
|
|
|
83
26
|
style,
|
|
84
27
|
children,
|
|
85
28
|
}: ShimmerProps) {
|
|
86
|
-
|
|
87
|
-
const
|
|
29
|
+
const progress = useRef(new Animated.Value(0)).current;
|
|
30
|
+
const [measuredWidth, setMeasuredWidth] = useState(0);
|
|
88
31
|
|
|
89
32
|
useEffect(() => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
33
|
+
const loop = Animated.loop(
|
|
34
|
+
Animated.timing(progress, {
|
|
35
|
+
toValue: 1,
|
|
93
36
|
duration,
|
|
94
37
|
easing: Easing.linear,
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
false // Don't reverse
|
|
38
|
+
useNativeDriver: true,
|
|
39
|
+
})
|
|
98
40
|
);
|
|
41
|
+
loop.start();
|
|
42
|
+
return () => loop.stop();
|
|
99
43
|
}, [duration, progress]);
|
|
100
44
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
45
|
+
const onLayout = (event: LayoutChangeEvent) => {
|
|
46
|
+
const w = event.nativeEvent.layout.width;
|
|
47
|
+
setMeasuredWidth(prev => (prev === w ? prev : w));
|
|
48
|
+
};
|
|
104
49
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const translateX = interpolate(progress.value, [0, 1], [-1, 1]);
|
|
50
|
+
const containerWidth = typeof width === 'number' ? width : measuredWidth || 200;
|
|
51
|
+
const bandWidth = Math.max(containerWidth * 0.6, 80);
|
|
108
52
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
53
|
+
const translateX = progress.interpolate({
|
|
54
|
+
inputRange: [0, 1],
|
|
55
|
+
outputRange: [-bandWidth, containerWidth],
|
|
56
|
+
});
|
|
113
57
|
|
|
114
58
|
return (
|
|
115
59
|
<View
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
{
|
|
119
|
-
width,
|
|
120
|
-
height,
|
|
121
|
-
borderRadius,
|
|
122
|
-
backgroundColor: baseColor,
|
|
123
|
-
},
|
|
124
|
-
style,
|
|
125
|
-
]}
|
|
60
|
+
onLayout={onLayout}
|
|
61
|
+
style={[styles.container, { width, height, borderRadius, backgroundColor: baseColor }, style]}
|
|
126
62
|
>
|
|
127
|
-
{/* Shimmer gradient overlay */}
|
|
128
63
|
<Animated.View
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
{
|
|
132
|
-
overflow: 'hidden',
|
|
133
|
-
borderRadius,
|
|
134
|
-
},
|
|
135
|
-
]}
|
|
64
|
+
pointerEvents="none"
|
|
65
|
+
style={[styles.band, { width: bandWidth, transform: [{ translateX }] }]}
|
|
136
66
|
>
|
|
137
|
-
<
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
{
|
|
141
|
-
width: typeof width === 'number' ? width : '100%',
|
|
142
|
-
height: '100%',
|
|
143
|
-
},
|
|
144
|
-
animatedStyle,
|
|
145
|
-
]}
|
|
146
|
-
>
|
|
147
|
-
<LinearGradient
|
|
148
|
-
colors={[baseColor, highlightColor, highlightColor, baseColor]}
|
|
149
|
-
start={{ x: 0, y: 0 }}
|
|
150
|
-
end={{ x: 1, y: 0 }}
|
|
151
|
-
style={StyleSheet.absoluteFill}
|
|
152
|
-
/>
|
|
153
|
-
</Animated.View>
|
|
67
|
+
<View style={[styles.segment, { backgroundColor: highlightColor, opacity: 0.25 }]} />
|
|
68
|
+
<View style={[styles.segment, { backgroundColor: highlightColor, opacity: 0.9 }]} />
|
|
69
|
+
<View style={[styles.segment, { backgroundColor: highlightColor, opacity: 0.25 }]} />
|
|
154
70
|
</Animated.View>
|
|
155
71
|
|
|
156
|
-
{/* Child content */}
|
|
157
72
|
{children}
|
|
158
73
|
</View>
|
|
159
74
|
);
|
|
@@ -163,7 +78,13 @@ const styles = StyleSheet.create({
|
|
|
163
78
|
container: {
|
|
164
79
|
overflow: 'hidden',
|
|
165
80
|
},
|
|
166
|
-
|
|
81
|
+
band: {
|
|
167
82
|
position: 'absolute',
|
|
83
|
+
top: 0,
|
|
84
|
+
bottom: 0,
|
|
85
|
+
flexDirection: 'row',
|
|
86
|
+
},
|
|
87
|
+
segment: {
|
|
88
|
+
flex: 1,
|
|
168
89
|
},
|
|
169
90
|
});
|
|
@@ -5,6 +5,7 @@ import { SkeletonRenderer } from './SkeletonRenderer';
|
|
|
5
5
|
import { SkeletonIgnore } from './SkeletonIgnore';
|
|
6
6
|
import { StyleSkeleton } from '../core/generator/StyleSkeleton';
|
|
7
7
|
import { getDeepExpander } from '../core/deepRegistry';
|
|
8
|
+
import { expandListPlaceholders } from '../core/parser/expandLists';
|
|
8
9
|
import { DEFAULT_CONFIG } from '../constants/defaults';
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -40,7 +41,8 @@ export function Skeleton({
|
|
|
40
41
|
children,
|
|
41
42
|
styles,
|
|
42
43
|
excludeStyles,
|
|
43
|
-
deep
|
|
44
|
+
deep,
|
|
45
|
+
count = 6,
|
|
44
46
|
animation = DEFAULT_CONFIG.animation,
|
|
45
47
|
duration = DEFAULT_CONFIG.duration,
|
|
46
48
|
baseColor = DEFAULT_CONFIG.baseColor,
|
|
@@ -63,27 +65,31 @@ export function Skeleton({
|
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
try {
|
|
68
|
+
// Turn FlatList/SectionList into placeholder rows so lists show a
|
|
69
|
+
// skeleton even though their data (and rows) don't exist yet.
|
|
70
|
+
const prepared = expandListPlaceholders(children, count);
|
|
71
|
+
|
|
66
72
|
// Deep mode: expand opaque components into their real host tree via the
|
|
67
73
|
// opt-in expander (registered by importing 'react-native-skelo/deep').
|
|
68
|
-
//
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
} else if (__DEV__) {
|
|
80
|
-
console.warn(
|
|
81
|
-
"[Skelo] `deep` requires react-reconciler. Install it and add `import 'react-native-skelo/deep';` in your app entry."
|
|
82
|
-
);
|
|
74
|
+
// When `deep` is not set explicitly, it's used automatically whenever the
|
|
75
|
+
// expander is available. Falls back to static parsing otherwise.
|
|
76
|
+
const expand = getDeepExpander();
|
|
77
|
+
const wantDeep = deep === undefined ? expand !== null : deep;
|
|
78
|
+
if (wantDeep && expand) {
|
|
79
|
+
const expanded = expand(<>{prepared}</>);
|
|
80
|
+
if (expanded && expanded.length > 0) {
|
|
81
|
+
return expanded;
|
|
82
|
+
}
|
|
83
|
+
if (__DEV__) {
|
|
84
|
+
console.warn('[Skelo] deep expansion returned nothing; falling back to static parsing.');
|
|
83
85
|
}
|
|
86
|
+
} else if (deep === true && !expand && __DEV__) {
|
|
87
|
+
console.warn(
|
|
88
|
+
"[Skelo] `deep` requires react-reconciler. Install it and add `import 'react-native-skelo/deep';` in your app entry."
|
|
89
|
+
);
|
|
84
90
|
}
|
|
85
91
|
|
|
86
|
-
const parsed = Parser.parse(
|
|
92
|
+
const parsed = Parser.parse(prepared);
|
|
87
93
|
|
|
88
94
|
if (__DEV__ && debug) {
|
|
89
95
|
// Log a lightweight summary: the raw nodes hold React elements
|
|
@@ -104,7 +110,7 @@ export function Skeleton({
|
|
|
104
110
|
}
|
|
105
111
|
return [];
|
|
106
112
|
}
|
|
107
|
-
}, [loading, styles, deep, children, debug]);
|
|
113
|
+
}, [loading, styles, deep, count, children, debug]);
|
|
108
114
|
|
|
109
115
|
// Create skeleton config
|
|
110
116
|
const config = useMemo(
|