@webority-technologies/mobile 0.0.5 → 0.0.7

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 (62) hide show
  1. package/README.md +3 -435
  2. package/lib/commonjs/components/Accordion/Accordion.js +20 -1
  3. package/lib/commonjs/components/Banner/Banner.js +17 -5
  4. package/lib/commonjs/components/Button/Button.js +5 -2
  5. package/lib/commonjs/components/Carousel/Carousel.js +18 -1
  6. package/lib/commonjs/components/Chip/Chip.js +27 -15
  7. package/lib/commonjs/components/ImageGallery/ImageGallery.js +19 -9
  8. package/lib/commonjs/components/Rating/Rating.js +11 -1
  9. package/lib/commonjs/components/Skeleton/Skeleton.js +20 -12
  10. package/lib/commonjs/components/Skeleton/SkeletonContent.js +25 -9
  11. package/lib/commonjs/components/Skeleton/SkeletonList.js +7 -2
  12. package/lib/commonjs/components/Skeleton/SkeletonProvider.js +48 -0
  13. package/lib/commonjs/components/Skeleton/SkeletonSkip.js +37 -0
  14. package/lib/commonjs/components/Skeleton/index.js +20 -0
  15. package/lib/commonjs/components/Stepper/Stepper.js +13 -3
  16. package/lib/commonjs/components/index.js +18 -0
  17. package/lib/module/components/Accordion/Accordion.js +20 -1
  18. package/lib/module/components/Banner/Banner.js +17 -5
  19. package/lib/module/components/Button/Button.js +6 -3
  20. package/lib/module/components/Carousel/Carousel.js +18 -1
  21. package/lib/module/components/Chip/Chip.js +27 -15
  22. package/lib/module/components/ImageGallery/ImageGallery.js +11 -1
  23. package/lib/module/components/Rating/Rating.js +11 -1
  24. package/lib/module/components/Skeleton/Skeleton.js +20 -12
  25. package/lib/module/components/Skeleton/SkeletonContent.js +25 -9
  26. package/lib/module/components/Skeleton/SkeletonList.js +7 -2
  27. package/lib/module/components/Skeleton/SkeletonProvider.js +41 -0
  28. package/lib/module/components/Skeleton/SkeletonSkip.js +31 -0
  29. package/lib/module/components/Skeleton/index.js +2 -0
  30. package/lib/module/components/Stepper/Stepper.js +13 -3
  31. package/lib/module/components/index.js +1 -1
  32. package/lib/typescript/commonjs/components/Accordion/Accordion.d.ts +7 -0
  33. package/lib/typescript/commonjs/components/Banner/Banner.d.ts +6 -0
  34. package/lib/typescript/commonjs/components/Button/Button.d.ts +5 -0
  35. package/lib/typescript/commonjs/components/Carousel/Carousel.d.ts +7 -0
  36. package/lib/typescript/commonjs/components/Chip/Chip.d.ts +6 -0
  37. package/lib/typescript/commonjs/components/ImageGallery/ImageGallery.d.ts +6 -0
  38. package/lib/typescript/commonjs/components/Rating/Rating.d.ts +6 -0
  39. package/lib/typescript/commonjs/components/Skeleton/Skeleton.d.ts +9 -0
  40. package/lib/typescript/commonjs/components/Skeleton/SkeletonContent.d.ts +6 -0
  41. package/lib/typescript/commonjs/components/Skeleton/SkeletonList.d.ts +3 -0
  42. package/lib/typescript/commonjs/components/Skeleton/SkeletonProvider.d.ts +32 -0
  43. package/lib/typescript/commonjs/components/Skeleton/SkeletonSkip.d.ts +25 -0
  44. package/lib/typescript/commonjs/components/Skeleton/index.d.ts +4 -0
  45. package/lib/typescript/commonjs/components/Stepper/Stepper.d.ts +6 -0
  46. package/lib/typescript/commonjs/components/index.d.ts +2 -2
  47. package/lib/typescript/module/components/Accordion/Accordion.d.ts +7 -0
  48. package/lib/typescript/module/components/Banner/Banner.d.ts +6 -0
  49. package/lib/typescript/module/components/Button/Button.d.ts +5 -0
  50. package/lib/typescript/module/components/Carousel/Carousel.d.ts +7 -0
  51. package/lib/typescript/module/components/Chip/Chip.d.ts +6 -0
  52. package/lib/typescript/module/components/ImageGallery/ImageGallery.d.ts +6 -0
  53. package/lib/typescript/module/components/Rating/Rating.d.ts +6 -0
  54. package/lib/typescript/module/components/Skeleton/Skeleton.d.ts +9 -0
  55. package/lib/typescript/module/components/Skeleton/SkeletonContent.d.ts +6 -0
  56. package/lib/typescript/module/components/Skeleton/SkeletonList.d.ts +3 -0
  57. package/lib/typescript/module/components/Skeleton/SkeletonProvider.d.ts +32 -0
  58. package/lib/typescript/module/components/Skeleton/SkeletonSkip.d.ts +25 -0
  59. package/lib/typescript/module/components/Skeleton/index.d.ts +4 -0
  60. package/lib/typescript/module/components/Stepper/Stepper.d.ts +6 -0
  61. package/lib/typescript/module/components/index.d.ts +2 -2
  62. package/package.json +1 -1
@@ -273,6 +273,18 @@ Object.defineProperty(exports, "SkeletonListItem", {
273
273
  return _index35.SkeletonListItem;
274
274
  }
275
275
  });
276
+ Object.defineProperty(exports, "SkeletonProvider", {
277
+ enumerable: true,
278
+ get: function () {
279
+ return _index35.SkeletonProvider;
280
+ }
281
+ });
282
+ Object.defineProperty(exports, "SkeletonSkip", {
283
+ enumerable: true,
284
+ get: function () {
285
+ return _index35.SkeletonSkip;
286
+ }
287
+ });
276
288
  Object.defineProperty(exports, "SkeletonText", {
277
289
  enumerable: true,
278
290
  get: function () {
@@ -345,6 +357,12 @@ Object.defineProperty(exports, "toast", {
345
357
  return _index41.toast;
346
358
  }
347
359
  });
360
+ Object.defineProperty(exports, "useSkeletonDefaults", {
361
+ enumerable: true,
362
+ get: function () {
363
+ return _index35.useSkeletonDefaults;
364
+ }
365
+ });
348
366
  Object.defineProperty(exports, "useToast", {
349
367
  enumerable: true,
350
368
  get: function () {
@@ -4,6 +4,7 @@ import React, { createContext, useCallback, useContext, useEffect, useMemo, useR
4
4
  import { Animated, Easing, LayoutAnimation, Pressable, StyleSheet, Text, View } from 'react-native';
5
5
  import { useTheme } from "../../theme/index.js";
6
6
  import { triggerHaptic } from "../../utils/hapticUtils.js";
7
+ import { SkeletonContent } from "../Skeleton/index.js";
7
8
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
9
  const AccordionGroupContext = /*#__PURE__*/createContext(null);
9
10
  const useAccordionGroup = () => useContext(AccordionGroupContext);
@@ -86,7 +87,8 @@ const Accordion = props => {
86
87
  style,
87
88
  headerStyle,
88
89
  contentStyle,
89
- testID
90
+ testID,
91
+ loading = false
90
92
  } = props;
91
93
  const theme = useTheme();
92
94
  const styles = useMemo(() => buildStyles(theme), [theme]);
@@ -152,6 +154,23 @@ const Accordion = props => {
152
154
  backgroundColor: theme.colors.background.elevated,
153
155
  borderRadius: theme.radius.md
154
156
  }] : null;
157
+ if (loading) {
158
+ return /*#__PURE__*/_jsx(SkeletonContent, {
159
+ loading: true,
160
+ mode: "auto",
161
+ style: [cardStyle, style],
162
+ children: /*#__PURE__*/_jsx(View, {
163
+ style: styles.header,
164
+ children: /*#__PURE__*/_jsx(Text, {
165
+ style: [styles.title, {
166
+ fontSize: theme.typography.fontSize.base
167
+ }],
168
+ numberOfLines: 1,
169
+ children: title ?? ' '
170
+ })
171
+ })
172
+ });
173
+ }
155
174
  return /*#__PURE__*/_jsxs(View, {
156
175
  style: [cardStyle, style],
157
176
  testID: testID,
@@ -3,6 +3,7 @@
3
3
  import React, { forwardRef, useEffect, useMemo, useRef, useState } from 'react';
4
4
  import { Animated, Pressable, StyleSheet, Text, View } from 'react-native';
5
5
  import { useTheme } from "../../theme/index.js";
6
+ import { SkeletonContent } from "../Skeleton/index.js";
6
7
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
8
  const Banner = /*#__PURE__*/forwardRef((props, ref) => {
8
9
  const {
@@ -15,6 +16,7 @@ const Banner = /*#__PURE__*/forwardRef((props, ref) => {
15
16
  onDismiss,
16
17
  visible = true,
17
18
  animateMount = true,
19
+ loading = false,
18
20
  accessibilityLabel,
19
21
  style,
20
22
  testID
@@ -59,6 +61,8 @@ const Banner = /*#__PURE__*/forwardRef((props, ref) => {
59
61
  // eslint-disable-next-line react-hooks/exhaustive-deps
60
62
  }, [visible]);
61
63
  if (!mounted) return null;
64
+ const safeTitle = title ?? ' ';
65
+ const safeMessageString = typeof message === 'string' ? message ?? ' ' : '';
62
66
  const renderIcon = () => {
63
67
  if (icon === false) return null;
64
68
  if (icon) return /*#__PURE__*/_jsx(View, {
@@ -81,7 +85,7 @@ const Banner = /*#__PURE__*/forwardRef((props, ref) => {
81
85
  const messageString = typeof message === 'string' ? message : '';
82
86
  const builtA11y = accessibilityLabel ?? (title ? `${title}. ${messageString}` : messageString || undefined);
83
87
  const liveRegion = variant === 'error' ? 'assertive' : 'polite';
84
- return /*#__PURE__*/_jsxs(Animated.View, {
88
+ const rendered = /*#__PURE__*/_jsxs(Animated.View, {
85
89
  ref: ref,
86
90
  accessibilityRole: 'alert',
87
91
  accessibilityLiveRegion: liveRegion,
@@ -104,7 +108,7 @@ const Banner = /*#__PURE__*/forwardRef((props, ref) => {
104
108
  style: styles.row,
105
109
  children: [renderIcon(), /*#__PURE__*/_jsxs(View, {
106
110
  style: styles.textBlock,
107
- children: [title ? /*#__PURE__*/_jsx(Text, {
111
+ children: [title || loading ? /*#__PURE__*/_jsx(Text, {
108
112
  style: {
109
113
  color: theme.colors.text.primary,
110
114
  fontSize: theme.typography.fontSize.base,
@@ -112,15 +116,15 @@ const Banner = /*#__PURE__*/forwardRef((props, ref) => {
112
116
  lineHeight: 20
113
117
  },
114
118
  numberOfLines: 2,
115
- children: title
116
- }) : null, typeof message === 'string' ? /*#__PURE__*/_jsx(Text, {
119
+ children: safeTitle
120
+ }) : null, typeof message === 'string' || loading ? /*#__PURE__*/_jsx(Text, {
117
121
  style: {
118
122
  color: theme.colors.text.secondary,
119
123
  fontSize: theme.typography.fontSize.sm,
120
124
  lineHeight: 18,
121
125
  marginTop: title ? 2 : 0
122
126
  },
123
- children: message
127
+ children: safeMessageString || ' '
124
128
  }) : /*#__PURE__*/_jsx(View, {
125
129
  style: {
126
130
  marginTop: title ? 2 : 0
@@ -174,6 +178,14 @@ const Banner = /*#__PURE__*/forwardRef((props, ref) => {
174
178
  })
175
179
  }) : null]
176
180
  });
181
+ if (loading) {
182
+ return /*#__PURE__*/_jsx(SkeletonContent, {
183
+ loading: true,
184
+ mode: "auto",
185
+ children: rendered
186
+ });
187
+ }
188
+ return rendered;
177
189
  });
178
190
  Banner.displayName = 'Banner';
179
191
  const tintFor = (theme, variant) => {
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
 
3
3
  import React, { forwardRef, useMemo } from 'react';
4
- import { ActivityIndicator, Animated, Pressable, StyleSheet, Text, View } from 'react-native';
4
+ import { Animated, Pressable, StyleSheet, Text, View } from 'react-native';
5
5
  import { useTheme } from "../../theme/index.js";
6
6
  import { usePressAnimation } from "../../hooks/usePressAnimation.js";
7
7
  import { triggerHaptic } from "../../utils/hapticUtils.js";
8
+ import { Spinner } from "../Spinner/index.js";
8
9
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
9
10
  const Button = /*#__PURE__*/forwardRef((props, ref) => {
10
11
  const {
@@ -50,9 +51,11 @@ const Button = /*#__PURE__*/forwardRef((props, ref) => {
50
51
  const accessibleLabel = accessibilityLabel ?? title;
51
52
  const content = /*#__PURE__*/_jsx(View, {
52
53
  style: styles.contentRow,
53
- children: loading ? /*#__PURE__*/_jsx(ActivityIndicator, {
54
+ children: loading ? /*#__PURE__*/_jsx(Spinner, {
55
+ variant: "circular",
56
+ size: "small",
54
57
  color: variantStyles.textColor,
55
- size: size === 'xs' || size === 'sm' ? 'small' : 'small'
58
+ accessibilityLabel: "Loading"
56
59
  }) : /*#__PURE__*/_jsxs(_Fragment, {
57
60
  children: [leftIcon ? /*#__PURE__*/_jsx(View, {
58
61
  style: styles.iconLeft,
@@ -26,6 +26,7 @@ import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo
26
26
  import { Animated, Dimensions, FlatList, Image, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
27
27
  import { useTheme } from "../../theme/index.js";
28
28
  import { triggerHaptic } from "../../utils/index.js";
29
+ import { SkeletonContent } from "../Skeleton/index.js";
29
30
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
30
31
  // We intentionally use a generic forwardRef wrapper — the inner component is
31
32
  // untyped at the generic level (forwardRef can't preserve generics in TS yet),
@@ -49,7 +50,8 @@ const CarouselInner = /*#__PURE__*/forwardRef((props, ref) => {
49
50
  accessibilityLabel,
50
51
  testID,
51
52
  showThumbnails = false,
52
- renderThumbnail
53
+ renderThumbnail,
54
+ loading = false
53
55
  } = props;
54
56
  const theme = useTheme();
55
57
  const isControlled = typeof controlledIndex === 'number';
@@ -210,6 +212,21 @@ const CarouselInner = /*#__PURE__*/forwardRef((props, ref) => {
210
212
  offset: slideStride * i,
211
213
  index: i
212
214
  }), [slideStride]);
215
+ if (loading) {
216
+ const slideWidth = itemWidth === 'screen' ? containerWidth || 320 : itemWidth;
217
+ return /*#__PURE__*/_jsx(SkeletonContent, {
218
+ loading: true,
219
+ mode: "auto",
220
+ style: [styles.container, containerStyle],
221
+ children: /*#__PURE__*/_jsx(View, {
222
+ style: {
223
+ width: slideWidth,
224
+ height: 160,
225
+ borderRadius: 12
226
+ }
227
+ })
228
+ });
229
+ }
213
230
  return /*#__PURE__*/_jsxs(View, {
214
231
  style: [styles.container, containerStyle],
215
232
  onLayout: e => setContainerWidth(e.nativeEvent.layout.width),
@@ -5,6 +5,7 @@ import { Animated, Pressable, StyleSheet, Text, View } from 'react-native';
5
5
  import { useTheme } from "../../theme/index.js";
6
6
  import { usePressAnimation } from "../../hooks/usePressAnimation.js";
7
7
  import { triggerHaptic } from "../../utils/hapticUtils.js";
8
+ import { SkeletonContent } from "../Skeleton/index.js";
8
9
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
9
10
  const toneFor = (theme, tone) => {
10
11
  switch (tone) {
@@ -96,6 +97,7 @@ const Chip = /*#__PURE__*/forwardRef((props, ref) => {
96
97
  tone = 'neutral',
97
98
  size = 'md',
98
99
  disabled = false,
100
+ loading = false,
99
101
  accessibilityLabel,
100
102
  style,
101
103
  textStyle,
@@ -154,7 +156,7 @@ const Chip = /*#__PURE__*/forwardRef((props, ref) => {
154
156
  fontWeight: theme.typography.fontWeight.medium
155
157
  }, textStyle],
156
158
  numberOfLines: 1,
157
- children: label
159
+ children: label ?? ' '
158
160
  }), onClose ? /*#__PURE__*/_jsx(Pressable, {
159
161
  onPress: handleClose,
160
162
  disabled: disabled,
@@ -195,8 +197,9 @@ const Chip = /*#__PURE__*/forwardRef((props, ref) => {
195
197
  borderColor,
196
198
  opacity: disabled ? 0.55 : 1
197
199
  };
200
+ let rendered;
198
201
  if (isPressable) {
199
- return /*#__PURE__*/_jsx(Animated.View, {
202
+ rendered = /*#__PURE__*/_jsx(Animated.View, {
200
203
  style: {
201
204
  transform: [{
202
205
  scale
@@ -228,20 +231,29 @@ const Chip = /*#__PURE__*/forwardRef((props, ref) => {
228
231
  children: content
229
232
  })
230
233
  });
234
+ } else {
235
+ rendered = /*#__PURE__*/_jsx(View, {
236
+ ref: ref,
237
+ style: [styles.base, baseStyle, style],
238
+ accessible: true,
239
+ accessibilityRole: "text",
240
+ accessibilityLabel: a11yLabel,
241
+ accessibilityState: {
242
+ selected,
243
+ disabled
244
+ },
245
+ testID: testID,
246
+ children: content
247
+ });
231
248
  }
232
- return /*#__PURE__*/_jsx(View, {
233
- ref: ref,
234
- style: [styles.base, baseStyle, style],
235
- accessible: true,
236
- accessibilityRole: "text",
237
- accessibilityLabel: a11yLabel,
238
- accessibilityState: {
239
- selected,
240
- disabled
241
- },
242
- testID: testID,
243
- children: content
244
- });
249
+ if (loading) {
250
+ return /*#__PURE__*/_jsx(SkeletonContent, {
251
+ loading: true,
252
+ mode: "auto",
253
+ children: rendered
254
+ });
255
+ }
256
+ return rendered;
245
257
  });
246
258
  Chip.displayName = 'Chip';
247
259
  const styles = StyleSheet.create({
@@ -25,6 +25,7 @@ import { Gesture, GestureDetector } from 'react-native-gesture-handler';
25
25
  import Animated, { runOnJS, useAnimatedStyle, useSharedValue, withSpring, withTiming } from 'react-native-reanimated';
26
26
  import { Carousel } from "../Carousel/index.js";
27
27
  import { AppIcon } from "../AppIcon/index.js";
28
+ import { SkeletonContent } from "../Skeleton/index.js";
28
29
  import { useTheme } from "../../theme/index.js";
29
30
  import { triggerHaptic } from "../../utils/index.js";
30
31
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -44,6 +45,7 @@ const ImageGallery = ({
44
45
  enableLightbox = true,
45
46
  enablePinchZoom = true,
46
47
  onIndexChange,
48
+ loading = false,
47
49
  accessibilityLabel,
48
50
  containerStyle,
49
51
  testID
@@ -85,7 +87,7 @@ const ImageGallery = ({
85
87
  style: styles.thumbnailImage,
86
88
  resizeMode: "cover"
87
89
  }), [styles]);
88
- return /*#__PURE__*/_jsxs(View, {
90
+ const rendered = /*#__PURE__*/_jsxs(View, {
89
91
  style: [styles.container, containerStyle],
90
92
  testID: testID,
91
93
  accessibilityLabel: accessibilityLabel ?? 'Image gallery',
@@ -120,6 +122,14 @@ const ImageGallery = ({
120
122
  onIndexChange: handleIndexChange
121
123
  }) : null]
122
124
  });
125
+ if (loading) {
126
+ return /*#__PURE__*/_jsx(SkeletonContent, {
127
+ loading: true,
128
+ mode: "auto",
129
+ children: rendered
130
+ });
131
+ }
132
+ return rendered;
123
133
  };
124
134
  ImageGallery.displayName = 'ImageGallery';
125
135
 
@@ -4,6 +4,7 @@ import React, { forwardRef, useCallback, useMemo, useRef } from 'react';
4
4
  import { Animated, Easing, Pressable, StyleSheet, Text, View } from 'react-native';
5
5
  import { useTheme } from "../../theme/index.js";
6
6
  import { triggerHaptic } from "../../utils/hapticUtils.js";
7
+ import { SkeletonContent } from "../Skeleton/index.js";
7
8
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
9
  const sizePxMap = {
9
10
  sm: 16,
@@ -78,6 +79,7 @@ const Rating = /*#__PURE__*/forwardRef((props, ref) => {
78
79
  size = 'md',
79
80
  tone = 'warning',
80
81
  label,
82
+ loading = false,
81
83
  accessibilityLabel,
82
84
  style,
83
85
  testID
@@ -163,7 +165,7 @@ const Rating = /*#__PURE__*/forwardRef((props, ref) => {
163
165
  children: star
164
166
  }, i));
165
167
  }
166
- return /*#__PURE__*/_jsxs(View, {
168
+ const rendered = /*#__PURE__*/_jsxs(View, {
167
169
  style: [styles.wrapper, style],
168
170
  ref: ref,
169
171
  testID: testID,
@@ -193,6 +195,14 @@ const Rating = /*#__PURE__*/forwardRef((props, ref) => {
193
195
  children: stars
194
196
  })]
195
197
  });
198
+ if (loading) {
199
+ return /*#__PURE__*/_jsx(SkeletonContent, {
200
+ loading: true,
201
+ mode: "auto",
202
+ children: rendered
203
+ });
204
+ }
205
+ return rendered;
196
206
  });
197
207
  Rating.displayName = 'Rating';
198
208
  const starStyles = StyleSheet.create({
@@ -4,6 +4,7 @@ import React, { useEffect, useMemo, useRef, useState } from 'react';
4
4
  import { Animated, Easing, StyleSheet, View } from 'react-native';
5
5
  import { useTheme } from "../../theme/index.js";
6
6
  import { Responsive } from "../../utils/index.js";
7
+ import { useSkeletonDefaults } from "./SkeletonProvider.js";
7
8
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
9
  const SPEED_DURATION = {
9
10
  slow: 1800,
@@ -28,23 +29,30 @@ const resolveWidth = width => {
28
29
  const Skeleton = ({
29
30
  width = '100%',
30
31
  height = 16,
31
- radius = 'sm',
32
- variant = 'shimmer',
33
- speed = 'normal',
32
+ radius,
33
+ variant,
34
+ speed,
35
+ colors,
34
36
  style,
35
37
  testID
36
38
  }) => {
37
39
  const theme = useTheme();
40
+ const defaults = useSkeletonDefaults();
41
+ const resolvedVariant = variant ?? defaults.variant ?? 'shimmer';
42
+ const resolvedSpeed = speed ?? defaults.speed ?? 'normal';
43
+ const resolvedRadiusToken = radius ?? defaults.radius ?? 'sm';
44
+ const backgroundColor = colors?.background ?? defaults.colors?.background ?? theme.colors.skeleton.background;
45
+ const highlightColor = colors?.highlight ?? defaults.colors?.highlight ?? theme.colors.skeleton.highlight;
38
46
  const styles = useMemo(() => buildStyles(theme), [theme]);
39
- const borderRadius = resolveRadius(theme, radius);
47
+ const borderRadius = resolveRadius(theme, resolvedRadiusToken);
40
48
  const resolvedWidth = resolveWidth(width);
41
49
  const resolvedHeight = Responsive.size(height);
42
50
  const progress = useRef(new Animated.Value(0)).current;
43
51
  const [containerWidth, setContainerWidth] = useState(0);
44
52
  useEffect(() => {
45
53
  progress.setValue(0);
46
- const duration = variant === 'pulse' ? PULSE_DURATION : SPEED_DURATION[speed];
47
- const animation = variant === 'pulse' ? Animated.loop(Animated.sequence([Animated.timing(progress, {
54
+ const duration = resolvedVariant === 'pulse' ? PULSE_DURATION : SPEED_DURATION[resolvedSpeed];
55
+ const animation = resolvedVariant === 'pulse' ? Animated.loop(Animated.sequence([Animated.timing(progress, {
48
56
  toValue: 1,
49
57
  duration: duration / 2,
50
58
  easing: Easing.inOut(Easing.ease),
@@ -64,17 +72,17 @@ const Skeleton = ({
64
72
  return () => {
65
73
  animation.stop();
66
74
  };
67
- }, [progress, speed, variant]);
75
+ }, [progress, resolvedSpeed, resolvedVariant]);
68
76
  const handleLayout = event => {
69
77
  const next = event.nativeEvent.layout.width;
70
78
  if (next !== containerWidth) setContainerWidth(next);
71
79
  };
72
80
  const overlay = useMemo(() => {
73
- if (variant === 'pulse') {
81
+ if (resolvedVariant === 'pulse') {
74
82
  return /*#__PURE__*/_jsx(Animated.View, {
75
83
  pointerEvents: "none",
76
84
  style: [StyleSheet.absoluteFillObject, {
77
- backgroundColor: theme.colors.skeleton.highlight,
85
+ backgroundColor: highlightColor,
78
86
  opacity: progress.interpolate({
79
87
  inputRange: [0, 1],
80
88
  outputRange: [0, 0.6]
@@ -92,13 +100,13 @@ const Skeleton = ({
92
100
  pointerEvents: "none",
93
101
  style: [styles.shimmer, {
94
102
  width: highlightWidth,
95
- backgroundColor: theme.colors.skeleton.highlight,
103
+ backgroundColor: highlightColor,
96
104
  transform: [{
97
105
  translateX
98
106
  }]
99
107
  }]
100
108
  });
101
- }, [containerWidth, progress, styles.shimmer, theme.colors.skeleton.highlight, variant]);
109
+ }, [containerWidth, progress, styles.shimmer, highlightColor, resolvedVariant]);
102
110
  return /*#__PURE__*/_jsx(View, {
103
111
  onLayout: handleLayout,
104
112
  accessible: true,
@@ -110,7 +118,7 @@ const Skeleton = ({
110
118
  width: resolvedWidth,
111
119
  height: resolvedHeight,
112
120
  borderRadius,
113
- backgroundColor: theme.colors.skeleton.background
121
+ backgroundColor
114
122
  }, style],
115
123
  children: overlay
116
124
  });
@@ -3,6 +3,7 @@
3
3
  import React, { Children, cloneElement, isValidElement, useState } from 'react';
4
4
  import { Image, StyleSheet, Text, View } from 'react-native';
5
5
  import { Skeleton } from "./Skeleton.js";
6
+ import { SkeletonSkip } from "./SkeletonSkip.js";
6
7
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
7
8
  const flattenStyle = style => {
8
9
  if (!style) return {};
@@ -22,7 +23,7 @@ const resolveRadius = (raw, fallback) => {
22
23
  if (typeof raw === 'number') return raw;
23
24
  return fallback;
24
25
  };
25
- const skeletonizeNode = (node, variant, speed, keyHint = 'r') => {
26
+ const skeletonizeNode = (node, variant, speed, colors, keyHint = 'r') => {
26
27
  if (node == null || typeof node === 'boolean') return null;
27
28
  if (typeof node === 'string' || typeof node === 'number') {
28
29
  return /*#__PURE__*/_jsx(Skeleton, {
@@ -30,11 +31,12 @@ const skeletonizeNode = (node, variant, speed, keyHint = 'r') => {
30
31
  height: 14,
31
32
  radius: "sm",
32
33
  variant: variant,
33
- speed: speed
34
+ speed: speed,
35
+ colors: colors
34
36
  }, `${keyHint}-text`);
35
37
  }
36
38
  if (Array.isArray(node)) {
37
- return Children.map(node, (child, index) => skeletonizeNode(child, variant, speed, `${keyHint}-${index}`));
39
+ return Children.map(node, (child, index) => skeletonizeNode(child, variant, speed, colors, `${keyHint}-${index}`));
38
40
  }
39
41
  if (! /*#__PURE__*/isValidElement(node)) return null;
40
42
  const element = node;
@@ -42,6 +44,13 @@ const skeletonizeNode = (node, variant, speed, keyHint = 'r') => {
42
44
  const elementStyle = flattenStyle(props.style);
43
45
  const elementType = element.type;
44
46
 
47
+ // <SkeletonSkip /> → opt-out marker; render its children unchanged
48
+ if (elementType === SkeletonSkip) {
49
+ return /*#__PURE__*/cloneElement(element, {
50
+ key: `${keyHint}-skip`
51
+ });
52
+ }
53
+
45
54
  // <Image /> → fixed-size skeleton block matching style.width/height/borderRadius
46
55
  if (elementType === Image) {
47
56
  const width = resolveWidth(elementStyle.width, '100%');
@@ -53,6 +62,7 @@ const skeletonizeNode = (node, variant, speed, keyHint = 'r') => {
53
62
  radius: radius,
54
63
  variant: variant,
55
64
  speed: speed,
65
+ colors: colors,
56
66
  style: {
57
67
  margin: typeof elementStyle.margin === 'number' ? elementStyle.margin : undefined
58
68
  }
@@ -69,6 +79,7 @@ const skeletonizeNode = (node, variant, speed, keyHint = 'r') => {
69
79
  radius: "sm",
70
80
  variant: variant,
71
81
  speed: speed,
82
+ colors: colors,
72
83
  style: {
73
84
  marginVertical: 2
74
85
  }
@@ -79,7 +90,7 @@ const skeletonizeNode = (node, variant, speed, keyHint = 'r') => {
79
90
  if (props.children != null) {
80
91
  return /*#__PURE__*/cloneElement(element, {
81
92
  key: `${keyHint}-w`
82
- }, skeletonizeNode(props.children, variant, speed, `${keyHint}-c`));
93
+ }, skeletonizeNode(props.children, variant, speed, colors, `${keyHint}-c`));
83
94
  }
84
95
 
85
96
  // Leaf <View /> with explicit dimensions → skeleton block
@@ -92,7 +103,8 @@ const skeletonizeNode = (node, variant, speed, keyHint = 'r') => {
92
103
  height: height,
93
104
  radius: radius,
94
105
  variant: variant,
95
- speed: speed
106
+ speed: speed,
107
+ colors: colors
96
108
  }, `${keyHint}-vw`);
97
109
  }
98
110
 
@@ -105,10 +117,11 @@ const skeletonizeNode = (node, variant, speed, keyHint = 'r') => {
105
117
  const SkeletonContent = ({
106
118
  loading,
107
119
  children,
108
- variant = 'shimmer',
109
- speed = 'normal',
120
+ variant,
121
+ speed,
110
122
  mode = 'auto',
111
123
  count = 1,
124
+ colors,
112
125
  style,
113
126
  testID
114
127
  }) => {
@@ -128,6 +141,7 @@ const SkeletonContent = ({
128
141
  testID: testID,
129
142
  variant: variant,
130
143
  speed: speed,
144
+ colors: colors,
131
145
  children: repeated
132
146
  });
133
147
  }
@@ -138,7 +152,7 @@ const SkeletonContent = ({
138
152
  accessibilityLabel: "Loading",
139
153
  accessibilityRole: "progressbar",
140
154
  accessibilityLiveRegion: "polite",
141
- children: skeletonizeNode(repeated, variant, speed)
155
+ children: skeletonizeNode(repeated, variant, speed, colors)
142
156
  });
143
157
  };
144
158
  SkeletonContent.displayName = 'SkeletonContent';
@@ -146,6 +160,7 @@ const BlockSkeleton = ({
146
160
  children,
147
161
  variant,
148
162
  speed,
163
+ colors,
149
164
  style,
150
165
  testID
151
166
  }) => {
@@ -182,7 +197,8 @@ const BlockSkeleton = ({
182
197
  height: size.height,
183
198
  radius: "md",
184
199
  variant: variant,
185
- speed: speed
200
+ speed: speed,
201
+ colors: colors
186
202
  })
187
203
  }) : null]
188
204
  });
@@ -3,6 +3,7 @@
3
3
  import React from 'react';
4
4
  import { FlatList, View } from 'react-native';
5
5
  import { SkeletonContent } from "./SkeletonContent.js";
6
+ import { useSkeletonDefaults } from "./SkeletonProvider.js";
6
7
  import { jsx as _jsx } from "react/jsx-runtime";
7
8
  /**
8
9
  * Drop-in FlatList replacement that renders `placeholderCount` skeleton rows while
@@ -27,9 +28,10 @@ function SkeletonListInner(props) {
27
28
  data,
28
29
  renderItem,
29
30
  renderPlaceholder,
30
- placeholderCount = 3,
31
+ placeholderCount,
31
32
  variant,
32
33
  speed,
34
+ colors,
33
35
  placeholderContainerStyle,
34
36
  horizontal,
35
37
  contentContainerStyle,
@@ -37,9 +39,11 @@ function SkeletonListInner(props) {
37
39
  testID,
38
40
  ...rest
39
41
  } = props;
42
+ const defaults = useSkeletonDefaults();
43
+ const resolvedCount = placeholderCount ?? defaults.placeholderCount ?? 3;
40
44
  if (loading) {
41
45
  const slots = Array.from({
42
- length: Math.max(0, placeholderCount)
46
+ length: Math.max(0, resolvedCount)
43
47
  }, (_, index) => /*#__PURE__*/_jsx(React.Fragment, {
44
48
  children: renderPlaceholder ? renderPlaceholder(index) : null
45
49
  }, `sk-list-${index}`));
@@ -47,6 +51,7 @@ function SkeletonListInner(props) {
47
51
  loading: true,
48
52
  variant: variant,
49
53
  speed: speed,
54
+ colors: colors,
50
55
  style: style,
51
56
  testID: testID,
52
57
  children: /*#__PURE__*/_jsx(View, {
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+
3
+ import React, { createContext, useContext, useMemo } from 'react';
4
+
5
+ /**
6
+ * Per-instance color override for a skeleton. `background` is the resting tone
7
+ * of the placeholder; `highlight` is the moving shimmer band (or pulse fade).
8
+ * Either can be omitted — missing keys fall back to the active theme.
9
+ */
10
+ import { jsx as _jsx } from "react/jsx-runtime";
11
+ const SkeletonDefaultsContext = /*#__PURE__*/createContext({});
12
+ export const SkeletonProvider = ({
13
+ children,
14
+ variant,
15
+ speed,
16
+ placeholderCount,
17
+ radius,
18
+ colors
19
+ }) => {
20
+ const value = useMemo(() => ({
21
+ variant,
22
+ speed,
23
+ placeholderCount,
24
+ radius,
25
+ colors
26
+ }), [variant, speed, placeholderCount, radius, colors]);
27
+ return /*#__PURE__*/_jsx(SkeletonDefaultsContext.Provider, {
28
+ value: value,
29
+ children: children
30
+ });
31
+ };
32
+ SkeletonProvider.displayName = 'SkeletonProvider';
33
+
34
+ /**
35
+ * Read the current SkeletonProvider defaults. Returns an empty object when no
36
+ * provider is mounted, so the skeleton primitives still work outside of one.
37
+ */
38
+ export const useSkeletonDefaults = () => {
39
+ return useContext(SkeletonDefaultsContext);
40
+ };
41
+ //# sourceMappingURL=SkeletonProvider.js.map