react-native-skelo 0.0.1 → 0.0.3

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 (269) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +149 -20
  3. package/lib/commonjs/Skelo.js +104 -0
  4. package/lib/commonjs/Skelo.js.map +1 -0
  5. package/lib/commonjs/animations/AnimationWrapper.js +76 -0
  6. package/lib/commonjs/animations/AnimationWrapper.js.map +1 -0
  7. package/lib/commonjs/animations/PulseAnimation.js +52 -0
  8. package/lib/commonjs/animations/PulseAnimation.js.map +1 -0
  9. package/lib/commonjs/animations/ShimmerAnimation.js +73 -0
  10. package/lib/commonjs/animations/ShimmerAnimation.js.map +1 -0
  11. package/lib/commonjs/animations/index.js +27 -0
  12. package/lib/commonjs/animations/index.js.map +1 -0
  13. package/lib/commonjs/components/MeasuredBlock.js +64 -0
  14. package/lib/commonjs/components/MeasuredBlock.js.map +1 -0
  15. package/lib/commonjs/components/Skeleton.js +144 -0
  16. package/lib/commonjs/components/Skeleton.js.map +1 -0
  17. package/lib/commonjs/components/SkeletonIgnore.js +30 -0
  18. package/lib/commonjs/components/SkeletonIgnore.js.map +1 -0
  19. package/lib/commonjs/components/SkeletonRenderer.js +270 -0
  20. package/lib/commonjs/components/SkeletonRenderer.js.map +1 -0
  21. package/lib/commonjs/components/primitives/SkeletonBox.js +47 -0
  22. package/lib/commonjs/components/primitives/SkeletonBox.js.map +1 -0
  23. package/lib/commonjs/components/primitives/SkeletonCircle.js +44 -0
  24. package/lib/commonjs/components/primitives/SkeletonCircle.js.map +1 -0
  25. package/lib/commonjs/components/primitives/SkeletonImage.js +46 -0
  26. package/lib/commonjs/components/primitives/SkeletonImage.js.map +1 -0
  27. package/lib/commonjs/components/primitives/SkeletonText.js +60 -0
  28. package/lib/commonjs/components/primitives/SkeletonText.js.map +1 -0
  29. package/lib/commonjs/components/primitives/index.js +34 -0
  30. package/lib/commonjs/components/primitives/index.js.map +1 -0
  31. package/lib/commonjs/components/withSkeleton.js +45 -0
  32. package/lib/commonjs/components/withSkeleton.js.map +1 -0
  33. package/lib/commonjs/constants/defaults.js +43 -0
  34. package/lib/commonjs/constants/defaults.js.map +1 -0
  35. package/lib/commonjs/core/deepRegistry.js +18 -0
  36. package/lib/commonjs/core/deepRegistry.js.map +1 -0
  37. package/lib/commonjs/core/generator/StyleSkeleton.js +101 -0
  38. package/lib/commonjs/core/generator/StyleSkeleton.js.map +1 -0
  39. package/lib/commonjs/core/parser/Parser.js +84 -0
  40. package/lib/commonjs/core/parser/Parser.js.map +1 -0
  41. package/lib/commonjs/core/parser/expandOffline.js +83 -0
  42. package/lib/commonjs/core/parser/expandOffline.js.map +1 -0
  43. package/lib/commonjs/core/parser/hostTreeReconciler.js +228 -0
  44. package/lib/commonjs/core/parser/hostTreeReconciler.js.map +1 -0
  45. package/lib/commonjs/core/parser/index.js +13 -0
  46. package/lib/commonjs/core/parser/index.js.map +1 -0
  47. package/lib/commonjs/core/registry/SkeletonRegistry.js +113 -0
  48. package/lib/commonjs/core/registry/SkeletonRegistry.js.map +1 -0
  49. package/lib/commonjs/core/registry/index.js +19 -0
  50. package/lib/commonjs/core/registry/index.js.map +1 -0
  51. package/lib/commonjs/core/resolver/StyleResolver.js +83 -0
  52. package/lib/commonjs/core/resolver/StyleResolver.js.map +1 -0
  53. package/lib/commonjs/core/resolver/index.js +13 -0
  54. package/lib/commonjs/core/resolver/index.js.map +1 -0
  55. package/lib/commonjs/deep.js +18 -0
  56. package/lib/commonjs/deep.js.map +1 -0
  57. package/lib/commonjs/index.js +66 -0
  58. package/lib/commonjs/index.js.map +1 -0
  59. package/lib/commonjs/plugins/ImagePlugin.js +60 -0
  60. package/lib/commonjs/plugins/ImagePlugin.js.map +1 -0
  61. package/lib/commonjs/plugins/TextPlugin.js +70 -0
  62. package/lib/commonjs/plugins/TextPlugin.js.map +1 -0
  63. package/lib/commonjs/plugins/ViewPlugin.js +71 -0
  64. package/lib/commonjs/plugins/ViewPlugin.js.map +1 -0
  65. package/lib/commonjs/plugins/index.js +27 -0
  66. package/lib/commonjs/plugins/index.js.map +1 -0
  67. package/lib/commonjs/types/index.js +2 -0
  68. package/lib/commonjs/types/index.js.map +1 -0
  69. package/lib/commonjs/types/plugin.js +6 -0
  70. package/lib/commonjs/types/plugin.js.map +1 -0
  71. package/lib/commonjs/types/skeleton.js +6 -0
  72. package/lib/commonjs/types/skeleton.js.map +1 -0
  73. package/lib/commonjs/utils/componentUtils.js +138 -0
  74. package/lib/commonjs/utils/componentUtils.js.map +1 -0
  75. package/lib/commonjs/utils/index.js +62 -0
  76. package/lib/commonjs/utils/index.js.map +1 -0
  77. package/lib/commonjs/utils/styleUtils.js +76 -0
  78. package/lib/commonjs/utils/styleUtils.js.map +1 -0
  79. package/lib/module/Skelo.js +98 -0
  80. package/lib/module/Skelo.js.map +1 -0
  81. package/lib/module/animations/AnimationWrapper.js +69 -0
  82. package/lib/module/animations/AnimationWrapper.js.map +1 -0
  83. package/lib/module/animations/PulseAnimation.js +45 -0
  84. package/lib/module/animations/PulseAnimation.js.map +1 -0
  85. package/lib/module/animations/ShimmerAnimation.js +66 -0
  86. package/lib/module/animations/ShimmerAnimation.js.map +1 -0
  87. package/lib/module/animations/index.js +4 -0
  88. package/lib/module/animations/index.js.map +1 -0
  89. package/lib/module/components/MeasuredBlock.js +57 -0
  90. package/lib/module/components/MeasuredBlock.js.map +1 -0
  91. package/lib/module/components/Skeleton.js +138 -0
  92. package/lib/module/components/Skeleton.js.map +1 -0
  93. package/lib/module/components/SkeletonIgnore.js +23 -0
  94. package/lib/module/components/SkeletonIgnore.js.map +1 -0
  95. package/lib/module/components/SkeletonRenderer.js +264 -0
  96. package/lib/module/components/SkeletonRenderer.js.map +1 -0
  97. package/lib/module/components/primitives/SkeletonBox.js +40 -0
  98. package/lib/module/components/primitives/SkeletonBox.js.map +1 -0
  99. package/lib/module/components/primitives/SkeletonCircle.js +37 -0
  100. package/lib/module/components/primitives/SkeletonCircle.js.map +1 -0
  101. package/lib/module/components/primitives/SkeletonImage.js +39 -0
  102. package/lib/module/components/primitives/SkeletonImage.js.map +1 -0
  103. package/lib/module/components/primitives/SkeletonText.js +53 -0
  104. package/lib/module/components/primitives/SkeletonText.js.map +1 -0
  105. package/lib/module/components/primitives/index.js +5 -0
  106. package/lib/module/components/primitives/index.js.map +1 -0
  107. package/lib/module/components/withSkeleton.js +38 -0
  108. package/lib/module/components/withSkeleton.js.map +1 -0
  109. package/lib/module/constants/defaults.js +37 -0
  110. package/lib/module/constants/defaults.js.map +1 -0
  111. package/lib/module/core/deepRegistry.js +11 -0
  112. package/lib/module/core/deepRegistry.js.map +1 -0
  113. package/lib/module/core/generator/StyleSkeleton.js +95 -0
  114. package/lib/module/core/generator/StyleSkeleton.js.map +1 -0
  115. package/lib/module/core/parser/Parser.js +77 -0
  116. package/lib/module/core/parser/Parser.js.map +1 -0
  117. package/lib/module/core/parser/expandOffline.js +77 -0
  118. package/lib/module/core/parser/expandOffline.js.map +1 -0
  119. package/lib/module/core/parser/hostTreeReconciler.js +222 -0
  120. package/lib/module/core/parser/hostTreeReconciler.js.map +1 -0
  121. package/lib/module/core/parser/index.js +2 -0
  122. package/lib/module/core/parser/index.js.map +1 -0
  123. package/lib/module/core/registry/SkeletonRegistry.js +106 -0
  124. package/lib/module/core/registry/SkeletonRegistry.js.map +1 -0
  125. package/lib/module/core/registry/index.js +2 -0
  126. package/lib/module/core/registry/index.js.map +1 -0
  127. package/lib/module/core/resolver/StyleResolver.js +77 -0
  128. package/lib/module/core/resolver/StyleResolver.js.map +1 -0
  129. package/lib/module/core/resolver/index.js +2 -0
  130. package/lib/module/core/resolver/index.js.map +1 -0
  131. package/lib/module/deep.js +11 -0
  132. package/lib/module/deep.js.map +1 -0
  133. package/lib/module/index.js +21 -0
  134. package/lib/module/index.js.map +1 -0
  135. package/lib/module/plugins/ImagePlugin.js +53 -0
  136. package/lib/module/plugins/ImagePlugin.js.map +1 -0
  137. package/lib/module/plugins/TextPlugin.js +63 -0
  138. package/lib/module/plugins/TextPlugin.js.map +1 -0
  139. package/lib/module/plugins/ViewPlugin.js +64 -0
  140. package/lib/module/plugins/ViewPlugin.js.map +1 -0
  141. package/lib/module/plugins/index.js +4 -0
  142. package/lib/module/plugins/index.js.map +1 -0
  143. package/lib/module/types/index.js +2 -0
  144. package/lib/module/types/index.js.map +1 -0
  145. package/lib/module/types/plugin.js +2 -0
  146. package/lib/module/types/plugin.js.map +1 -0
  147. package/lib/module/types/skeleton.js +2 -0
  148. package/lib/module/types/skeleton.js.map +1 -0
  149. package/lib/module/utils/componentUtils.js +123 -0
  150. package/lib/module/utils/componentUtils.js.map +1 -0
  151. package/lib/module/utils/index.js +3 -0
  152. package/lib/module/utils/index.js.map +1 -0
  153. package/lib/module/utils/styleUtils.js +66 -0
  154. package/lib/module/utils/styleUtils.js.map +1 -0
  155. package/lib/typescript/Skelo.d.ts +76 -0
  156. package/lib/typescript/Skelo.d.ts.map +1 -0
  157. package/lib/typescript/animations/AnimationWrapper.d.ts +66 -0
  158. package/lib/typescript/animations/AnimationWrapper.d.ts.map +1 -0
  159. package/lib/typescript/animations/PulseAnimation.d.ts +15 -0
  160. package/lib/typescript/animations/PulseAnimation.d.ts.map +1 -0
  161. package/lib/typescript/animations/ShimmerAnimation.d.ts +15 -0
  162. package/lib/typescript/animations/ShimmerAnimation.d.ts.map +1 -0
  163. package/lib/typescript/animations/index.d.ts +5 -0
  164. package/lib/typescript/animations/index.d.ts.map +1 -0
  165. package/lib/typescript/components/MeasuredBlock.d.ts +32 -0
  166. package/lib/typescript/components/MeasuredBlock.d.ts.map +1 -0
  167. package/lib/typescript/components/Skeleton.d.ts +37 -0
  168. package/lib/typescript/components/Skeleton.d.ts.map +1 -0
  169. package/lib/typescript/components/SkeletonIgnore.d.ts +26 -0
  170. package/lib/typescript/components/SkeletonIgnore.d.ts.map +1 -0
  171. package/lib/typescript/components/SkeletonRenderer.d.ts +39 -0
  172. package/lib/typescript/components/SkeletonRenderer.d.ts.map +1 -0
  173. package/lib/typescript/components/primitives/SkeletonBox.d.ts +21 -0
  174. package/lib/typescript/components/primitives/SkeletonBox.d.ts.map +1 -0
  175. package/lib/typescript/components/primitives/SkeletonCircle.d.ts +21 -0
  176. package/lib/typescript/components/primitives/SkeletonCircle.d.ts.map +1 -0
  177. package/lib/typescript/components/primitives/SkeletonImage.d.ts +21 -0
  178. package/lib/typescript/components/primitives/SkeletonImage.d.ts.map +1 -0
  179. package/lib/typescript/components/primitives/SkeletonText.d.ts +21 -0
  180. package/lib/typescript/components/primitives/SkeletonText.d.ts.map +1 -0
  181. package/lib/typescript/components/primitives/index.d.ts +5 -0
  182. package/lib/typescript/components/primitives/index.d.ts.map +1 -0
  183. package/lib/typescript/components/withSkeleton.d.ts +37 -0
  184. package/lib/typescript/components/withSkeleton.d.ts.map +1 -0
  185. package/lib/typescript/constants/defaults.d.ts +29 -0
  186. package/lib/typescript/constants/defaults.d.ts.map +1 -0
  187. package/lib/typescript/core/deepRegistry.d.ts +7 -0
  188. package/lib/typescript/core/deepRegistry.d.ts.map +1 -0
  189. package/lib/typescript/core/generator/StyleSkeleton.d.ts +36 -0
  190. package/lib/typescript/core/generator/StyleSkeleton.d.ts.map +1 -0
  191. package/lib/typescript/core/parser/Parser.d.ts +30 -0
  192. package/lib/typescript/core/parser/Parser.d.ts.map +1 -0
  193. package/lib/typescript/core/parser/expandOffline.d.ts +10 -0
  194. package/lib/typescript/core/parser/expandOffline.d.ts.map +1 -0
  195. package/lib/typescript/core/parser/hostTreeReconciler.d.ts +28 -0
  196. package/lib/typescript/core/parser/hostTreeReconciler.d.ts.map +1 -0
  197. package/lib/typescript/core/parser/index.d.ts +2 -0
  198. package/lib/typescript/core/parser/index.d.ts.map +1 -0
  199. package/lib/typescript/core/registry/SkeletonRegistry.d.ts +57 -0
  200. package/lib/typescript/core/registry/SkeletonRegistry.d.ts.map +1 -0
  201. package/lib/typescript/core/registry/index.d.ts +2 -0
  202. package/lib/typescript/core/registry/index.d.ts.map +1 -0
  203. package/lib/typescript/core/resolver/StyleResolver.d.ts +54 -0
  204. package/lib/typescript/core/resolver/StyleResolver.d.ts.map +1 -0
  205. package/lib/typescript/core/resolver/index.d.ts +2 -0
  206. package/lib/typescript/core/resolver/index.d.ts.map +1 -0
  207. package/lib/typescript/deep.d.ts +2 -0
  208. package/lib/typescript/deep.d.ts.map +1 -0
  209. package/lib/typescript/index.d.ts +17 -0
  210. package/lib/typescript/index.d.ts.map +1 -0
  211. package/lib/typescript/plugins/ImagePlugin.d.ts +11 -0
  212. package/lib/typescript/plugins/ImagePlugin.d.ts.map +1 -0
  213. package/lib/typescript/plugins/TextPlugin.d.ts +12 -0
  214. package/lib/typescript/plugins/TextPlugin.d.ts.map +1 -0
  215. package/lib/typescript/plugins/ViewPlugin.d.ts +11 -0
  216. package/lib/typescript/plugins/ViewPlugin.d.ts.map +1 -0
  217. package/lib/typescript/plugins/index.d.ts +4 -0
  218. package/lib/typescript/plugins/index.d.ts.map +1 -0
  219. package/lib/typescript/types/index.d.ts +3 -0
  220. package/lib/typescript/types/index.d.ts.map +1 -0
  221. package/lib/typescript/types/plugin.d.ts +144 -0
  222. package/lib/typescript/types/plugin.d.ts.map +1 -0
  223. package/lib/typescript/types/skeleton.d.ts +176 -0
  224. package/lib/typescript/types/skeleton.d.ts.map +1 -0
  225. package/lib/typescript/utils/componentUtils.d.ts +40 -0
  226. package/lib/typescript/utils/componentUtils.d.ts.map +1 -0
  227. package/lib/typescript/utils/index.d.ts +3 -0
  228. package/lib/typescript/utils/index.d.ts.map +1 -0
  229. package/lib/typescript/utils/styleUtils.d.ts +41 -0
  230. package/lib/typescript/utils/styleUtils.d.ts.map +1 -0
  231. package/package.json +169 -11
  232. package/src/Skelo.ts +103 -0
  233. package/src/animations/AnimationWrapper.tsx +139 -0
  234. package/src/animations/PulseAnimation.tsx +76 -0
  235. package/src/animations/ShimmerAnimation.tsx +101 -0
  236. package/src/animations/index.ts +4 -0
  237. package/src/components/MeasuredBlock.tsx +85 -0
  238. package/src/components/Skeleton.tsx +149 -0
  239. package/src/components/SkeletonIgnore.tsx +27 -0
  240. package/src/components/SkeletonRenderer.tsx +341 -0
  241. package/src/components/primitives/SkeletonBox.tsx +53 -0
  242. package/src/components/primitives/SkeletonCircle.tsx +48 -0
  243. package/src/components/primitives/SkeletonImage.tsx +50 -0
  244. package/src/components/primitives/SkeletonText.tsx +69 -0
  245. package/src/components/primitives/index.ts +4 -0
  246. package/src/components/withSkeleton.tsx +62 -0
  247. package/src/constants/defaults.ts +38 -0
  248. package/src/core/deepRegistry.ts +16 -0
  249. package/src/core/generator/StyleSkeleton.tsx +138 -0
  250. package/src/core/parser/Parser.ts +86 -0
  251. package/src/core/parser/expandOffline.tsx +83 -0
  252. package/src/core/parser/hostTreeReconciler.tsx +271 -0
  253. package/src/core/parser/index.ts +1 -0
  254. package/src/core/registry/SkeletonRegistry.ts +111 -0
  255. package/src/core/registry/index.ts +1 -0
  256. package/src/core/resolver/StyleResolver.ts +80 -0
  257. package/src/core/resolver/index.ts +1 -0
  258. package/src/deep.ts +12 -0
  259. package/src/index.ts +30 -0
  260. package/src/plugins/ImagePlugin.tsx +65 -0
  261. package/src/plugins/TextPlugin.tsx +71 -0
  262. package/src/plugins/ViewPlugin.tsx +67 -0
  263. package/src/plugins/index.ts +3 -0
  264. package/src/types/index.ts +14 -0
  265. package/src/types/plugin.ts +164 -0
  266. package/src/types/skeleton.ts +197 -0
  267. package/src/utils/componentUtils.ts +166 -0
  268. package/src/utils/index.ts +9 -0
  269. package/src/utils/styleUtils.ts +72 -0
@@ -0,0 +1,67 @@
1
+ import React from 'react';
2
+ import { View } from 'react-native';
3
+ import type { SkeletonPlugin } from '../types';
4
+ import type { ViewProps } from 'react-native';
5
+
6
+ /**
7
+ * Built-in plugin for React Native View component
8
+ *
9
+ * Renders View as:
10
+ * - SkeletonBox if has explicit width/height
11
+ * - Container with parsed children otherwise
12
+ */
13
+ export const ViewPlugin: SkeletonPlugin<ViewProps> = {
14
+ name: 'View',
15
+ component: View,
16
+ version: '1.0.0',
17
+
18
+ strategy: (props, context) => {
19
+ const { primitives, parseChildren, config } = context;
20
+ const style = props.style || {};
21
+ const flatStyle = Array.isArray(style) ? Object.assign({}, ...style) : style;
22
+
23
+ const width = flatStyle.width;
24
+ const height = flatStyle.height;
25
+ const borderRadius = flatStyle.borderRadius ?? config.borderRadius;
26
+
27
+ // If View has explicit dimensions, render as box
28
+ if (width && height) {
29
+ return (
30
+ <primitives.Box
31
+ width={width}
32
+ height={height}
33
+ borderRadius={borderRadius}
34
+ animation={config.animation}
35
+ baseColor={config.baseColor}
36
+ highlightColor={config.highlightColor}
37
+ duration={config.duration}
38
+ style={flatStyle}
39
+ />
40
+ );
41
+ }
42
+
43
+ // If View has children, render as container
44
+ if (props.children) {
45
+ return <View style={flatStyle}>{parseChildren(props.children)}</View>;
46
+ }
47
+
48
+ // Empty View - render as small placeholder
49
+ return (
50
+ <primitives.Box
51
+ width={width ?? 100}
52
+ height={height ?? 20}
53
+ borderRadius={borderRadius}
54
+ animation={config.animation}
55
+ baseColor={config.baseColor}
56
+ highlightColor={config.highlightColor}
57
+ duration={config.duration}
58
+ style={flatStyle}
59
+ />
60
+ );
61
+ },
62
+
63
+ metadata: {
64
+ description: 'Automatic skeleton generation for View components',
65
+ author: 'Skelo',
66
+ },
67
+ };
@@ -0,0 +1,3 @@
1
+ export { ViewPlugin } from './ViewPlugin';
2
+ export { TextPlugin } from './TextPlugin';
3
+ export { ImagePlugin } from './ImagePlugin';
@@ -0,0 +1,14 @@
1
+ export type { SkeletonProps, SkeletonConfig, ResolvedStyle, ComponentNode } from './skeleton';
2
+
3
+ export type {
4
+ SkeletonPlugin,
5
+ SkeletonStrategy,
6
+ SkeletonContext,
7
+ SkeletonPrimitives,
8
+ SkeletonUtils,
9
+ PluginMetadata,
10
+ BoxProps,
11
+ TextProps,
12
+ ImageProps,
13
+ CircleProps,
14
+ } from './plugin';
@@ -0,0 +1,164 @@
1
+ import type { ComponentType, ReactElement, ReactNode } from 'react';
2
+ import type { DimensionValue } from 'react-native';
3
+ import type { SkeletonConfig, ResolvedStyle } from './skeleton';
4
+
5
+ /**
6
+ * Plugin for custom component skeleton generation
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * const AvatarPlugin: SkeletonPlugin<AvatarProps> = {
11
+ * name: 'Avatar',
12
+ * component: Avatar,
13
+ * strategy: (props, { primitives }) => {
14
+ * return <primitives.Circle size={props.size || 40} />;
15
+ * },
16
+ * };
17
+ * ```
18
+ */
19
+ export interface SkeletonPlugin<P = any> {
20
+ /**
21
+ * Unique identifier for the plugin
22
+ */
23
+ name: string;
24
+
25
+ /**
26
+ * Component type this plugin handles
27
+ */
28
+ component: ComponentType<P>;
29
+
30
+ /**
31
+ * Strategy function to generate skeleton
32
+ */
33
+ strategy: SkeletonStrategy<P>;
34
+
35
+ /**
36
+ * Optional: Plugin version
37
+ */
38
+ version?: string;
39
+
40
+ /**
41
+ * Optional: Plugin metadata
42
+ */
43
+ metadata?: PluginMetadata;
44
+ }
45
+
46
+ /**
47
+ * Strategy function signature
48
+ */
49
+ export type SkeletonStrategy<P = any> = (props: P, context: SkeletonContext) => ReactElement | null;
50
+
51
+ /**
52
+ * Context provided to plugin strategies
53
+ */
54
+ export interface SkeletonContext {
55
+ /**
56
+ * Configuration from parent Skeleton component
57
+ */
58
+ config: SkeletonConfig;
59
+
60
+ /**
61
+ * Theme information (light/dark)
62
+ */
63
+ theme: 'light' | 'dark';
64
+
65
+ /**
66
+ * Recursively parse children
67
+ */
68
+ parseChildren: (children: ReactNode) => ReactNode;
69
+
70
+ /**
71
+ * Access to skeleton primitives
72
+ */
73
+ primitives: SkeletonPrimitives;
74
+
75
+ /**
76
+ * Utility functions
77
+ */
78
+ utils: SkeletonUtils;
79
+ }
80
+
81
+ /**
82
+ * Skeleton primitive components
83
+ */
84
+ export interface SkeletonPrimitives {
85
+ Box: ComponentType<BoxProps>;
86
+ Text: ComponentType<TextProps>;
87
+ Image: ComponentType<ImageProps>;
88
+ Circle: ComponentType<CircleProps>;
89
+ }
90
+
91
+ /**
92
+ * Utility functions for plugins
93
+ */
94
+ export interface SkeletonUtils {
95
+ /**
96
+ * Flatten and resolve styles
97
+ */
98
+ resolveStyle: (style: any) => ResolvedStyle;
99
+
100
+ /**
101
+ * Extract dimensions from a resolved style
102
+ */
103
+ extractDimensions: (style: ResolvedStyle) => {
104
+ width?: DimensionValue;
105
+ height?: DimensionValue;
106
+ };
107
+
108
+ /**
109
+ * Generate random width for natural look
110
+ */
111
+ randomWidth: (min?: number, max?: number) => string;
112
+ }
113
+
114
+ /**
115
+ * Plugin metadata
116
+ */
117
+ export interface PluginMetadata {
118
+ author?: string;
119
+ description?: string;
120
+ repository?: string;
121
+ license?: string;
122
+ }
123
+
124
+ /**
125
+ * Animation and color props shared by all skeleton primitives
126
+ */
127
+ export interface SkeletonAnimationProps {
128
+ animation?: 'shimmer' | 'pulse' | 'none';
129
+ baseColor?: string;
130
+ highlightColor?: string;
131
+ duration?: number;
132
+ }
133
+
134
+ /**
135
+ * Props for skeleton primitives
136
+ */
137
+ export interface BoxProps extends SkeletonAnimationProps {
138
+ width?: DimensionValue;
139
+ height?: DimensionValue;
140
+ borderRadius?: number;
141
+ style?: any;
142
+ children?: ReactNode;
143
+ }
144
+
145
+ export interface TextProps extends SkeletonAnimationProps {
146
+ lines?: number;
147
+ fontSize?: number;
148
+ lineHeight?: number;
149
+ width?: DimensionValue;
150
+ lastLineWidth?: DimensionValue;
151
+ style?: any;
152
+ }
153
+
154
+ export interface ImageProps extends SkeletonAnimationProps {
155
+ width?: DimensionValue;
156
+ height?: DimensionValue;
157
+ borderRadius?: number;
158
+ style?: any;
159
+ }
160
+
161
+ export interface CircleProps extends SkeletonAnimationProps {
162
+ size?: number;
163
+ style?: any;
164
+ }
@@ -0,0 +1,197 @@
1
+ import type { ReactElement, ReactNode } from 'react';
2
+ import type { DimensionValue, FlexAlignType } from 'react-native';
3
+
4
+ /**
5
+ * Props for the main Skeleton component
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * <Skeleton loading={true} animation="shimmer">
10
+ * <YourComponent />
11
+ * </Skeleton>
12
+ * ```
13
+ */
14
+ export interface SkeletonProps {
15
+ /**
16
+ * Whether to show skeleton (true) or actual content (false)
17
+ */
18
+ loading: boolean;
19
+
20
+ /**
21
+ * Animation type
22
+ * - 'shimmer': Moving gradient animation (default)
23
+ * - 'pulse': Fade in/out animation
24
+ * - 'none': Static skeleton
25
+ *
26
+ * @default 'shimmer'
27
+ */
28
+ animation?: 'shimmer' | 'pulse' | 'none';
29
+
30
+ /**
31
+ * Animation duration in milliseconds
32
+ * @default 1200
33
+ */
34
+ duration?: number;
35
+
36
+ /**
37
+ * Base skeleton color
38
+ * @default Auto-detected based on color scheme (light/dark)
39
+ */
40
+ baseColor?: string;
41
+
42
+ /**
43
+ * Shimmer highlight color
44
+ * @default Auto-detected based on color scheme (light/dark)
45
+ */
46
+ highlightColor?: string;
47
+
48
+ /**
49
+ * Default border radius for skeleton elements
50
+ * @default 4
51
+ */
52
+ borderRadius?: number;
53
+
54
+ /**
55
+ * Components to render.
56
+ *
57
+ * When `styles` is provided, `children` is optional — the skeleton is derived
58
+ * from the styles instead of the child tree.
59
+ */
60
+ children?: ReactNode;
61
+
62
+ /**
63
+ * Generate the skeleton directly from a set of styles instead of from the
64
+ * child element tree. Accepts a `StyleSheet.create` object (values used in
65
+ * definition order) or an array of styles.
66
+ *
67
+ * Because a StyleSheet has no hierarchy, the result is a vertical stack of
68
+ * skeleton shapes — one per style that has visual dimensions.
69
+ *
70
+ * @example
71
+ * ```tsx
72
+ * <Skeleton loading={loading} styles={styles} />
73
+ * ```
74
+ */
75
+ styles?: Record<string, unknown> | unknown[];
76
+
77
+ /**
78
+ * When using `styles`, style keys to skip (e.g. layout containers).
79
+ */
80
+ excludeStyles?: string[];
81
+
82
+ /**
83
+ * Deep mode: expand opaque (custom) child components into their real
84
+ * host-element tree via offline rendering, producing a structured skeleton
85
+ * without inlining host elements.
86
+ *
87
+ * @experimental Renders the children offline to introspect them, so their
88
+ * mount effects run during expansion and they render outside your app's
89
+ * providers (navigation/theme/redux). Best for presentational trees; guard
90
+ * effectful/context-dependent screens or register a plugin for them. Falls
91
+ * back to static parsing if offline rendering is unavailable or fails.
92
+ * Requires `react-reconciler` to be installed.
93
+ *
94
+ * @default false
95
+ */
96
+ deep?: boolean;
97
+
98
+ /**
99
+ * Enable accessibility features
100
+ * @default true
101
+ */
102
+ accessible?: boolean;
103
+
104
+ /**
105
+ * Screen reader label
106
+ * @default "Loading content"
107
+ */
108
+ accessibilityLabel?: string;
109
+
110
+ /**
111
+ * Debug mode (development only)
112
+ * Shows component boundaries and names
113
+ * @default false
114
+ */
115
+ debug?: boolean;
116
+ }
117
+
118
+ /**
119
+ * Configuration options for SkeletonProvider
120
+ */
121
+ export interface SkeletonConfig {
122
+ /**
123
+ * Default animation type
124
+ * @default 'shimmer'
125
+ */
126
+ animation?: 'shimmer' | 'pulse' | 'none';
127
+
128
+ /**
129
+ * Default animation duration in milliseconds
130
+ * @default 1200
131
+ */
132
+ duration?: number;
133
+
134
+ /**
135
+ * Default base color
136
+ */
137
+ baseColor?: string;
138
+
139
+ /**
140
+ * Default highlight color
141
+ */
142
+ highlightColor?: string;
143
+
144
+ /**
145
+ * Default border radius
146
+ * @default 4
147
+ */
148
+ borderRadius?: number;
149
+
150
+ /**
151
+ * Enable debug mode globally
152
+ * @default false
153
+ */
154
+ debug?: boolean;
155
+ }
156
+
157
+ /**
158
+ * Resolved style properties extracted from React Native styles
159
+ */
160
+ export interface ResolvedStyle {
161
+ width?: DimensionValue;
162
+ height?: DimensionValue;
163
+ borderRadius?: number;
164
+ backgroundColor?: string;
165
+ fontSize?: number;
166
+ lineHeight?: number;
167
+ marginTop?: number;
168
+ marginBottom?: number;
169
+ marginLeft?: number;
170
+ marginRight?: number;
171
+ paddingTop?: number;
172
+ paddingBottom?: number;
173
+ paddingLeft?: number;
174
+ paddingRight?: number;
175
+ flexDirection?: 'row' | 'column';
176
+ alignItems?: FlexAlignType;
177
+ justifyContent?:
178
+ 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly';
179
+ }
180
+
181
+ /**
182
+ * Parsed component node in the tree
183
+ */
184
+ export interface ComponentNode {
185
+ type: string;
186
+ props: any;
187
+ style: ResolvedStyle;
188
+ children: ComponentNode[];
189
+ /**
190
+ * The original React element this node was parsed from.
191
+ *
192
+ * Retained so the renderer can fall back to rendering-and-measuring the
193
+ * real element when it is an opaque (non-host) component the parser can't
194
+ * introspect. Excluded from debug serialization.
195
+ */
196
+ element?: ReactElement;
197
+ }
@@ -0,0 +1,166 @@
1
+ import React, { isValidElement } from 'react';
2
+ import type { ReactElement, ReactNode } from 'react';
3
+ import {
4
+ View,
5
+ Text,
6
+ Image,
7
+ ImageBackground,
8
+ ScrollView,
9
+ SafeAreaView,
10
+ FlatList,
11
+ SectionList,
12
+ VirtualizedList,
13
+ TouchableOpacity,
14
+ TouchableHighlight,
15
+ TouchableWithoutFeedback,
16
+ Pressable,
17
+ KeyboardAvoidingView,
18
+ } from 'react-native';
19
+
20
+ // Re-exported so consumers can access it from the skelo utils surface
21
+ export { isValidElement };
22
+
23
+ /**
24
+ * Reference map of React Native host components to their canonical names.
25
+ *
26
+ * Modern RN components (View/Text/Image/...) are `forwardRef`/`memo` objects,
27
+ * not plain functions or strings, so name/displayName sniffing is unreliable.
28
+ * Identifying them by reference is exact. This works across the library/app
29
+ * module boundary because Metro resolves a single `react-native` instance.
30
+ */
31
+ const RN_COMPONENT_NAMES = new Map<unknown, string>([
32
+ [View, 'View'],
33
+ [Text, 'Text'],
34
+ [Image, 'Image'],
35
+ [ImageBackground, 'ImageBackground'],
36
+ [ScrollView, 'ScrollView'],
37
+ [SafeAreaView, 'SafeAreaView'],
38
+ [FlatList, 'FlatList'],
39
+ [SectionList, 'SectionList'],
40
+ [VirtualizedList, 'VirtualizedList'],
41
+ [TouchableOpacity, 'TouchableOpacity'],
42
+ [TouchableHighlight, 'TouchableHighlight'],
43
+ [TouchableWithoutFeedback, 'TouchableWithoutFeedback'],
44
+ [Pressable, 'Pressable'],
45
+ [KeyboardAvoidingView, 'KeyboardAvoidingView'],
46
+ ]);
47
+
48
+ /**
49
+ * Get component display name or type name
50
+ *
51
+ * @param element - React element
52
+ * @returns Component name as string
53
+ */
54
+ export function getComponentName(element: ReactElement): string {
55
+ const type: unknown = element.type;
56
+
57
+ if (type === React.Fragment) {
58
+ return 'Fragment';
59
+ }
60
+
61
+ // Exact identification of RN host components (forwardRef/memo objects).
62
+ const mapped = RN_COMPONENT_NAMES.get(type);
63
+ if (mapped) {
64
+ return mapped;
65
+ }
66
+
67
+ // Intrinsic host string (e.g. web/DOM or raw native tags).
68
+ if (typeof type === 'string') {
69
+ return type;
70
+ }
71
+
72
+ // Plain function/class components.
73
+ if (typeof type === 'function') {
74
+ const fn = type as { displayName?: string; name?: string };
75
+ return fn.displayName || fn.name || 'Anonymous';
76
+ }
77
+
78
+ // forwardRef / memo wrappers: unwrap to find a usable name.
79
+ if (typeof type === 'object' && type !== null) {
80
+ const obj = type as {
81
+ displayName?: string;
82
+ render?: { displayName?: string; name?: string };
83
+ type?: unknown;
84
+ };
85
+ if (obj.displayName) {
86
+ return obj.displayName;
87
+ }
88
+ if (obj.render) {
89
+ return obj.render.displayName || obj.render.name || 'Anonymous';
90
+ }
91
+ // memo(Component) nests the real component under `.type`.
92
+ if (obj.type) {
93
+ return getComponentName({ type: obj.type } as ReactElement);
94
+ }
95
+ return 'Anonymous';
96
+ }
97
+
98
+ return 'Unknown';
99
+ }
100
+
101
+ /**
102
+ * Check if element is a React Fragment
103
+ *
104
+ * @param element - React element
105
+ * @returns True if element is a Fragment
106
+ */
107
+ export function isFragment(element: ReactElement): boolean {
108
+ return element.type === React.Fragment;
109
+ }
110
+
111
+ /**
112
+ * Flatten children, handling Fragments recursively
113
+ *
114
+ * @param children - React children
115
+ * @returns Flattened array of children
116
+ */
117
+ export function flattenChildren(children: ReactNode): ReactNode[] {
118
+ const result: ReactNode[] = [];
119
+
120
+ React.Children.forEach(children, child => {
121
+ if (!isValidElement(child)) {
122
+ result.push(child);
123
+ return;
124
+ }
125
+
126
+ if (isFragment(child)) {
127
+ // Recursively flatten fragment children
128
+ const fragmentChildren = flattenChildren(child.props.children);
129
+ result.push(...fragmentChildren);
130
+ } else {
131
+ result.push(child);
132
+ }
133
+ });
134
+
135
+ return result;
136
+ }
137
+
138
+ /**
139
+ * Check if component is a touchable component
140
+ *
141
+ * @param element - React element
142
+ * @returns True if component is touchable
143
+ */
144
+ export function isTouchableComponent(element: ReactElement): boolean {
145
+ const name = getComponentName(element);
146
+ const touchableTypes = [
147
+ 'TouchableOpacity',
148
+ 'TouchableHighlight',
149
+ 'TouchableWithoutFeedback',
150
+ 'TouchableNativeFeedback',
151
+ 'Pressable',
152
+ ];
153
+ return touchableTypes.includes(name);
154
+ }
155
+
156
+ /**
157
+ * Generate random width percentage for natural skeleton look
158
+ *
159
+ * @param min - Minimum percentage (0-100)
160
+ * @param max - Maximum percentage (0-100)
161
+ * @returns Random percentage as string (e.g., "75%")
162
+ */
163
+ export function randomWidth(min: number = 60, max: number = 90): string {
164
+ const random = Math.floor(Math.random() * (max - min + 1)) + min;
165
+ return `${random}%`;
166
+ }
@@ -0,0 +1,9 @@
1
+ export { resolveStyle, extractDimensions, isPercentage, percentageToNumber } from './styleUtils';
2
+
3
+ export {
4
+ getComponentName,
5
+ isFragment,
6
+ flattenChildren,
7
+ isTouchableComponent,
8
+ randomWidth,
9
+ } from './componentUtils';
@@ -0,0 +1,72 @@
1
+ import { StyleSheet } from 'react-native';
2
+ import type { DimensionValue } from 'react-native';
3
+ import type { ResolvedStyle } from '../types';
4
+
5
+ /**
6
+ * Flatten and resolve styles from React Native style prop
7
+ *
8
+ * @param style - Style prop (can be object, array, or StyleSheet reference)
9
+ * @returns Flattened style object
10
+ */
11
+ export function resolveStyle(style: any): ResolvedStyle {
12
+ if (!style) {
13
+ return {};
14
+ }
15
+
16
+ try {
17
+ const flattened = StyleSheet.flatten(style);
18
+ return flattened as ResolvedStyle;
19
+ } catch (error) {
20
+ // Handle invalid styles gracefully
21
+ if (__DEV__) {
22
+ console.warn('[Skelo] Failed to resolve style:', error);
23
+ }
24
+ return {};
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Extract dimensions from resolved style
30
+ *
31
+ * @param style - Resolved style object
32
+ * @returns Object with width and height (if present)
33
+ */
34
+ export function extractDimensions(style: ResolvedStyle): {
35
+ width?: DimensionValue;
36
+ height?: DimensionValue;
37
+ } {
38
+ return {
39
+ width: style.width,
40
+ height: style.height,
41
+ };
42
+ }
43
+
44
+ /**
45
+ * Check if a resolved style declares both an explicit width and height
46
+ *
47
+ * @param style - Resolved style object
48
+ * @returns True if both width and height are defined
49
+ */
50
+ export function hasExplicitSize(style: ResolvedStyle): boolean {
51
+ return style.width !== undefined && style.height !== undefined;
52
+ }
53
+
54
+ /**
55
+ * Check if a value is a percentage string
56
+ *
57
+ * @param value - Value to check
58
+ * @returns True if value is a percentage string
59
+ */
60
+ export function isPercentage(value: any): boolean {
61
+ return typeof value === 'string' && value.includes('%');
62
+ }
63
+
64
+ /**
65
+ * Convert percentage to number (strips %)
66
+ *
67
+ * @param value - Percentage string (e.g., "50%")
68
+ * @returns Number without % sign
69
+ */
70
+ export function percentageToNumber(value: string): number {
71
+ return parseFloat(value.replace('%', ''));
72
+ }