react-native-skelo 0.0.1 → 0.0.2

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 +147 -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 +76 -0
  8. package/lib/commonjs/animations/PulseAnimation.js.map +1 -0
  9. package/lib/commonjs/animations/ShimmerAnimation.js +103 -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 +69 -0
  84. package/lib/module/animations/PulseAnimation.js.map +1 -0
  85. package/lib/module/animations/ShimmerAnimation.js +96 -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 +59 -0
  160. package/lib/typescript/animations/PulseAnimation.d.ts.map +1 -0
  161. package/lib/typescript/animations/ShimmerAnimation.d.ts +59 -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 +171 -11
  232. package/src/Skelo.ts +103 -0
  233. package/src/animations/AnimationWrapper.tsx +139 -0
  234. package/src/animations/PulseAnimation.tsx +138 -0
  235. package/src/animations/ShimmerAnimation.tsx +169 -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,80 @@
1
+ import type { ReactElement } from 'react';
2
+ import type { DimensionValue } from 'react-native';
3
+ import type { ResolvedStyle } from '../../types';
4
+ import { resolveStyle, extractDimensions } from '../../utils';
5
+
6
+ /**
7
+ * StyleResolver class for extracting and resolving component styles
8
+ */
9
+ export class StyleResolver {
10
+ /**
11
+ * Resolve styles from a React element
12
+ *
13
+ * @param element - React element
14
+ * @returns Resolved style object
15
+ */
16
+ static resolve(element: ReactElement): ResolvedStyle {
17
+ const props = element.props || {};
18
+ const style = props.style;
19
+
20
+ return resolveStyle(style);
21
+ }
22
+
23
+ /**
24
+ * Get dimensions from element props and style
25
+ *
26
+ * @param element - React element
27
+ * @returns Object with width and height
28
+ */
29
+ static getDimensions(element: ReactElement): {
30
+ width?: DimensionValue;
31
+ height?: DimensionValue;
32
+ } {
33
+ const style = this.resolve(element);
34
+ return extractDimensions(style);
35
+ }
36
+
37
+ /**
38
+ * Check if element has explicit dimensions
39
+ *
40
+ * @param element - React element
41
+ * @returns True if both width and height are defined
42
+ */
43
+ static hasExplicitDimensions(element: ReactElement): boolean {
44
+ const { width, height } = this.getDimensions(element);
45
+ return width !== undefined && height !== undefined;
46
+ }
47
+
48
+ /**
49
+ * Get border radius from style
50
+ *
51
+ * @param element - React element
52
+ * @returns Border radius value or undefined
53
+ */
54
+ static getBorderRadius(element: ReactElement): number | undefined {
55
+ const style = this.resolve(element);
56
+ return style.borderRadius;
57
+ }
58
+
59
+ /**
60
+ * Get font size from style
61
+ *
62
+ * @param element - React element
63
+ * @returns Font size value or undefined
64
+ */
65
+ static getFontSize(element: ReactElement): number | undefined {
66
+ const style = this.resolve(element);
67
+ return style.fontSize;
68
+ }
69
+
70
+ /**
71
+ * Get line height from style
72
+ *
73
+ * @param element - React element
74
+ * @returns Line height value or undefined
75
+ */
76
+ static getLineHeight(element: ReactElement): number | undefined {
77
+ const style = this.resolve(element);
78
+ return style.lineHeight;
79
+ }
80
+ }
@@ -0,0 +1 @@
1
+ export { StyleResolver } from './StyleResolver';
package/src/deep.ts ADDED
@@ -0,0 +1,12 @@
1
+ // Opt-in deep mode. Import once in your app entry to enable `<Skeleton deep>`:
2
+ //
3
+ // import 'react-native-skelo/deep';
4
+ //
5
+ // This is the only module that pulls in react-reconciler, so apps that don't
6
+ // use deep mode never bundle it. Requires `react-reconciler` to be installed.
7
+ import { setDeepExpander } from './core/deepRegistry';
8
+ import { expandToComponentNodes } from './core/parser/expandOffline';
9
+
10
+ setDeepExpander(expandToComponentNodes);
11
+
12
+ export const deepEnabled = true;
package/src/index.ts ADDED
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Skelo - Automatic skeleton loading for React Native
3
+ *
4
+ * Write your UI once. Skelo builds the loading state automatically.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+
9
+ // Main component
10
+ export { Skeleton } from './components/Skeleton';
11
+ export { SkeletonIgnore } from './components/SkeletonIgnore';
12
+ export { withSkeleton } from './components/withSkeleton';
13
+ export type { WithSkeletonOptions } from './components/withSkeleton';
14
+ export { StyleSkeleton } from './core/generator/StyleSkeleton';
15
+ export type { StyleInput } from './core/generator/StyleSkeleton';
16
+
17
+ // Global API
18
+ export { Skelo } from './Skelo';
19
+
20
+ // Types
21
+ export type {
22
+ SkeletonProps,
23
+ SkeletonConfig,
24
+ SkeletonPlugin,
25
+ SkeletonStrategy,
26
+ SkeletonContext,
27
+ } from './types';
28
+
29
+ // Primitives (for plugin development)
30
+ export { SkeletonBox, SkeletonText, SkeletonImage, SkeletonCircle } from './components/primitives';
@@ -0,0 +1,65 @@
1
+ import React from 'react';
2
+ import { Image } from 'react-native';
3
+ import type { SkeletonPlugin } from '../types';
4
+ import type { ImageProps } from 'react-native';
5
+
6
+ /**
7
+ * Built-in plugin for React Native Image component
8
+ *
9
+ * Renders Image as:
10
+ * - SkeletonCircle if circular (avatar-like)
11
+ * - SkeletonImage otherwise
12
+ */
13
+ export const ImagePlugin: SkeletonPlugin<ImageProps> = {
14
+ name: 'Image',
15
+ component: Image,
16
+ version: '1.0.0',
17
+
18
+ strategy: (props, context) => {
19
+ const { primitives, config } = context;
20
+ const style = props.style || {};
21
+ const flatStyle = Array.isArray(style) ? Object.assign({}, ...style) : style;
22
+
23
+ const width = flatStyle.width ?? 100;
24
+ const height = flatStyle.height ?? 100;
25
+ const borderRadius = flatStyle.borderRadius ?? 0;
26
+
27
+ // Check if it's a circular image (avatar)
28
+ const isCircle =
29
+ typeof width === 'number' &&
30
+ typeof height === 'number' &&
31
+ width === height &&
32
+ borderRadius === width / 2;
33
+
34
+ if (isCircle) {
35
+ return (
36
+ <primitives.Circle
37
+ size={width as number}
38
+ animation={config.animation}
39
+ baseColor={config.baseColor}
40
+ highlightColor={config.highlightColor}
41
+ duration={config.duration}
42
+ style={flatStyle}
43
+ />
44
+ );
45
+ }
46
+
47
+ return (
48
+ <primitives.Image
49
+ width={width}
50
+ height={height}
51
+ borderRadius={borderRadius as number}
52
+ animation={config.animation}
53
+ baseColor={config.baseColor}
54
+ highlightColor={config.highlightColor}
55
+ duration={config.duration}
56
+ style={flatStyle}
57
+ />
58
+ );
59
+ },
60
+
61
+ metadata: {
62
+ description: 'Automatic skeleton generation for Image components',
63
+ author: 'Skelo',
64
+ },
65
+ };
@@ -0,0 +1,71 @@
1
+ import React from 'react';
2
+ import { Text } from 'react-native';
3
+ import type { SkeletonPlugin } from '../types';
4
+ import type { TextProps } from 'react-native';
5
+
6
+ /**
7
+ * Built-in plugin for React Native Text component
8
+ *
9
+ * Renders Text as SkeletonText with:
10
+ * - Estimated line count from text content
11
+ * - Font size from style
12
+ * - Line height from style
13
+ */
14
+ export const TextPlugin: SkeletonPlugin<TextProps> = {
15
+ name: 'Text',
16
+ component: Text,
17
+ version: '1.0.0',
18
+
19
+ strategy: (props, context) => {
20
+ const { primitives, config } = context;
21
+ const style = props.style || {};
22
+ const flatStyle = Array.isArray(style) ? Object.assign({}, ...style) : style;
23
+
24
+ const fontSize = flatStyle.fontSize ?? 14;
25
+ const lineHeight = flatStyle.lineHeight ?? fontSize * 1.4;
26
+
27
+ // Estimate number of lines from text content
28
+ const textContent = props.children;
29
+ const estimatedLines = estimateTextLines(textContent);
30
+
31
+ return (
32
+ <primitives.Text
33
+ lines={estimatedLines}
34
+ fontSize={fontSize}
35
+ lineHeight={lineHeight}
36
+ width={flatStyle.width ?? '100%'}
37
+ animation={config.animation}
38
+ baseColor={config.baseColor}
39
+ highlightColor={config.highlightColor}
40
+ duration={config.duration}
41
+ style={flatStyle}
42
+ />
43
+ );
44
+ },
45
+
46
+ metadata: {
47
+ description: 'Automatic skeleton generation for Text components',
48
+ author: 'Skelo',
49
+ },
50
+ };
51
+
52
+ /**
53
+ * Estimate number of lines from text content
54
+ */
55
+ function estimateTextLines(children: any): number {
56
+ if (!children) return 1;
57
+
58
+ if (typeof children === 'string' || typeof children === 'number') {
59
+ const text = String(children);
60
+ const avgCharsPerLine = 40;
61
+ const estimatedLines = Math.ceil(text.length / avgCharsPerLine);
62
+ return Math.max(1, Math.min(estimatedLines, 5)); // Cap at 5 lines
63
+ }
64
+
65
+ if (Array.isArray(children)) {
66
+ // Multiple text nodes - count as separate lines
67
+ return Math.min(children.length, 5);
68
+ }
69
+
70
+ return 1;
71
+ }
@@ -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
+ }