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.
Files changed (41) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +86 -90
  3. package/lib/commonjs/animations/PulseAnimation.js +17 -42
  4. package/lib/commonjs/animations/PulseAnimation.js.map +1 -1
  5. package/lib/commonjs/animations/ShimmerAnimation.js +54 -65
  6. package/lib/commonjs/animations/ShimmerAnimation.js.map +1 -1
  7. package/lib/commonjs/components/Skeleton.js +22 -16
  8. package/lib/commonjs/components/Skeleton.js.map +1 -1
  9. package/lib/commonjs/core/parser/expandLists.js +67 -0
  10. package/lib/commonjs/core/parser/expandLists.js.map +1 -0
  11. package/lib/commonjs/index.js +1 -0
  12. package/lib/commonjs/index.js.map +1 -1
  13. package/lib/module/animations/PulseAnimation.js +18 -43
  14. package/lib/module/animations/PulseAnimation.js.map +1 -1
  15. package/lib/module/animations/ShimmerAnimation.js +55 -66
  16. package/lib/module/animations/ShimmerAnimation.js.map +1 -1
  17. package/lib/module/components/Skeleton.js +22 -16
  18. package/lib/module/components/Skeleton.js.map +1 -1
  19. package/lib/module/core/parser/expandLists.js +61 -0
  20. package/lib/module/core/parser/expandLists.js.map +1 -0
  21. package/lib/module/index.js +4 -0
  22. package/lib/module/index.js.map +1 -1
  23. package/lib/typescript/animations/PulseAnimation.d.ts +0 -44
  24. package/lib/typescript/animations/PulseAnimation.d.ts.map +1 -1
  25. package/lib/typescript/animations/ShimmerAnimation.d.ts +0 -44
  26. package/lib/typescript/animations/ShimmerAnimation.d.ts.map +1 -1
  27. package/lib/typescript/components/Skeleton.d.ts +1 -1
  28. package/lib/typescript/components/Skeleton.d.ts.map +1 -1
  29. package/lib/typescript/core/parser/expandLists.d.ts +3 -0
  30. package/lib/typescript/core/parser/expandLists.d.ts.map +1 -0
  31. package/lib/typescript/index.d.ts +1 -0
  32. package/lib/typescript/index.d.ts.map +1 -1
  33. package/lib/typescript/types/skeleton.d.ts +8 -0
  34. package/lib/typescript/types/skeleton.d.ts.map +1 -1
  35. package/package.json +5 -12
  36. package/src/animations/PulseAnimation.tsx +17 -89
  37. package/src/animations/ShimmerAnimation.tsx +39 -118
  38. package/src/components/Skeleton.tsx +24 -18
  39. package/src/core/parser/expandLists.tsx +77 -0
  40. package/src/index.ts +4 -0
  41. 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,KAAoB,MAAM,OAAO,CAAC;AACzC,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAWzE,UAAU,UAAU;IAClB;;OAEG;IACH,KAAK,CAAC,EAAE,cAAc,CAAC;IAEvB;;OAEG;IACH,MAAM,CAAC,EAAE,cAAc,CAAC;IAExB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAE7B;;OAEG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,MAAM,EACN,SAAqB,EACrB,QAAe,EACf,YAAgB,EAChB,KAAK,EACL,QAAQ,GACT,EAAE,UAAU,qBAiDZ"}
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,KAAoB,MAAM,OAAO,CAAC;AACzC,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAYzE,UAAU,YAAY;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,cAAc,CAAC;IAEvB;;OAEG;IACH,MAAM,CAAC,EAAE,cAAc,CAAC;IAExB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAE7B;;OAEG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,MAAM,EACN,SAAqB,EACrB,cAA0B,EAC1B,QAAe,EACf,YAAgB,EAChB,KAAK,EACL,QAAQ,GACT,EAAE,YAAY,qBA2Ed"}
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;AAKlD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,QAAQ,CAAC,EACvB,OAAO,EACP,QAAQ,EACR,MAAM,EACN,aAAa,EACb,IAAY,EACZ,SAAoC,EACpC,QAAkC,EAClC,SAAoC,EACpC,cAA8C,EAC9C,YAA0C,EAC1C,UAAiB,EACjB,kBAAsC,EACtC,KAAa,GACd,EAAE,aAAa,qBAyFf;yBAvGe,QAAQ"}
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,3 @@
1
+ import type { ReactNode } from 'react';
2
+ export declare function expandListPlaceholders(children: ReactNode, count: number): ReactNode;
3
+ //# sourceMappingURL=expandLists.d.ts.map
@@ -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"}
@@ -5,6 +5,7 @@
5
5
  *
6
6
  * @packageDocumentation
7
7
  */
8
+ import './deep';
8
9
  export { Skeleton } from './components/Skeleton';
9
10
  export { SkeletonIgnore } from './components/SkeletonIgnore';
10
11
  export { withSkeleton } from './components/withSkeleton';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,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"}
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.2",
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
- "peerDependenciesMeta": {
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|react-native-reanimated|react-native-linear-gradient)/)"
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
- // Shared value for opacity (0 to 1)
85
- const opacity = useSharedValue(1);
26
+ const opacity = useRef(new Animated.Value(1)).current;
86
27
 
87
28
  useEffect(() => {
88
- // Start infinite pulse animation
89
- // Sequence: fade out -> fade in
90
- opacity.value = withRepeat(
91
- withSequence(
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
- withTiming(1, {
37
+ Animated.timing(opacity, {
38
+ toValue: 1,
97
39
  duration: duration / 2,
98
40
  easing: Easing.inOut(Easing.ease),
99
- })
100
- ),
101
- -1, // Infinite repeat
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
- * Shimmer animation component using Reanimated 3
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
- // Shared value for animation progress (0 to 1)
87
- const progress = useSharedValue(0);
29
+ const progress = useRef(new Animated.Value(0)).current;
30
+ const [measuredWidth, setMeasuredWidth] = useState(0);
88
31
 
89
32
  useEffect(() => {
90
- // Start infinite shimmer animation
91
- progress.value = withRepeat(
92
- withTiming(1, {
33
+ const loop = Animated.loop(
34
+ Animated.timing(progress, {
35
+ toValue: 1,
93
36
  duration,
94
37
  easing: Easing.linear,
95
- }),
96
- -1, // Infinite repeat
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
- // Animated style for shimmer overlay
102
- const animatedStyle = useAnimatedStyle(() => {
103
- 'worklet';
45
+ const onLayout = (event: LayoutChangeEvent) => {
46
+ const w = event.nativeEvent.layout.width;
47
+ setMeasuredWidth(prev => (prev === w ? prev : w));
48
+ };
104
49
 
105
- // Calculate shimmer position
106
- // Interpolate from -100% to 100% to create left-to-right sweep
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
- return {
110
- transform: [{ translateX: translateX * (typeof width === 'number' ? width : 200) }],
111
- };
112
- }, [width]);
53
+ const translateX = progress.interpolate({
54
+ inputRange: [0, 1],
55
+ outputRange: [-bandWidth, containerWidth],
56
+ });
113
57
 
114
58
  return (
115
59
  <View
116
- style={[
117
- styles.container,
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
- style={[
130
- StyleSheet.absoluteFill,
131
- {
132
- overflow: 'hidden',
133
- borderRadius,
134
- },
135
- ]}
64
+ pointerEvents="none"
65
+ style={[styles.band, { width: bandWidth, transform: [{ translateX }] }]}
136
66
  >
137
- <Animated.View
138
- style={[
139
- styles.shimmer,
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
- shimmer: {
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 = false,
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
- // Falls back to static parsing if unavailable or it returns nothing.
69
- if (deep) {
70
- const expand = getDeepExpander();
71
- if (expand) {
72
- const expanded = expand(<>{children}</>);
73
- if (expanded && expanded.length > 0) {
74
- return expanded;
75
- }
76
- if (__DEV__) {
77
- console.warn('[Skelo] deep expansion returned nothing; falling back to static parsing.');
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(children);
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(