@webority-technologies/mobile 0.0.6 → 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.
- package/README.md +3 -463
- package/lib/commonjs/components/Skeleton/Skeleton.js +20 -12
- package/lib/commonjs/components/Skeleton/SkeletonContent.js +25 -9
- package/lib/commonjs/components/Skeleton/SkeletonList.js +7 -2
- package/lib/commonjs/components/Skeleton/SkeletonProvider.js +48 -0
- package/lib/commonjs/components/Skeleton/SkeletonSkip.js +37 -0
- package/lib/commonjs/components/Skeleton/index.js +20 -0
- package/lib/commonjs/components/index.js +18 -0
- package/lib/module/components/Skeleton/Skeleton.js +20 -12
- package/lib/module/components/Skeleton/SkeletonContent.js +25 -9
- package/lib/module/components/Skeleton/SkeletonList.js +7 -2
- package/lib/module/components/Skeleton/SkeletonProvider.js +41 -0
- package/lib/module/components/Skeleton/SkeletonSkip.js +31 -0
- package/lib/module/components/Skeleton/index.js +2 -0
- package/lib/module/components/index.js +1 -1
- package/lib/typescript/commonjs/components/Skeleton/Skeleton.d.ts +9 -0
- package/lib/typescript/commonjs/components/Skeleton/SkeletonContent.d.ts +6 -0
- package/lib/typescript/commonjs/components/Skeleton/SkeletonList.d.ts +3 -0
- package/lib/typescript/commonjs/components/Skeleton/SkeletonProvider.d.ts +32 -0
- package/lib/typescript/commonjs/components/Skeleton/SkeletonSkip.d.ts +25 -0
- package/lib/typescript/commonjs/components/Skeleton/index.d.ts +4 -0
- package/lib/typescript/commonjs/components/index.d.ts +2 -2
- package/lib/typescript/module/components/Skeleton/Skeleton.d.ts +9 -0
- package/lib/typescript/module/components/Skeleton/SkeletonContent.d.ts +6 -0
- package/lib/typescript/module/components/Skeleton/SkeletonList.d.ts +3 -0
- package/lib/typescript/module/components/Skeleton/SkeletonProvider.d.ts +32 -0
- package/lib/typescript/module/components/Skeleton/SkeletonSkip.d.ts +25 -0
- package/lib/typescript/module/components/Skeleton/index.d.ts +4 -0
- package/lib/typescript/module/components/index.d.ts +2 -2
- package/package.json +1 -1
|
@@ -7,6 +7,7 @@ exports.SkeletonList = void 0;
|
|
|
7
7
|
var _react = _interopRequireDefault(require("react"));
|
|
8
8
|
var _reactNative = require("react-native");
|
|
9
9
|
var _SkeletonContent = require("./SkeletonContent.js");
|
|
10
|
+
var _SkeletonProvider = require("./SkeletonProvider.js");
|
|
10
11
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
11
12
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
13
|
/**
|
|
@@ -32,9 +33,10 @@ function SkeletonListInner(props) {
|
|
|
32
33
|
data,
|
|
33
34
|
renderItem,
|
|
34
35
|
renderPlaceholder,
|
|
35
|
-
placeholderCount
|
|
36
|
+
placeholderCount,
|
|
36
37
|
variant,
|
|
37
38
|
speed,
|
|
39
|
+
colors,
|
|
38
40
|
placeholderContainerStyle,
|
|
39
41
|
horizontal,
|
|
40
42
|
contentContainerStyle,
|
|
@@ -42,9 +44,11 @@ function SkeletonListInner(props) {
|
|
|
42
44
|
testID,
|
|
43
45
|
...rest
|
|
44
46
|
} = props;
|
|
47
|
+
const defaults = (0, _SkeletonProvider.useSkeletonDefaults)();
|
|
48
|
+
const resolvedCount = placeholderCount ?? defaults.placeholderCount ?? 3;
|
|
45
49
|
if (loading) {
|
|
46
50
|
const slots = Array.from({
|
|
47
|
-
length: Math.max(0,
|
|
51
|
+
length: Math.max(0, resolvedCount)
|
|
48
52
|
}, (_, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_react.default.Fragment, {
|
|
49
53
|
children: renderPlaceholder ? renderPlaceholder(index) : null
|
|
50
54
|
}, `sk-list-${index}`));
|
|
@@ -52,6 +56,7 @@ function SkeletonListInner(props) {
|
|
|
52
56
|
loading: true,
|
|
53
57
|
variant: variant,
|
|
54
58
|
speed: speed,
|
|
59
|
+
colors: colors,
|
|
55
60
|
style: style,
|
|
56
61
|
testID: testID,
|
|
57
62
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.useSkeletonDefaults = exports.SkeletonProvider = void 0;
|
|
7
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
9
|
+
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); }
|
|
10
|
+
/**
|
|
11
|
+
* Per-instance color override for a skeleton. `background` is the resting tone
|
|
12
|
+
* of the placeholder; `highlight` is the moving shimmer band (or pulse fade).
|
|
13
|
+
* Either can be omitted — missing keys fall back to the active theme.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const SkeletonDefaultsContext = /*#__PURE__*/(0, _react.createContext)({});
|
|
17
|
+
const SkeletonProvider = ({
|
|
18
|
+
children,
|
|
19
|
+
variant,
|
|
20
|
+
speed,
|
|
21
|
+
placeholderCount,
|
|
22
|
+
radius,
|
|
23
|
+
colors
|
|
24
|
+
}) => {
|
|
25
|
+
const value = (0, _react.useMemo)(() => ({
|
|
26
|
+
variant,
|
|
27
|
+
speed,
|
|
28
|
+
placeholderCount,
|
|
29
|
+
radius,
|
|
30
|
+
colors
|
|
31
|
+
}), [variant, speed, placeholderCount, radius, colors]);
|
|
32
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(SkeletonDefaultsContext.Provider, {
|
|
33
|
+
value: value,
|
|
34
|
+
children: children
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
exports.SkeletonProvider = SkeletonProvider;
|
|
38
|
+
SkeletonProvider.displayName = 'SkeletonProvider';
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Read the current SkeletonProvider defaults. Returns an empty object when no
|
|
42
|
+
* provider is mounted, so the skeleton primitives still work outside of one.
|
|
43
|
+
*/
|
|
44
|
+
const useSkeletonDefaults = () => {
|
|
45
|
+
return (0, _react.useContext)(SkeletonDefaultsContext);
|
|
46
|
+
};
|
|
47
|
+
exports.useSkeletonDefaults = useSkeletonDefaults;
|
|
48
|
+
//# sourceMappingURL=SkeletonProvider.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.SkeletonSkip = void 0;
|
|
7
|
+
var _react = _interopRequireDefault(require("react"));
|
|
8
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
9
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
/**
|
|
11
|
+
* Pass-through marker that opts a subtree out of `SkeletonContent`'s auto walker.
|
|
12
|
+
*
|
|
13
|
+
* The walker recognizes this element type and returns its children unchanged
|
|
14
|
+
* even while `loading` is true. Use it to keep a specific Text/Image/View
|
|
15
|
+
* visible inside a skeleton block — e.g., a brand mark, a status icon, or a
|
|
16
|
+
* decorative element that should never shimmer.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* <SkeletonContent loading>
|
|
20
|
+
* <View style={styles.card}>
|
|
21
|
+
* <SkeletonSkip>
|
|
22
|
+
* <Image source={Logo} style={styles.brandMark} />
|
|
23
|
+
* </SkeletonSkip>
|
|
24
|
+
* <Text>Loading…</Text>
|
|
25
|
+
* </View>
|
|
26
|
+
* </SkeletonContent>
|
|
27
|
+
*/
|
|
28
|
+
const SkeletonSkip = ({
|
|
29
|
+
children
|
|
30
|
+
}) => {
|
|
31
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
|
|
32
|
+
children: children
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
exports.SkeletonSkip = SkeletonSkip;
|
|
36
|
+
SkeletonSkip.displayName = 'SkeletonSkip';
|
|
37
|
+
//# sourceMappingURL=SkeletonSkip.js.map
|
|
@@ -45,6 +45,18 @@ Object.defineProperty(exports, "SkeletonListItem", {
|
|
|
45
45
|
return _Skeleton.SkeletonListItem;
|
|
46
46
|
}
|
|
47
47
|
});
|
|
48
|
+
Object.defineProperty(exports, "SkeletonProvider", {
|
|
49
|
+
enumerable: true,
|
|
50
|
+
get: function () {
|
|
51
|
+
return _SkeletonProvider.SkeletonProvider;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
Object.defineProperty(exports, "SkeletonSkip", {
|
|
55
|
+
enumerable: true,
|
|
56
|
+
get: function () {
|
|
57
|
+
return _SkeletonSkip.SkeletonSkip;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
48
60
|
Object.defineProperty(exports, "SkeletonText", {
|
|
49
61
|
enumerable: true,
|
|
50
62
|
get: function () {
|
|
@@ -57,8 +69,16 @@ Object.defineProperty(exports, "default", {
|
|
|
57
69
|
return _Skeleton.default;
|
|
58
70
|
}
|
|
59
71
|
});
|
|
72
|
+
Object.defineProperty(exports, "useSkeletonDefaults", {
|
|
73
|
+
enumerable: true,
|
|
74
|
+
get: function () {
|
|
75
|
+
return _SkeletonProvider.useSkeletonDefaults;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
60
78
|
var _Skeleton = _interopRequireWildcard(require("./Skeleton.js"));
|
|
61
79
|
var _SkeletonContent = require("./SkeletonContent.js");
|
|
62
80
|
var _SkeletonList = require("./SkeletonList.js");
|
|
81
|
+
var _SkeletonProvider = require("./SkeletonProvider.js");
|
|
82
|
+
var _SkeletonSkip = require("./SkeletonSkip.js");
|
|
63
83
|
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); }
|
|
64
84
|
//# sourceMappingURL=index.js.map
|
|
@@ -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, { 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
|
|
32
|
-
variant
|
|
33
|
-
speed
|
|
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,
|
|
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 =
|
|
47
|
-
const animation =
|
|
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,
|
|
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 (
|
|
81
|
+
if (resolvedVariant === 'pulse') {
|
|
74
82
|
return /*#__PURE__*/_jsx(Animated.View, {
|
|
75
83
|
pointerEvents: "none",
|
|
76
84
|
style: [StyleSheet.absoluteFillObject, {
|
|
77
|
-
backgroundColor:
|
|
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:
|
|
103
|
+
backgroundColor: highlightColor,
|
|
96
104
|
transform: [{
|
|
97
105
|
translateX
|
|
98
106
|
}]
|
|
99
107
|
}]
|
|
100
108
|
});
|
|
101
|
-
}, [containerWidth, progress, styles.shimmer,
|
|
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
|
|
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
|
|
109
|
-
speed
|
|
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
|
|
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,
|
|
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
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
5
|
+
/**
|
|
6
|
+
* Pass-through marker that opts a subtree out of `SkeletonContent`'s auto walker.
|
|
7
|
+
*
|
|
8
|
+
* The walker recognizes this element type and returns its children unchanged
|
|
9
|
+
* even while `loading` is true. Use it to keep a specific Text/Image/View
|
|
10
|
+
* visible inside a skeleton block — e.g., a brand mark, a status icon, or a
|
|
11
|
+
* decorative element that should never shimmer.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* <SkeletonContent loading>
|
|
15
|
+
* <View style={styles.card}>
|
|
16
|
+
* <SkeletonSkip>
|
|
17
|
+
* <Image source={Logo} style={styles.brandMark} />
|
|
18
|
+
* </SkeletonSkip>
|
|
19
|
+
* <Text>Loading…</Text>
|
|
20
|
+
* </View>
|
|
21
|
+
* </SkeletonContent>
|
|
22
|
+
*/
|
|
23
|
+
export const SkeletonSkip = ({
|
|
24
|
+
children
|
|
25
|
+
}) => {
|
|
26
|
+
return /*#__PURE__*/_jsx(_Fragment, {
|
|
27
|
+
children: children
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
SkeletonSkip.displayName = 'SkeletonSkip';
|
|
31
|
+
//# sourceMappingURL=SkeletonSkip.js.map
|
|
@@ -3,4 +3,6 @@
|
|
|
3
3
|
export { Skeleton, SkeletonCircle, SkeletonText, SkeletonAvatar, SkeletonCard, SkeletonListItem, default } from "./Skeleton.js";
|
|
4
4
|
export { SkeletonContent } from "./SkeletonContent.js";
|
|
5
5
|
export { SkeletonList } from "./SkeletonList.js";
|
|
6
|
+
export { SkeletonProvider, useSkeletonDefaults } from "./SkeletonProvider.js";
|
|
7
|
+
export { SkeletonSkip } from "./SkeletonSkip.js";
|
|
6
8
|
//# sourceMappingURL=index.js.map
|
|
@@ -36,7 +36,7 @@ export { SearchBar } from "./SearchBar/index.js";
|
|
|
36
36
|
export { SegmentedControl } from "./SegmentedControl/index.js";
|
|
37
37
|
export { Select } from "./Select/index.js";
|
|
38
38
|
export { Stepper } from "./Stepper/index.js";
|
|
39
|
-
export { Skeleton, SkeletonAvatar, SkeletonCard, SkeletonCircle, SkeletonContent, SkeletonList, SkeletonListItem, SkeletonText } from "./Skeleton/index.js";
|
|
39
|
+
export { Skeleton, SkeletonAvatar, SkeletonCard, SkeletonCircle, SkeletonContent, SkeletonList, SkeletonListItem, SkeletonProvider, SkeletonSkip, SkeletonText, useSkeletonDefaults } from "./Skeleton/index.js";
|
|
40
40
|
export { Slider } from "./Slider/index.js";
|
|
41
41
|
export { Swipeable } from "./Swipeable/index.js";
|
|
42
42
|
export { Switch } from "./Switch/index.js";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { StyleProp, ViewStyle } from 'react-native';
|
|
3
3
|
import type { RadiusScale } from '../../theme/types';
|
|
4
|
+
import type { SkeletonColors } from './SkeletonProvider';
|
|
4
5
|
export type SkeletonVariant = 'shimmer' | 'pulse';
|
|
5
6
|
export type SkeletonSpeed = 'slow' | 'normal' | 'fast';
|
|
6
7
|
export type SkeletonRadius = keyof Pick<RadiusScale, 'sm' | 'md' | 'lg' | 'xl' | 'full'> | number;
|
|
@@ -12,6 +13,14 @@ export interface SkeletonProps {
|
|
|
12
13
|
radius?: SkeletonRadius;
|
|
13
14
|
variant?: SkeletonVariant;
|
|
14
15
|
speed?: SkeletonSpeed;
|
|
16
|
+
/**
|
|
17
|
+
* Per-instance colour override. Either `background` or `highlight` (or both)
|
|
18
|
+
* can be set; missing keys fall back to the SkeletonProvider's defaults
|
|
19
|
+
* and finally to the theme. Use this for one-off contrast adjustments
|
|
20
|
+
* (dark shimmer on a light banner, etc.) — for app-wide overrides prefer
|
|
21
|
+
* `<SkeletonProvider colors={{...}}>`.
|
|
22
|
+
*/
|
|
23
|
+
colors?: SkeletonColors;
|
|
15
24
|
style?: StyleProp<ViewStyle>;
|
|
16
25
|
testID?: string;
|
|
17
26
|
}
|
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import type { ReactNode } from 'react';
|
|
3
3
|
import type { StyleProp, ViewStyle } from 'react-native';
|
|
4
4
|
import type { SkeletonSpeed, SkeletonVariant } from './Skeleton';
|
|
5
|
+
import type { SkeletonColors } from './SkeletonProvider';
|
|
5
6
|
export type SkeletonContentMode = 'auto' | 'block';
|
|
6
7
|
export interface SkeletonContentProps {
|
|
7
8
|
/** When true, replace children with skeleton placeholders. */
|
|
@@ -26,6 +27,11 @@ export interface SkeletonContentProps {
|
|
|
26
27
|
* `loading` is false. Default: `1`.
|
|
27
28
|
*/
|
|
28
29
|
count?: number;
|
|
30
|
+
/**
|
|
31
|
+
* Colour override forwarded to every `<Skeleton>` produced by the walker. Either or both
|
|
32
|
+
* keys can be set; missing keys fall back to provider defaults / theme.
|
|
33
|
+
*/
|
|
34
|
+
colors?: SkeletonColors;
|
|
29
35
|
style?: StyleProp<ViewStyle>;
|
|
30
36
|
testID?: string;
|
|
31
37
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ReactElement, ReactNode } from 'react';
|
|
2
2
|
import type { FlatListProps, StyleProp, ViewStyle } from 'react-native';
|
|
3
3
|
import type { SkeletonSpeed, SkeletonVariant } from './Skeleton';
|
|
4
|
+
import type { SkeletonColors } from './SkeletonProvider';
|
|
4
5
|
export interface SkeletonListProps<ItemT> extends Omit<FlatListProps<ItemT>, 'data' | 'renderItem'> {
|
|
5
6
|
/** Whether the list is in its initial loading state. */
|
|
6
7
|
loading: boolean;
|
|
@@ -19,6 +20,8 @@ export interface SkeletonListProps<ItemT> extends Omit<FlatListProps<ItemT>, 'da
|
|
|
19
20
|
variant?: SkeletonVariant;
|
|
20
21
|
/** Animation speed — same as Skeleton. */
|
|
21
22
|
speed?: SkeletonSpeed;
|
|
23
|
+
/** Colour override forwarded to the placeholder skeletons. */
|
|
24
|
+
colors?: SkeletonColors;
|
|
22
25
|
/** Style applied to the wrapper View around the placeholders. */
|
|
23
26
|
placeholderContainerStyle?: StyleProp<ViewStyle>;
|
|
24
27
|
testID?: string;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
import type { SkeletonRadius, SkeletonSpeed, SkeletonVariant } from './Skeleton';
|
|
4
|
+
/**
|
|
5
|
+
* Per-instance color override for a skeleton. `background` is the resting tone
|
|
6
|
+
* of the placeholder; `highlight` is the moving shimmer band (or pulse fade).
|
|
7
|
+
* Either can be omitted — missing keys fall back to the active theme.
|
|
8
|
+
*/
|
|
9
|
+
export interface SkeletonColors {
|
|
10
|
+
background?: string;
|
|
11
|
+
highlight?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface SkeletonProviderDefaults {
|
|
14
|
+
variant?: SkeletonVariant;
|
|
15
|
+
speed?: SkeletonSpeed;
|
|
16
|
+
/** Default `placeholderCount` for `<SkeletonList>` when not specified per-instance. */
|
|
17
|
+
placeholderCount?: number;
|
|
18
|
+
/** Default `radius` for `<Skeleton>` when not specified per-instance. */
|
|
19
|
+
radius?: SkeletonRadius;
|
|
20
|
+
/** App-wide colour overrides for the shimmer base + highlight. */
|
|
21
|
+
colors?: SkeletonColors;
|
|
22
|
+
}
|
|
23
|
+
export interface SkeletonProviderProps extends SkeletonProviderDefaults {
|
|
24
|
+
children: ReactNode;
|
|
25
|
+
}
|
|
26
|
+
export declare const SkeletonProvider: React.FC<SkeletonProviderProps>;
|
|
27
|
+
/**
|
|
28
|
+
* Read the current SkeletonProvider defaults. Returns an empty object when no
|
|
29
|
+
* provider is mounted, so the skeleton primitives still work outside of one.
|
|
30
|
+
*/
|
|
31
|
+
export declare const useSkeletonDefaults: () => SkeletonProviderDefaults;
|
|
32
|
+
//# sourceMappingURL=SkeletonProvider.d.ts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
export interface SkeletonSkipProps {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Pass-through marker that opts a subtree out of `SkeletonContent`'s auto walker.
|
|
8
|
+
*
|
|
9
|
+
* The walker recognizes this element type and returns its children unchanged
|
|
10
|
+
* even while `loading` is true. Use it to keep a specific Text/Image/View
|
|
11
|
+
* visible inside a skeleton block — e.g., a brand mark, a status icon, or a
|
|
12
|
+
* decorative element that should never shimmer.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* <SkeletonContent loading>
|
|
16
|
+
* <View style={styles.card}>
|
|
17
|
+
* <SkeletonSkip>
|
|
18
|
+
* <Image source={Logo} style={styles.brandMark} />
|
|
19
|
+
* </SkeletonSkip>
|
|
20
|
+
* <Text>Loading…</Text>
|
|
21
|
+
* </View>
|
|
22
|
+
* </SkeletonContent>
|
|
23
|
+
*/
|
|
24
|
+
export declare const SkeletonSkip: React.FC<SkeletonSkipProps>;
|
|
25
|
+
//# sourceMappingURL=SkeletonSkip.d.ts.map
|