@webority-technologies/mobile 0.0.5 → 0.0.6

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 (34) hide show
  1. package/README.md +38 -10
  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/Stepper/Stepper.js +13 -3
  10. package/lib/module/components/Accordion/Accordion.js +20 -1
  11. package/lib/module/components/Banner/Banner.js +17 -5
  12. package/lib/module/components/Button/Button.js +6 -3
  13. package/lib/module/components/Carousel/Carousel.js +18 -1
  14. package/lib/module/components/Chip/Chip.js +27 -15
  15. package/lib/module/components/ImageGallery/ImageGallery.js +11 -1
  16. package/lib/module/components/Rating/Rating.js +11 -1
  17. package/lib/module/components/Stepper/Stepper.js +13 -3
  18. package/lib/typescript/commonjs/components/Accordion/Accordion.d.ts +7 -0
  19. package/lib/typescript/commonjs/components/Banner/Banner.d.ts +6 -0
  20. package/lib/typescript/commonjs/components/Button/Button.d.ts +5 -0
  21. package/lib/typescript/commonjs/components/Carousel/Carousel.d.ts +7 -0
  22. package/lib/typescript/commonjs/components/Chip/Chip.d.ts +6 -0
  23. package/lib/typescript/commonjs/components/ImageGallery/ImageGallery.d.ts +6 -0
  24. package/lib/typescript/commonjs/components/Rating/Rating.d.ts +6 -0
  25. package/lib/typescript/commonjs/components/Stepper/Stepper.d.ts +6 -0
  26. package/lib/typescript/module/components/Accordion/Accordion.d.ts +7 -0
  27. package/lib/typescript/module/components/Banner/Banner.d.ts +6 -0
  28. package/lib/typescript/module/components/Button/Button.d.ts +5 -0
  29. package/lib/typescript/module/components/Carousel/Carousel.d.ts +7 -0
  30. package/lib/typescript/module/components/Chip/Chip.d.ts +6 -0
  31. package/lib/typescript/module/components/ImageGallery/ImageGallery.d.ts +6 -0
  32. package/lib/typescript/module/components/Rating/Rating.d.ts +6 -0
  33. package/lib/typescript/module/components/Stepper/Stepper.d.ts +6 -0
  34. package/package.json +1 -1
package/README.md CHANGED
@@ -396,7 +396,8 @@ For runnable usage of every component, see [`example/`](../../example/).
396
396
 
397
397
  ## Designing skeleton-aware components
398
398
 
399
- Presentational primitives (`Card`, `ListItem`, `Avatar`, `Badge`) accept an optional
399
+ Presentational primitives (`Card`, `ListItem`, `Avatar`, `Badge`, `Banner`, `Chip`,
400
+ `Rating`, `Stepper`, `ImageGallery`) accept an optional
400
401
  `loading?: boolean` prop. When `true`, the component renders its normal layout wrapped
401
402
  in `<SkeletonContent loading mode="auto">` — the walker replaces every `<Text>`,
402
403
  `<Image>`, and sized leaf `<View>` with a shimmer block matching the element's
@@ -420,20 +421,47 @@ Before / after with `Card`:
420
421
 
421
422
  ```tsx
422
423
  // Before — caller hand-rolls a placeholder branch
423
- {loading ? (
424
- <SkeletonCard />
425
- ) : (
426
- <Card>
427
- <Text>{site.name}</Text>
428
- <Text>{site.address}</Text>
429
- </Card>
430
- )}
424
+ {
425
+ loading ? (
426
+ <SkeletonCard />
427
+ ) : (
428
+ <Card>
429
+ <Text>{site.name}</Text>
430
+ <Text>{site.address}</Text>
431
+ </Card>
432
+ );
433
+ }
431
434
 
432
435
  // After — Card itself is skeleton-aware
433
436
  <Card loading={loading}>
434
437
  <Text>{site?.name ?? ' '}</Text>
435
438
  <Text>{site?.address ?? ' '}</Text>
436
- </Card>
439
+ </Card>;
440
+ ```
441
+
442
+ ### Two flavours of `loading`
443
+
444
+ Same prop name, different semantic by category:
445
+
446
+ - **Display primitives** (`Card`, `ListItem`, `Avatar`, `Badge`, `Banner`, `Chip`, `Rating`,
447
+ `Stepper`, `ImageGallery`) — `loading={true}` renders the component as a skeleton placeholder
448
+ via `SkeletonContent`'s auto walker. Use when the data driving the component is still being
449
+ fetched.
450
+ - **Interactive triggers** (`Button`) — `loading={true}` swaps the label for an inline `Spinner`,
451
+ hides leading/trailing icons, and disables press handling. The button keeps its footprint and
452
+ visual style. Use when an action is in flight (submit, save, delete) — pending action, not
453
+ data fetch.
454
+
455
+ Before / after with `Button`:
456
+
457
+ ```tsx
458
+ // Before — caller swaps a separate spinner in
459
+ {
460
+ submitting ? <Spinner size="small" /> : <Button title="Save" onPress={save} />;
461
+ }
462
+
463
+ // After — Button itself signals the in-flight action
464
+ <Button title="Save" loading={submitting} onPress={save} />;
437
465
  ```
438
466
 
439
467
  ---
@@ -8,6 +8,7 @@ var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  var _index = require("../../theme/index.js");
10
10
  var _hapticUtils = require("../../utils/hapticUtils.js");
11
+ var _index2 = require("../Skeleton/index.js");
11
12
  var _jsxRuntime = require("react/jsx-runtime");
12
13
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
13
14
  const AccordionGroupContext = /*#__PURE__*/(0, _react.createContext)(null);
@@ -92,7 +93,8 @@ const Accordion = props => {
92
93
  style,
93
94
  headerStyle,
94
95
  contentStyle,
95
- testID
96
+ testID,
97
+ loading = false
96
98
  } = props;
97
99
  const theme = (0, _index.useTheme)();
98
100
  const styles = (0, _react.useMemo)(() => buildStyles(theme), [theme]);
@@ -158,6 +160,23 @@ const Accordion = props => {
158
160
  backgroundColor: theme.colors.background.elevated,
159
161
  borderRadius: theme.radius.md
160
162
  }] : null;
163
+ if (loading) {
164
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.SkeletonContent, {
165
+ loading: true,
166
+ mode: "auto",
167
+ style: [cardStyle, style],
168
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
169
+ style: styles.header,
170
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
171
+ style: [styles.title, {
172
+ fontSize: theme.typography.fontSize.base
173
+ }],
174
+ numberOfLines: 1,
175
+ children: title ?? ' '
176
+ })
177
+ })
178
+ });
179
+ }
161
180
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
162
181
  style: [cardStyle, style],
163
182
  testID: testID,
@@ -7,6 +7,7 @@ exports.default = exports.Banner = void 0;
7
7
  var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  var _index = require("../../theme/index.js");
10
+ var _index2 = require("../Skeleton/index.js");
10
11
  var _jsxRuntime = require("react/jsx-runtime");
11
12
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
12
13
  const Banner = exports.Banner = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
@@ -20,6 +21,7 @@ const Banner = exports.Banner = /*#__PURE__*/(0, _react.forwardRef)((props, ref)
20
21
  onDismiss,
21
22
  visible = true,
22
23
  animateMount = true,
24
+ loading = false,
23
25
  accessibilityLabel,
24
26
  style,
25
27
  testID
@@ -64,6 +66,8 @@ const Banner = exports.Banner = /*#__PURE__*/(0, _react.forwardRef)((props, ref)
64
66
  // eslint-disable-next-line react-hooks/exhaustive-deps
65
67
  }, [visible]);
66
68
  if (!mounted) return null;
69
+ const safeTitle = title ?? ' ';
70
+ const safeMessageString = typeof message === 'string' ? message ?? ' ' : '';
67
71
  const renderIcon = () => {
68
72
  if (icon === false) return null;
69
73
  if (icon) return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
@@ -86,7 +90,7 @@ const Banner = exports.Banner = /*#__PURE__*/(0, _react.forwardRef)((props, ref)
86
90
  const messageString = typeof message === 'string' ? message : '';
87
91
  const builtA11y = accessibilityLabel ?? (title ? `${title}. ${messageString}` : messageString || undefined);
88
92
  const liveRegion = variant === 'error' ? 'assertive' : 'polite';
89
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Animated.View, {
93
+ const rendered = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Animated.View, {
90
94
  ref: ref,
91
95
  accessibilityRole: 'alert',
92
96
  accessibilityLiveRegion: liveRegion,
@@ -109,7 +113,7 @@ const Banner = exports.Banner = /*#__PURE__*/(0, _react.forwardRef)((props, ref)
109
113
  style: styles.row,
110
114
  children: [renderIcon(), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
111
115
  style: styles.textBlock,
112
- children: [title ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
116
+ children: [title || loading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
113
117
  style: {
114
118
  color: theme.colors.text.primary,
115
119
  fontSize: theme.typography.fontSize.base,
@@ -117,15 +121,15 @@ const Banner = exports.Banner = /*#__PURE__*/(0, _react.forwardRef)((props, ref)
117
121
  lineHeight: 20
118
122
  },
119
123
  numberOfLines: 2,
120
- children: title
121
- }) : null, typeof message === 'string' ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
124
+ children: safeTitle
125
+ }) : null, typeof message === 'string' || loading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
122
126
  style: {
123
127
  color: theme.colors.text.secondary,
124
128
  fontSize: theme.typography.fontSize.sm,
125
129
  lineHeight: 18,
126
130
  marginTop: title ? 2 : 0
127
131
  },
128
- children: message
132
+ children: safeMessageString || ' '
129
133
  }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
130
134
  style: {
131
135
  marginTop: title ? 2 : 0
@@ -179,6 +183,14 @@ const Banner = exports.Banner = /*#__PURE__*/(0, _react.forwardRef)((props, ref)
179
183
  })
180
184
  }) : null]
181
185
  });
186
+ if (loading) {
187
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.SkeletonContent, {
188
+ loading: true,
189
+ mode: "auto",
190
+ children: rendered
191
+ });
192
+ }
193
+ return rendered;
182
194
  });
183
195
  Banner.displayName = 'Banner';
184
196
  const tintFor = (theme, variant) => {
@@ -9,6 +9,7 @@ var _reactNative = require("react-native");
9
9
  var _index = require("../../theme/index.js");
10
10
  var _usePressAnimation = require("../../hooks/usePressAnimation.js");
11
11
  var _hapticUtils = require("../../utils/hapticUtils.js");
12
+ var _index2 = require("../Spinner/index.js");
12
13
  var _jsxRuntime = require("react/jsx-runtime");
13
14
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
14
15
  const Button = exports.Button = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
@@ -55,9 +56,11 @@ const Button = exports.Button = /*#__PURE__*/(0, _react.forwardRef)((props, ref)
55
56
  const accessibleLabel = accessibilityLabel ?? title;
56
57
  const content = /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
57
58
  style: styles.contentRow,
58
- children: loading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
59
+ children: loading ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.Spinner, {
60
+ variant: "circular",
61
+ size: "small",
59
62
  color: variantStyles.textColor,
60
- size: size === 'xs' || size === 'sm' ? 'small' : 'small'
63
+ accessibilityLabel: "Loading"
61
64
  }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
62
65
  children: [leftIcon ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
63
66
  style: styles.iconLeft,
@@ -8,6 +8,7 @@ var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  var _index = require("../../theme/index.js");
10
10
  var _index2 = require("../../utils/index.js");
11
+ var _index3 = require("../Skeleton/index.js");
11
12
  var _jsxRuntime = require("react/jsx-runtime");
12
13
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
13
14
  /**
@@ -54,7 +55,8 @@ const CarouselInner = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
54
55
  accessibilityLabel,
55
56
  testID,
56
57
  showThumbnails = false,
57
- renderThumbnail
58
+ renderThumbnail,
59
+ loading = false
58
60
  } = props;
59
61
  const theme = (0, _index.useTheme)();
60
62
  const isControlled = typeof controlledIndex === 'number';
@@ -215,6 +217,21 @@ const CarouselInner = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
215
217
  offset: slideStride * i,
216
218
  index: i
217
219
  }), [slideStride]);
220
+ if (loading) {
221
+ const slideWidth = itemWidth === 'screen' ? containerWidth || 320 : itemWidth;
222
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_index3.SkeletonContent, {
223
+ loading: true,
224
+ mode: "auto",
225
+ style: [styles.container, containerStyle],
226
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
227
+ style: {
228
+ width: slideWidth,
229
+ height: 160,
230
+ borderRadius: 12
231
+ }
232
+ })
233
+ });
234
+ }
218
235
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
219
236
  style: [styles.container, containerStyle],
220
237
  onLayout: e => setContainerWidth(e.nativeEvent.layout.width),
@@ -9,6 +9,7 @@ var _reactNative = require("react-native");
9
9
  var _index = require("../../theme/index.js");
10
10
  var _usePressAnimation = require("../../hooks/usePressAnimation.js");
11
11
  var _hapticUtils = require("../../utils/hapticUtils.js");
12
+ var _index2 = require("../Skeleton/index.js");
12
13
  var _jsxRuntime = require("react/jsx-runtime");
13
14
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
14
15
  const toneFor = (theme, tone) => {
@@ -101,6 +102,7 @@ const Chip = exports.Chip = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
101
102
  tone = 'neutral',
102
103
  size = 'md',
103
104
  disabled = false,
105
+ loading = false,
104
106
  accessibilityLabel,
105
107
  style,
106
108
  textStyle,
@@ -159,7 +161,7 @@ const Chip = exports.Chip = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
159
161
  fontWeight: theme.typography.fontWeight.medium
160
162
  }, textStyle],
161
163
  numberOfLines: 1,
162
- children: label
164
+ children: label ?? ' '
163
165
  }), onClose ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
164
166
  onPress: handleClose,
165
167
  disabled: disabled,
@@ -200,8 +202,9 @@ const Chip = exports.Chip = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
200
202
  borderColor,
201
203
  opacity: disabled ? 0.55 : 1
202
204
  };
205
+ let rendered;
203
206
  if (isPressable) {
204
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Animated.View, {
207
+ rendered = /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Animated.View, {
205
208
  style: {
206
209
  transform: [{
207
210
  scale
@@ -233,20 +236,29 @@ const Chip = exports.Chip = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
233
236
  children: content
234
237
  })
235
238
  });
239
+ } else {
240
+ rendered = /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
241
+ ref: ref,
242
+ style: [styles.base, baseStyle, style],
243
+ accessible: true,
244
+ accessibilityRole: "text",
245
+ accessibilityLabel: a11yLabel,
246
+ accessibilityState: {
247
+ selected,
248
+ disabled
249
+ },
250
+ testID: testID,
251
+ children: content
252
+ });
236
253
  }
237
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
238
- ref: ref,
239
- style: [styles.base, baseStyle, style],
240
- accessible: true,
241
- accessibilityRole: "text",
242
- accessibilityLabel: a11yLabel,
243
- accessibilityState: {
244
- selected,
245
- disabled
246
- },
247
- testID: testID,
248
- children: content
249
- });
254
+ if (loading) {
255
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.SkeletonContent, {
256
+ loading: true,
257
+ mode: "auto",
258
+ children: rendered
259
+ });
260
+ }
261
+ return rendered;
250
262
  });
251
263
  Chip.displayName = 'Chip';
252
264
  const styles = _reactNative.StyleSheet.create({
@@ -10,8 +10,9 @@ var _reactNativeGestureHandler = require("react-native-gesture-handler");
10
10
  var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated"));
11
11
  var _index = require("../Carousel/index.js");
12
12
  var _index2 = require("../AppIcon/index.js");
13
- var _index3 = require("../../theme/index.js");
14
- var _index4 = require("../../utils/index.js");
13
+ var _index3 = require("../Skeleton/index.js");
14
+ var _index4 = require("../../theme/index.js");
15
+ var _index5 = require("../../utils/index.js");
15
16
  var _jsxRuntime = require("react/jsx-runtime");
16
17
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
17
18
  /**
@@ -49,11 +50,12 @@ const ImageGallery = ({
49
50
  enableLightbox = true,
50
51
  enablePinchZoom = true,
51
52
  onIndexChange,
53
+ loading = false,
52
54
  accessibilityLabel,
53
55
  containerStyle,
54
56
  testID
55
57
  }) => {
56
- const theme = (0, _index3.useTheme)();
58
+ const theme = (0, _index4.useTheme)();
57
59
  const styles = (0, _react.useMemo)(() => buildStyles(theme), [theme]);
58
60
  const [currentIndex, setCurrentIndex] = (0, _react.useState)(clamp(initialIndex, 0, Math.max(0, images.length - 1)));
59
61
  const [lightboxOpen, setLightboxOpen] = (0, _react.useState)(false);
@@ -63,11 +65,11 @@ const ImageGallery = ({
63
65
  }, [onIndexChange]);
64
66
  const openLightbox = (0, _react.useCallback)(() => {
65
67
  if (!enableLightbox) return;
66
- (0, _index4.triggerHaptic)('selection');
68
+ (0, _index5.triggerHaptic)('selection');
67
69
  setLightboxOpen(true);
68
70
  }, [enableLightbox]);
69
71
  const closeLightbox = (0, _react.useCallback)(() => {
70
- (0, _index4.triggerHaptic)('selection');
72
+ (0, _index5.triggerHaptic)('selection');
71
73
  setLightboxOpen(false);
72
74
  }, []);
73
75
  const renderImage = (0, _react.useCallback)((image, idx) => {
@@ -90,7 +92,7 @@ const ImageGallery = ({
90
92
  style: styles.thumbnailImage,
91
93
  resizeMode: "cover"
92
94
  }), [styles]);
93
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
95
+ const rendered = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
94
96
  style: [styles.container, containerStyle],
95
97
  testID: testID,
96
98
  accessibilityLabel: accessibilityLabel ?? 'Image gallery',
@@ -125,6 +127,14 @@ const ImageGallery = ({
125
127
  onIndexChange: handleIndexChange
126
128
  }) : null]
127
129
  });
130
+ if (loading) {
131
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_index3.SkeletonContent, {
132
+ loading: true,
133
+ mode: "auto",
134
+ children: rendered
135
+ });
136
+ }
137
+ return rendered;
128
138
  };
129
139
  exports.ImageGallery = ImageGallery;
130
140
  ImageGallery.displayName = 'ImageGallery';
@@ -140,13 +150,13 @@ const Lightbox = ({
140
150
  onClose,
141
151
  onIndexChange
142
152
  }) => {
143
- const theme = (0, _index3.useTheme)();
153
+ const theme = (0, _index4.useTheme)();
144
154
  const styles = (0, _react.useMemo)(() => buildLightboxStyles(theme), [theme]);
145
155
  const carouselRef = (0, _react.useRef)(null);
146
156
  const [activeIndex, setActiveIndex] = (0, _react.useState)(initialIndex);
147
157
  const handleSwipe = (0, _react.useCallback)(idx => {
148
158
  if (idx !== activeIndex) {
149
- (0, _index4.triggerHaptic)('selection');
159
+ (0, _index5.triggerHaptic)('selection');
150
160
  setActiveIndex(idx);
151
161
  onIndexChange(idx);
152
162
  }
@@ -255,7 +265,7 @@ const ZoomableImage = ({
255
265
  savedTranslateY.value = 0;
256
266
  }
257
267
  }, [active, scale, translateX, translateY, savedScale, savedTranslateX, savedTranslateY]);
258
- const triggerImpact = (0, _react.useCallback)(() => (0, _index4.triggerHaptic)('impactLight'), []);
268
+ const triggerImpact = (0, _react.useCallback)(() => (0, _index5.triggerHaptic)('impactLight'), []);
259
269
  const pinch = (0, _react.useMemo)(() => _reactNativeGestureHandler.Gesture.Pinch().enabled(enabled).onStart(() => {
260
270
  'worklet';
261
271
 
@@ -8,6 +8,7 @@ var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  var _index = require("../../theme/index.js");
10
10
  var _hapticUtils = require("../../utils/hapticUtils.js");
11
+ var _index2 = require("../Skeleton/index.js");
11
12
  var _jsxRuntime = require("react/jsx-runtime");
12
13
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
13
14
  const sizePxMap = {
@@ -83,6 +84,7 @@ const Rating = exports.Rating = /*#__PURE__*/(0, _react.forwardRef)((props, ref)
83
84
  size = 'md',
84
85
  tone = 'warning',
85
86
  label,
87
+ loading = false,
86
88
  accessibilityLabel,
87
89
  style,
88
90
  testID
@@ -168,7 +170,7 @@ const Rating = exports.Rating = /*#__PURE__*/(0, _react.forwardRef)((props, ref)
168
170
  children: star
169
171
  }, i));
170
172
  }
171
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
173
+ const rendered = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
172
174
  style: [styles.wrapper, style],
173
175
  ref: ref,
174
176
  testID: testID,
@@ -198,6 +200,14 @@ const Rating = exports.Rating = /*#__PURE__*/(0, _react.forwardRef)((props, ref)
198
200
  children: stars
199
201
  })]
200
202
  });
203
+ if (loading) {
204
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.SkeletonContent, {
205
+ loading: true,
206
+ mode: "auto",
207
+ children: rendered
208
+ });
209
+ }
210
+ return rendered;
201
211
  });
202
212
  Rating.displayName = 'Rating';
203
213
  const starStyles = _reactNative.StyleSheet.create({
@@ -8,6 +8,7 @@ var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  var _index = require("../../theme/index.js");
10
10
  var _hapticUtils = require("../../utils/hapticUtils.js");
11
+ var _index2 = require("../Skeleton/index.js");
11
12
  var _jsxRuntime = require("react/jsx-runtime");
12
13
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
13
14
  const CIRCLE_SIZE = 24;
@@ -164,6 +165,7 @@ const Stepper = exports.Stepper = /*#__PURE__*/(0, _react.forwardRef)((props, re
164
165
  onStepPress,
165
166
  variant = 'horizontal',
166
167
  tone = 'primary',
168
+ loading = false,
167
169
  accessibilityLabel,
168
170
  style,
169
171
  testID
@@ -238,7 +240,7 @@ const Stepper = exports.Stepper = /*#__PURE__*/(0, _react.forwardRef)((props, re
238
240
  fontSize: theme.typography.fontSize.xs
239
241
  }],
240
242
  numberOfLines: 1,
241
- children: step.label
243
+ children: step?.label ?? ' '
242
244
  })]
243
245
  }, step.key);
244
246
  })]
@@ -286,7 +288,7 @@ const Stepper = exports.Stepper = /*#__PURE__*/(0, _react.forwardRef)((props, re
286
288
  fontWeight: theme.typography.fontWeight.semibold
287
289
  }],
288
290
  numberOfLines: 1,
289
- children: step.label
291
+ children: step?.label ?? ' '
290
292
  }), step.description ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
291
293
  style: [styles.vDescription, {
292
294
  color: theme.colors.text.secondary,
@@ -299,7 +301,7 @@ const Stepper = exports.Stepper = /*#__PURE__*/(0, _react.forwardRef)((props, re
299
301
  }, step.key);
300
302
  })
301
303
  });
302
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
304
+ const rendered = /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
303
305
  ref: ref,
304
306
  style: [styles.container, style],
305
307
  testID: testID,
@@ -312,6 +314,14 @@ const Stepper = exports.Stepper = /*#__PURE__*/(0, _react.forwardRef)((props, re
312
314
  },
313
315
  children: variant === 'horizontal' ? renderHorizontal() : renderVertical()
314
316
  });
317
+ if (loading) {
318
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.SkeletonContent, {
319
+ loading: true,
320
+ mode: "auto",
321
+ children: rendered
322
+ });
323
+ }
324
+ return rendered;
315
325
  });
316
326
  Stepper.displayName = 'Stepper';
317
327
  const buildStyles = theme => _reactNative.StyleSheet.create({
@@ -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, { forwardRef, useEffect, 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 CIRCLE_SIZE = 24;
9
10
  const PULSE_SIZE = 32;
@@ -159,6 +160,7 @@ const Stepper = /*#__PURE__*/forwardRef((props, ref) => {
159
160
  onStepPress,
160
161
  variant = 'horizontal',
161
162
  tone = 'primary',
163
+ loading = false,
162
164
  accessibilityLabel,
163
165
  style,
164
166
  testID
@@ -233,7 +235,7 @@ const Stepper = /*#__PURE__*/forwardRef((props, ref) => {
233
235
  fontSize: theme.typography.fontSize.xs
234
236
  }],
235
237
  numberOfLines: 1,
236
- children: step.label
238
+ children: step?.label ?? ' '
237
239
  })]
238
240
  }, step.key);
239
241
  })]
@@ -281,7 +283,7 @@ const Stepper = /*#__PURE__*/forwardRef((props, ref) => {
281
283
  fontWeight: theme.typography.fontWeight.semibold
282
284
  }],
283
285
  numberOfLines: 1,
284
- children: step.label
286
+ children: step?.label ?? ' '
285
287
  }), step.description ? /*#__PURE__*/_jsx(Text, {
286
288
  style: [styles.vDescription, {
287
289
  color: theme.colors.text.secondary,
@@ -294,7 +296,7 @@ const Stepper = /*#__PURE__*/forwardRef((props, ref) => {
294
296
  }, step.key);
295
297
  })
296
298
  });
297
- return /*#__PURE__*/_jsx(View, {
299
+ const rendered = /*#__PURE__*/_jsx(View, {
298
300
  ref: ref,
299
301
  style: [styles.container, style],
300
302
  testID: testID,
@@ -307,6 +309,14 @@ const Stepper = /*#__PURE__*/forwardRef((props, ref) => {
307
309
  },
308
310
  children: variant === 'horizontal' ? renderHorizontal() : renderVertical()
309
311
  });
312
+ if (loading) {
313
+ return /*#__PURE__*/_jsx(SkeletonContent, {
314
+ loading: true,
315
+ mode: "auto",
316
+ children: rendered
317
+ });
318
+ }
319
+ return rendered;
310
320
  });
311
321
  Stepper.displayName = 'Stepper';
312
322
  const buildStyles = theme => StyleSheet.create({
@@ -16,6 +16,13 @@ export interface AccordionProps {
16
16
  headerStyle?: StyleProp<ViewStyle>;
17
17
  contentStyle?: StyleProp<ViewStyle>;
18
18
  testID?: string;
19
+ /**
20
+ * When true, renders the accordion as a skeleton placeholder via
21
+ * SkeletonContent's auto walker. The header title and any sized content
22
+ * leaves are replaced with shimmer blocks. Use this when the data driving
23
+ * the accordion is still being fetched.
24
+ */
25
+ loading?: boolean;
19
26
  }
20
27
  export interface AccordionGroupProps {
21
28
  children: React.ReactNode;
@@ -17,6 +17,12 @@ export interface BannerProps {
17
17
  onDismiss?: () => void;
18
18
  visible?: boolean;
19
19
  animateMount?: boolean;
20
+ /**
21
+ * When true, renders the component as a skeleton placeholder via SkeletonContent's auto walker.
22
+ * Component still renders its normal layout — the walker replaces Text/Image/sized View leaves
23
+ * with shimmer blocks. Use this when the data driving the component is still being fetched.
24
+ */
25
+ loading?: boolean;
20
26
  accessibilityLabel?: string;
21
27
  style?: StyleProp<ViewStyle>;
22
28
  testID?: string;
@@ -11,6 +11,11 @@ export interface ButtonProps extends Omit<PressableProps, 'style' | 'children'>
11
11
  variant?: ButtonVariant;
12
12
  tone?: ButtonTone;
13
13
  size?: ButtonSize;
14
+ /**
15
+ * When true, the button is disabled and renders a Spinner in place of the title (icons hidden).
16
+ * Use for in-flight submissions. This is **not** SkeletonContent — interactive controls signal
17
+ * pending action with an inline spinner, not a placeholder shimmer.
18
+ */
14
19
  loading?: boolean;
15
20
  disabled?: boolean;
16
21
  fullWidth?: boolean;
@@ -52,6 +52,13 @@ export interface CarouselProps<T = unknown> {
52
52
  * shape is `{ uri: string }`, otherwise a numbered placeholder.
53
53
  */
54
54
  renderThumbnail?: (item: T, index: number) => React.ReactNode;
55
+ /**
56
+ * When true, renders the carousel as a skeleton placeholder via
57
+ * SkeletonContent's auto walker. The walker replaces Text/Image/sized View
58
+ * leaves in the rendered slides with shimmer blocks. Use this when the data
59
+ * driving the carousel is still being fetched.
60
+ */
61
+ loading?: boolean;
55
62
  }
56
63
  export interface CarouselRef {
57
64
  scrollTo: (index: number, animated?: boolean) => void;
@@ -14,6 +14,12 @@ export interface ChipProps {
14
14
  tone?: ChipTone;
15
15
  size?: ChipSize;
16
16
  disabled?: boolean;
17
+ /**
18
+ * When true, renders the component as a skeleton placeholder via SkeletonContent's auto walker.
19
+ * Component still renders its normal layout — the walker replaces Text/Image/sized View leaves
20
+ * with shimmer blocks. Use this when the data driving the component is still being fetched.
21
+ */
22
+ loading?: boolean;
17
23
  accessibilityLabel?: string;
18
24
  style?: StyleProp<ViewStyle>;
19
25
  textStyle?: StyleProp<TextStyle>;
@@ -31,6 +31,12 @@ export interface ImageGalleryProps {
31
31
  enableLightbox?: boolean;
32
32
  enablePinchZoom?: boolean;
33
33
  onIndexChange?: (idx: number) => void;
34
+ /**
35
+ * When true, renders the component as a skeleton placeholder via SkeletonContent's auto walker.
36
+ * Component still renders its normal layout — the walker replaces Text/Image/sized View leaves
37
+ * with shimmer blocks. Use this when the data driving the component is still being fetched.
38
+ */
39
+ loading?: boolean;
34
40
  accessibilityLabel?: string;
35
41
  containerStyle?: StyleProp<ViewStyle>;
36
42
  testID?: string;
@@ -12,6 +12,12 @@ export interface RatingProps {
12
12
  size?: RatingSize;
13
13
  tone?: RatingTone;
14
14
  label?: string;
15
+ /**
16
+ * When true, renders the component as a skeleton placeholder via SkeletonContent's auto walker.
17
+ * Component still renders its normal layout — the walker replaces Text/Image/sized View leaves
18
+ * with shimmer blocks. Use this when the data driving the component is still being fetched.
19
+ */
20
+ loading?: boolean;
15
21
  accessibilityLabel?: string;
16
22
  style?: StyleProp<ViewStyle>;
17
23
  testID?: string;
@@ -15,6 +15,12 @@ export interface StepperProps {
15
15
  onStepPress?: (index: number) => void;
16
16
  variant?: StepperVariant;
17
17
  tone?: StepperTone;
18
+ /**
19
+ * When true, renders the component as a skeleton placeholder via SkeletonContent's auto walker.
20
+ * Component still renders its normal layout — the walker replaces Text/Image/sized View leaves
21
+ * with shimmer blocks. Use this when the data driving the component is still being fetched.
22
+ */
23
+ loading?: boolean;
18
24
  accessibilityLabel?: string;
19
25
  style?: StyleProp<ViewStyle>;
20
26
  testID?: string;
@@ -16,6 +16,13 @@ export interface AccordionProps {
16
16
  headerStyle?: StyleProp<ViewStyle>;
17
17
  contentStyle?: StyleProp<ViewStyle>;
18
18
  testID?: string;
19
+ /**
20
+ * When true, renders the accordion as a skeleton placeholder via
21
+ * SkeletonContent's auto walker. The header title and any sized content
22
+ * leaves are replaced with shimmer blocks. Use this when the data driving
23
+ * the accordion is still being fetched.
24
+ */
25
+ loading?: boolean;
19
26
  }
20
27
  export interface AccordionGroupProps {
21
28
  children: React.ReactNode;
@@ -17,6 +17,12 @@ export interface BannerProps {
17
17
  onDismiss?: () => void;
18
18
  visible?: boolean;
19
19
  animateMount?: boolean;
20
+ /**
21
+ * When true, renders the component as a skeleton placeholder via SkeletonContent's auto walker.
22
+ * Component still renders its normal layout — the walker replaces Text/Image/sized View leaves
23
+ * with shimmer blocks. Use this when the data driving the component is still being fetched.
24
+ */
25
+ loading?: boolean;
20
26
  accessibilityLabel?: string;
21
27
  style?: StyleProp<ViewStyle>;
22
28
  testID?: string;
@@ -11,6 +11,11 @@ export interface ButtonProps extends Omit<PressableProps, 'style' | 'children'>
11
11
  variant?: ButtonVariant;
12
12
  tone?: ButtonTone;
13
13
  size?: ButtonSize;
14
+ /**
15
+ * When true, the button is disabled and renders a Spinner in place of the title (icons hidden).
16
+ * Use for in-flight submissions. This is **not** SkeletonContent — interactive controls signal
17
+ * pending action with an inline spinner, not a placeholder shimmer.
18
+ */
14
19
  loading?: boolean;
15
20
  disabled?: boolean;
16
21
  fullWidth?: boolean;
@@ -52,6 +52,13 @@ export interface CarouselProps<T = unknown> {
52
52
  * shape is `{ uri: string }`, otherwise a numbered placeholder.
53
53
  */
54
54
  renderThumbnail?: (item: T, index: number) => React.ReactNode;
55
+ /**
56
+ * When true, renders the carousel as a skeleton placeholder via
57
+ * SkeletonContent's auto walker. The walker replaces Text/Image/sized View
58
+ * leaves in the rendered slides with shimmer blocks. Use this when the data
59
+ * driving the carousel is still being fetched.
60
+ */
61
+ loading?: boolean;
55
62
  }
56
63
  export interface CarouselRef {
57
64
  scrollTo: (index: number, animated?: boolean) => void;
@@ -14,6 +14,12 @@ export interface ChipProps {
14
14
  tone?: ChipTone;
15
15
  size?: ChipSize;
16
16
  disabled?: boolean;
17
+ /**
18
+ * When true, renders the component as a skeleton placeholder via SkeletonContent's auto walker.
19
+ * Component still renders its normal layout — the walker replaces Text/Image/sized View leaves
20
+ * with shimmer blocks. Use this when the data driving the component is still being fetched.
21
+ */
22
+ loading?: boolean;
17
23
  accessibilityLabel?: string;
18
24
  style?: StyleProp<ViewStyle>;
19
25
  textStyle?: StyleProp<TextStyle>;
@@ -31,6 +31,12 @@ export interface ImageGalleryProps {
31
31
  enableLightbox?: boolean;
32
32
  enablePinchZoom?: boolean;
33
33
  onIndexChange?: (idx: number) => void;
34
+ /**
35
+ * When true, renders the component as a skeleton placeholder via SkeletonContent's auto walker.
36
+ * Component still renders its normal layout — the walker replaces Text/Image/sized View leaves
37
+ * with shimmer blocks. Use this when the data driving the component is still being fetched.
38
+ */
39
+ loading?: boolean;
34
40
  accessibilityLabel?: string;
35
41
  containerStyle?: StyleProp<ViewStyle>;
36
42
  testID?: string;
@@ -12,6 +12,12 @@ export interface RatingProps {
12
12
  size?: RatingSize;
13
13
  tone?: RatingTone;
14
14
  label?: string;
15
+ /**
16
+ * When true, renders the component as a skeleton placeholder via SkeletonContent's auto walker.
17
+ * Component still renders its normal layout — the walker replaces Text/Image/sized View leaves
18
+ * with shimmer blocks. Use this when the data driving the component is still being fetched.
19
+ */
20
+ loading?: boolean;
15
21
  accessibilityLabel?: string;
16
22
  style?: StyleProp<ViewStyle>;
17
23
  testID?: string;
@@ -15,6 +15,12 @@ export interface StepperProps {
15
15
  onStepPress?: (index: number) => void;
16
16
  variant?: StepperVariant;
17
17
  tone?: StepperTone;
18
+ /**
19
+ * When true, renders the component as a skeleton placeholder via SkeletonContent's auto walker.
20
+ * Component still renders its normal layout — the walker replaces Text/Image/sized View leaves
21
+ * with shimmer blocks. Use this when the data driving the component is still being fetched.
22
+ */
23
+ loading?: boolean;
18
24
  accessibilityLabel?: string;
19
25
  style?: StyleProp<ViewStyle>;
20
26
  testID?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webority-technologies/mobile",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "Beautiful, animated, accessible React Native components plus API/auth/logging/network/storage utilities for Webority projects.",
5
5
  "keywords": [
6
6
  "react-native",