@webority-technologies/mobile 0.0.3 → 0.0.5
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 +44 -0
- package/lib/commonjs/components/Avatar/Avatar.js +12 -2
- package/lib/commonjs/components/Badge/Badge.js +17 -10
- package/lib/commonjs/components/Card/Card.js +22 -10
- package/lib/commonjs/components/ListItem/ListItem.js +15 -8
- package/lib/commonjs/components/Skeleton/SkeletonContent.js +8 -2
- package/lib/commonjs/components/Skeleton/SkeletonList.js +82 -0
- package/lib/commonjs/components/Skeleton/index.js +7 -0
- package/lib/commonjs/components/index.js +6 -0
- package/lib/module/components/Avatar/Avatar.js +12 -2
- package/lib/module/components/Badge/Badge.js +17 -10
- package/lib/module/components/Card/Card.js +22 -10
- package/lib/module/components/ListItem/ListItem.js +15 -8
- package/lib/module/components/Skeleton/SkeletonContent.js +8 -2
- package/lib/module/components/Skeleton/SkeletonList.js +77 -0
- package/lib/module/components/Skeleton/index.js +1 -0
- package/lib/module/components/index.js +1 -1
- package/lib/typescript/commonjs/components/Avatar/Avatar.d.ts +6 -0
- package/lib/typescript/commonjs/components/Badge/Badge.d.ts +6 -0
- package/lib/typescript/commonjs/components/Card/Card.d.ts +6 -0
- package/lib/typescript/commonjs/components/ListItem/ListItem.d.ts +6 -0
- package/lib/typescript/commonjs/components/Skeleton/SkeletonContent.d.ts +6 -0
- package/lib/typescript/commonjs/components/Skeleton/SkeletonList.d.ts +27 -0
- package/lib/typescript/commonjs/components/Skeleton/index.d.ts +2 -0
- package/lib/typescript/commonjs/components/index.d.ts +2 -2
- package/lib/typescript/module/components/Avatar/Avatar.d.ts +6 -0
- package/lib/typescript/module/components/Badge/Badge.d.ts +6 -0
- package/lib/typescript/module/components/Card/Card.d.ts +6 -0
- package/lib/typescript/module/components/ListItem/ListItem.d.ts +6 -0
- package/lib/typescript/module/components/Skeleton/SkeletonContent.d.ts +6 -0
- package/lib/typescript/module/components/Skeleton/SkeletonList.d.ts +27 -0
- package/lib/typescript/module/components/Skeleton/index.d.ts +2 -0
- package/lib/typescript/module/components/index.d.ts +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -394,6 +394,50 @@ For runnable usage of every component, see [`example/`](../../example/).
|
|
|
394
394
|
|
|
395
395
|
---
|
|
396
396
|
|
|
397
|
+
## Designing skeleton-aware components
|
|
398
|
+
|
|
399
|
+
Presentational primitives (`Card`, `ListItem`, `Avatar`, `Badge`) accept an optional
|
|
400
|
+
`loading?: boolean` prop. When `true`, the component renders its normal layout wrapped
|
|
401
|
+
in `<SkeletonContent loading mode="auto">` — the walker replaces every `<Text>`,
|
|
402
|
+
`<Image>`, and sized leaf `<View>` with a shimmer block matching the element's
|
|
403
|
+
dimensions. When `loading` is `false` or omitted, behaviour is unchanged.
|
|
404
|
+
|
|
405
|
+
Conventions for components that opt into this pattern:
|
|
406
|
+
|
|
407
|
+
- **Render gracefully with undefined data.** Use optional chaining and string defaults
|
|
408
|
+
so the auto walker has leaves to skeletonize even before data arrives:
|
|
409
|
+
`{item?.title ?? ' '}`, `{item?.subtitle ?? ' '}`. Never let a `<Text>` render `undefined`.
|
|
410
|
+
- **Use explicit dimensions on visual elements.** Set `width`/`height` on `<Image>` and
|
|
411
|
+
`<View>` leaves, and `fontSize` on `<Text>`, so the walker can size each shimmer
|
|
412
|
+
block correctly. Inline styles, `StyleSheet.create`, and arrays all work — they get
|
|
413
|
+
flattened.
|
|
414
|
+
- **Wrap once at the top.** Don't sprinkle `<SkeletonContent>` inside subtrees; wrap the
|
|
415
|
+
component's final return so the entire layout becomes a single coherent placeholder.
|
|
416
|
+
- **For data-driven lists, prefer `<SkeletonList>`.** It owns the "show N placeholder
|
|
417
|
+
rows while loading, then real data" branching so callers don't hand-roll it.
|
|
418
|
+
|
|
419
|
+
Before / after with `Card`:
|
|
420
|
+
|
|
421
|
+
```tsx
|
|
422
|
+
// 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
|
+
)}
|
|
431
|
+
|
|
432
|
+
// After — Card itself is skeleton-aware
|
|
433
|
+
<Card loading={loading}>
|
|
434
|
+
<Text>{site?.name ?? ' '}</Text>
|
|
435
|
+
<Text>{site?.address ?? ' '}</Text>
|
|
436
|
+
</Card>
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
397
441
|
## License
|
|
398
442
|
|
|
399
443
|
MIT. Copyright © Webority Technologies.
|
|
@@ -7,6 +7,7 @@ exports.default = exports.AvatarGroup = exports.Avatar = 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 sizeMap = {
|
|
@@ -69,6 +70,7 @@ const Avatar = exports.Avatar = /*#__PURE__*/(0, _react.forwardRef)((props, ref)
|
|
|
69
70
|
statusPosition = 'bottomRight',
|
|
70
71
|
backgroundColor,
|
|
71
72
|
color,
|
|
73
|
+
loading = false,
|
|
72
74
|
accessibilityLabel,
|
|
73
75
|
style,
|
|
74
76
|
textStyle,
|
|
@@ -89,7 +91,7 @@ const Avatar = exports.Avatar = /*#__PURE__*/(0, _react.forwardRef)((props, ref)
|
|
|
89
91
|
const statusSize = Math.max(8, Math.round(dimension * 0.25));
|
|
90
92
|
const statusBorder = 2;
|
|
91
93
|
const a11yLabel = accessibilityLabel ?? (name ? `${name}'s avatar` : 'Avatar');
|
|
92
|
-
|
|
94
|
+
const rendered = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
93
95
|
ref: ref,
|
|
94
96
|
style: [styles.root, {
|
|
95
97
|
width: dimension,
|
|
@@ -119,7 +121,7 @@ const Avatar = exports.Avatar = /*#__PURE__*/(0, _react.forwardRef)((props, ref)
|
|
|
119
121
|
}, textStyle],
|
|
120
122
|
numberOfLines: 1,
|
|
121
123
|
allowFontScaling: false,
|
|
122
|
-
children: initials
|
|
124
|
+
children: initials ?? ' '
|
|
123
125
|
}), status ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
124
126
|
style: [styles.status, statusPosition === 'topRight' ? styles.statusTopRight : styles.statusBottomRight, {
|
|
125
127
|
width: statusSize,
|
|
@@ -133,6 +135,14 @@ const Avatar = exports.Avatar = /*#__PURE__*/(0, _react.forwardRef)((props, ref)
|
|
|
133
135
|
pointerEvents: "none"
|
|
134
136
|
}) : null]
|
|
135
137
|
});
|
|
138
|
+
if (loading) {
|
|
139
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.SkeletonContent, {
|
|
140
|
+
loading: true,
|
|
141
|
+
mode: "auto",
|
|
142
|
+
children: rendered
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return rendered;
|
|
136
146
|
});
|
|
137
147
|
Avatar.displayName = 'Avatar';
|
|
138
148
|
const styles = _reactNative.StyleSheet.create({
|
|
@@ -7,6 +7,7 @@ exports.default = exports.Badge = 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 toneFor = (theme, tone) => {
|
|
@@ -102,6 +103,7 @@ const Badge = exports.Badge = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =
|
|
|
102
103
|
tone = 'error',
|
|
103
104
|
size = 'sm',
|
|
104
105
|
invisible = false,
|
|
106
|
+
loading = false,
|
|
105
107
|
children,
|
|
106
108
|
anchor = 'topRight',
|
|
107
109
|
pulse = false,
|
|
@@ -174,23 +176,28 @@ const Badge = exports.Badge = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =
|
|
|
174
176
|
}, textStyle],
|
|
175
177
|
numberOfLines: 1,
|
|
176
178
|
allowFontScaling: false,
|
|
177
|
-
children: formatted
|
|
179
|
+
children: formatted ?? ' '
|
|
178
180
|
}) : null
|
|
179
181
|
}) : null;
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
182
|
+
const rendered = children ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
183
|
+
ref: ref,
|
|
184
|
+
style: [styles.wrapper, style],
|
|
185
|
+
testID: testID,
|
|
186
|
+
children: [children, badgeContent]
|
|
187
|
+
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
189
188
|
ref: ref,
|
|
190
189
|
style: style,
|
|
191
190
|
testID: testID,
|
|
192
191
|
children: badgeContent
|
|
193
192
|
});
|
|
193
|
+
if (loading) {
|
|
194
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.SkeletonContent, {
|
|
195
|
+
loading: true,
|
|
196
|
+
mode: "auto",
|
|
197
|
+
children: rendered
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
return rendered;
|
|
194
201
|
});
|
|
195
202
|
Badge.displayName = 'Badge';
|
|
196
203
|
const styles = _reactNative.StyleSheet.create({
|
|
@@ -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 paddingMap = {
|
|
@@ -32,6 +33,7 @@ const Card = exports.Card = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
|
|
|
32
33
|
imageHeight = 160,
|
|
33
34
|
imageAspectRatio,
|
|
34
35
|
imageOverlay,
|
|
36
|
+
loading = false,
|
|
35
37
|
onPress,
|
|
36
38
|
accessibilityLabel,
|
|
37
39
|
accessibilityHint,
|
|
@@ -132,12 +134,13 @@ const Card = exports.Card = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
|
|
|
132
134
|
children: innerContent
|
|
133
135
|
})]
|
|
134
136
|
}) : innerContent;
|
|
137
|
+
let rendered;
|
|
135
138
|
if (isInteractive) {
|
|
136
139
|
const handlePress = event => {
|
|
137
140
|
(0, _hapticUtils.triggerHaptic)('selection');
|
|
138
141
|
onPress?.(event);
|
|
139
142
|
};
|
|
140
|
-
|
|
143
|
+
rendered = /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Animated.View, {
|
|
141
144
|
style: [{
|
|
142
145
|
transform: [{
|
|
143
146
|
scale
|
|
@@ -161,16 +164,25 @@ const Card = exports.Card = /*#__PURE__*/(0, _react.forwardRef)((props, ref) =>
|
|
|
161
164
|
children: content
|
|
162
165
|
})
|
|
163
166
|
});
|
|
167
|
+
} else {
|
|
168
|
+
rendered = /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
169
|
+
ref: ref,
|
|
170
|
+
accessibilityLabel: accessibilityLabel,
|
|
171
|
+
accessibilityHint: accessibilityHint,
|
|
172
|
+
accessibilityRole: accessibilityRole,
|
|
173
|
+
testID: testID,
|
|
174
|
+
style: [containerStyle, style],
|
|
175
|
+
children: content
|
|
176
|
+
});
|
|
164
177
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
});
|
|
178
|
+
if (loading) {
|
|
179
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.SkeletonContent, {
|
|
180
|
+
loading: true,
|
|
181
|
+
mode: "auto",
|
|
182
|
+
children: rendered
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
return rendered;
|
|
174
186
|
});
|
|
175
187
|
Card.displayName = 'Card';
|
|
176
188
|
const buildStyles = theme => _reactNative.StyleSheet.create({
|
|
@@ -10,6 +10,7 @@ var _index = require("../../theme/index.js");
|
|
|
10
10
|
var _usePressAnimation = require("../../hooks/usePressAnimation.js");
|
|
11
11
|
var _hapticUtils = require("../../utils/hapticUtils.js");
|
|
12
12
|
var _index2 = require("../Swipeable/index.js");
|
|
13
|
+
var _index3 = require("../Skeleton/index.js");
|
|
13
14
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
14
15
|
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); }
|
|
15
16
|
const sizeFor = (theme, size) => {
|
|
@@ -56,6 +57,7 @@ const chevronStyles = _reactNative.StyleSheet.create({
|
|
|
56
57
|
const ListItem = exports.ListItem = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
|
|
57
58
|
const {
|
|
58
59
|
title,
|
|
60
|
+
loading = false,
|
|
59
61
|
subtitle,
|
|
60
62
|
description,
|
|
61
63
|
left,
|
|
@@ -108,7 +110,7 @@ const ListItem = exports.ListItem = /*#__PURE__*/(0, _react.forwardRef)((props,
|
|
|
108
110
|
color: disabled ? theme.colors.text.disabled : theme.colors.text.primary
|
|
109
111
|
}],
|
|
110
112
|
numberOfLines: 1,
|
|
111
|
-
children: title
|
|
113
|
+
children: title ?? ' '
|
|
112
114
|
}), subtitle ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
113
115
|
style: [styles.subtitle, {
|
|
114
116
|
fontSize: sz.subtitleSize,
|
|
@@ -179,15 +181,20 @@ const ListItem = exports.ListItem = /*#__PURE__*/(0, _react.forwardRef)((props,
|
|
|
179
181
|
|
|
180
182
|
// Wrap in Swipeable only when at least one side has actions; otherwise keep zero gesture overhead.
|
|
181
183
|
const hasSwipe = leftActions && leftActions.length > 0 || rightActions && rightActions.length > 0;
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
184
|
+
const final = hasSwipe ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_index2.Swipeable, {
|
|
185
|
+
leftActions: leftActions,
|
|
186
|
+
rightActions: rightActions,
|
|
187
|
+
accessibilityLabel: a11yLabel,
|
|
188
|
+
children: rendered
|
|
189
|
+
}) : rendered;
|
|
190
|
+
if (loading) {
|
|
191
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_index3.SkeletonContent, {
|
|
192
|
+
loading: true,
|
|
193
|
+
mode: "auto",
|
|
194
|
+
children: final
|
|
188
195
|
});
|
|
189
196
|
}
|
|
190
|
-
return
|
|
197
|
+
return final;
|
|
191
198
|
});
|
|
192
199
|
ListItem.displayName = 'ListItem';
|
|
193
200
|
const buildStyles = theme => _reactNative.StyleSheet.create({
|
|
@@ -113,6 +113,7 @@ const SkeletonContent = ({
|
|
|
113
113
|
variant = 'shimmer',
|
|
114
114
|
speed = 'normal',
|
|
115
115
|
mode = 'auto',
|
|
116
|
+
count = 1,
|
|
116
117
|
style,
|
|
117
118
|
testID
|
|
118
119
|
}) => {
|
|
@@ -121,13 +122,18 @@ const SkeletonContent = ({
|
|
|
121
122
|
children: children
|
|
122
123
|
});
|
|
123
124
|
}
|
|
125
|
+
const repeated = count > 1 ? Array.from({
|
|
126
|
+
length: count
|
|
127
|
+
}, (_, i) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_react.default.Fragment, {
|
|
128
|
+
children: children
|
|
129
|
+
}, `sk-rep-${i}`)) : children;
|
|
124
130
|
if (mode === 'block') {
|
|
125
131
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(BlockSkeleton, {
|
|
126
132
|
style: style,
|
|
127
133
|
testID: testID,
|
|
128
134
|
variant: variant,
|
|
129
135
|
speed: speed,
|
|
130
|
-
children:
|
|
136
|
+
children: repeated
|
|
131
137
|
});
|
|
132
138
|
}
|
|
133
139
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
@@ -137,7 +143,7 @@ const SkeletonContent = ({
|
|
|
137
143
|
accessibilityLabel: "Loading",
|
|
138
144
|
accessibilityRole: "progressbar",
|
|
139
145
|
accessibilityLiveRegion: "polite",
|
|
140
|
-
children: skeletonizeNode(
|
|
146
|
+
children: skeletonizeNode(repeated, variant, speed)
|
|
141
147
|
});
|
|
142
148
|
};
|
|
143
149
|
exports.SkeletonContent = SkeletonContent;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.SkeletonList = void 0;
|
|
7
|
+
var _react = _interopRequireDefault(require("react"));
|
|
8
|
+
var _reactNative = require("react-native");
|
|
9
|
+
var _SkeletonContent = require("./SkeletonContent.js");
|
|
10
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
11
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
+
/**
|
|
13
|
+
* Drop-in FlatList replacement that renders `placeholderCount` skeleton rows while
|
|
14
|
+
* `loading` is true, then transitions to a real `<FlatList>` of `data` once loaded.
|
|
15
|
+
*
|
|
16
|
+
* Solves the "FlatList with empty data renders nothing" problem so consumer screens
|
|
17
|
+
* don't have to maintain a separate placeholder branch.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* <SkeletonList
|
|
21
|
+
* loading={isLoading}
|
|
22
|
+
* data={sites}
|
|
23
|
+
* renderItem={({ item }) => <SiteCard item={item} />}
|
|
24
|
+
* renderPlaceholder={() => <SiteCard loading />}
|
|
25
|
+
* placeholderCount={3}
|
|
26
|
+
* horizontal
|
|
27
|
+
* />
|
|
28
|
+
*/
|
|
29
|
+
function SkeletonListInner(props) {
|
|
30
|
+
const {
|
|
31
|
+
loading,
|
|
32
|
+
data,
|
|
33
|
+
renderItem,
|
|
34
|
+
renderPlaceholder,
|
|
35
|
+
placeholderCount = 3,
|
|
36
|
+
variant,
|
|
37
|
+
speed,
|
|
38
|
+
placeholderContainerStyle,
|
|
39
|
+
horizontal,
|
|
40
|
+
contentContainerStyle,
|
|
41
|
+
style,
|
|
42
|
+
testID,
|
|
43
|
+
...rest
|
|
44
|
+
} = props;
|
|
45
|
+
if (loading) {
|
|
46
|
+
const slots = Array.from({
|
|
47
|
+
length: Math.max(0, placeholderCount)
|
|
48
|
+
}, (_, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_react.default.Fragment, {
|
|
49
|
+
children: renderPlaceholder ? renderPlaceholder(index) : null
|
|
50
|
+
}, `sk-list-${index}`));
|
|
51
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_SkeletonContent.SkeletonContent, {
|
|
52
|
+
loading: true,
|
|
53
|
+
variant: variant,
|
|
54
|
+
speed: speed,
|
|
55
|
+
style: style,
|
|
56
|
+
testID: testID,
|
|
57
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
58
|
+
style: [horizontal ? styles.row : styles.column, placeholderContainerStyle],
|
|
59
|
+
children: slots
|
|
60
|
+
})
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
|
|
64
|
+
data: data ?? [],
|
|
65
|
+
renderItem: renderItem,
|
|
66
|
+
horizontal: horizontal,
|
|
67
|
+
contentContainerStyle: contentContainerStyle,
|
|
68
|
+
style: style,
|
|
69
|
+
testID: testID,
|
|
70
|
+
...rest
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
const styles = {
|
|
74
|
+
row: {
|
|
75
|
+
flexDirection: 'row'
|
|
76
|
+
},
|
|
77
|
+
column: {
|
|
78
|
+
flexDirection: 'column'
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
const SkeletonList = exports.SkeletonList = SkeletonListInner;
|
|
82
|
+
//# sourceMappingURL=SkeletonList.js.map
|
|
@@ -33,6 +33,12 @@ Object.defineProperty(exports, "SkeletonContent", {
|
|
|
33
33
|
return _SkeletonContent.SkeletonContent;
|
|
34
34
|
}
|
|
35
35
|
});
|
|
36
|
+
Object.defineProperty(exports, "SkeletonList", {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
get: function () {
|
|
39
|
+
return _SkeletonList.SkeletonList;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
36
42
|
Object.defineProperty(exports, "SkeletonListItem", {
|
|
37
43
|
enumerable: true,
|
|
38
44
|
get: function () {
|
|
@@ -53,5 +59,6 @@ Object.defineProperty(exports, "default", {
|
|
|
53
59
|
});
|
|
54
60
|
var _Skeleton = _interopRequireWildcard(require("./Skeleton.js"));
|
|
55
61
|
var _SkeletonContent = require("./SkeletonContent.js");
|
|
62
|
+
var _SkeletonList = require("./SkeletonList.js");
|
|
56
63
|
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); }
|
|
57
64
|
//# sourceMappingURL=index.js.map
|
|
@@ -261,6 +261,12 @@ Object.defineProperty(exports, "SkeletonContent", {
|
|
|
261
261
|
return _index35.SkeletonContent;
|
|
262
262
|
}
|
|
263
263
|
});
|
|
264
|
+
Object.defineProperty(exports, "SkeletonList", {
|
|
265
|
+
enumerable: true,
|
|
266
|
+
get: function () {
|
|
267
|
+
return _index35.SkeletonList;
|
|
268
|
+
}
|
|
269
|
+
});
|
|
264
270
|
Object.defineProperty(exports, "SkeletonListItem", {
|
|
265
271
|
enumerable: true,
|
|
266
272
|
get: function () {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import React, { Children, cloneElement, forwardRef, isValidElement, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
4
|
import { Animated, Easing, Image, 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 sizeMap = {
|
|
8
9
|
xs: 24,
|
|
@@ -64,6 +65,7 @@ const Avatar = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
64
65
|
statusPosition = 'bottomRight',
|
|
65
66
|
backgroundColor,
|
|
66
67
|
color,
|
|
68
|
+
loading = false,
|
|
67
69
|
accessibilityLabel,
|
|
68
70
|
style,
|
|
69
71
|
textStyle,
|
|
@@ -84,7 +86,7 @@ const Avatar = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
84
86
|
const statusSize = Math.max(8, Math.round(dimension * 0.25));
|
|
85
87
|
const statusBorder = 2;
|
|
86
88
|
const a11yLabel = accessibilityLabel ?? (name ? `${name}'s avatar` : 'Avatar');
|
|
87
|
-
|
|
89
|
+
const rendered = /*#__PURE__*/_jsxs(View, {
|
|
88
90
|
ref: ref,
|
|
89
91
|
style: [styles.root, {
|
|
90
92
|
width: dimension,
|
|
@@ -114,7 +116,7 @@ const Avatar = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
114
116
|
}, textStyle],
|
|
115
117
|
numberOfLines: 1,
|
|
116
118
|
allowFontScaling: false,
|
|
117
|
-
children: initials
|
|
119
|
+
children: initials ?? ' '
|
|
118
120
|
}), status ? /*#__PURE__*/_jsx(View, {
|
|
119
121
|
style: [styles.status, statusPosition === 'topRight' ? styles.statusTopRight : styles.statusBottomRight, {
|
|
120
122
|
width: statusSize,
|
|
@@ -128,6 +130,14 @@ const Avatar = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
128
130
|
pointerEvents: "none"
|
|
129
131
|
}) : null]
|
|
130
132
|
});
|
|
133
|
+
if (loading) {
|
|
134
|
+
return /*#__PURE__*/_jsx(SkeletonContent, {
|
|
135
|
+
loading: true,
|
|
136
|
+
mode: "auto",
|
|
137
|
+
children: rendered
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
return rendered;
|
|
131
141
|
});
|
|
132
142
|
Avatar.displayName = 'Avatar';
|
|
133
143
|
const styles = StyleSheet.create({
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import React, { forwardRef, useEffect, useMemo, useRef } from 'react';
|
|
4
4
|
import { Animated, Easing, 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 toneFor = (theme, tone) => {
|
|
8
9
|
switch (tone) {
|
|
@@ -97,6 +98,7 @@ const Badge = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
97
98
|
tone = 'error',
|
|
98
99
|
size = 'sm',
|
|
99
100
|
invisible = false,
|
|
101
|
+
loading = false,
|
|
100
102
|
children,
|
|
101
103
|
anchor = 'topRight',
|
|
102
104
|
pulse = false,
|
|
@@ -169,23 +171,28 @@ const Badge = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
169
171
|
}, textStyle],
|
|
170
172
|
numberOfLines: 1,
|
|
171
173
|
allowFontScaling: false,
|
|
172
|
-
children: formatted
|
|
174
|
+
children: formatted ?? ' '
|
|
173
175
|
}) : null
|
|
174
176
|
}) : null;
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
return /*#__PURE__*/_jsx(View, {
|
|
177
|
+
const rendered = children ? /*#__PURE__*/_jsxs(View, {
|
|
178
|
+
ref: ref,
|
|
179
|
+
style: [styles.wrapper, style],
|
|
180
|
+
testID: testID,
|
|
181
|
+
children: [children, badgeContent]
|
|
182
|
+
}) : /*#__PURE__*/_jsx(View, {
|
|
184
183
|
ref: ref,
|
|
185
184
|
style: style,
|
|
186
185
|
testID: testID,
|
|
187
186
|
children: badgeContent
|
|
188
187
|
});
|
|
188
|
+
if (loading) {
|
|
189
|
+
return /*#__PURE__*/_jsx(SkeletonContent, {
|
|
190
|
+
loading: true,
|
|
191
|
+
mode: "auto",
|
|
192
|
+
children: rendered
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
return rendered;
|
|
189
196
|
});
|
|
190
197
|
Badge.displayName = 'Badge';
|
|
191
198
|
const styles = StyleSheet.create({
|
|
@@ -5,6 +5,7 @@ import { Animated, Image, Pressable, StyleSheet, 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, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
9
10
|
const paddingMap = {
|
|
10
11
|
none: 'none',
|
|
@@ -27,6 +28,7 @@ const Card = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
27
28
|
imageHeight = 160,
|
|
28
29
|
imageAspectRatio,
|
|
29
30
|
imageOverlay,
|
|
31
|
+
loading = false,
|
|
30
32
|
onPress,
|
|
31
33
|
accessibilityLabel,
|
|
32
34
|
accessibilityHint,
|
|
@@ -127,12 +129,13 @@ const Card = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
127
129
|
children: innerContent
|
|
128
130
|
})]
|
|
129
131
|
}) : innerContent;
|
|
132
|
+
let rendered;
|
|
130
133
|
if (isInteractive) {
|
|
131
134
|
const handlePress = event => {
|
|
132
135
|
triggerHaptic('selection');
|
|
133
136
|
onPress?.(event);
|
|
134
137
|
};
|
|
135
|
-
|
|
138
|
+
rendered = /*#__PURE__*/_jsx(Animated.View, {
|
|
136
139
|
style: [{
|
|
137
140
|
transform: [{
|
|
138
141
|
scale
|
|
@@ -156,16 +159,25 @@ const Card = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
156
159
|
children: content
|
|
157
160
|
})
|
|
158
161
|
});
|
|
162
|
+
} else {
|
|
163
|
+
rendered = /*#__PURE__*/_jsx(View, {
|
|
164
|
+
ref: ref,
|
|
165
|
+
accessibilityLabel: accessibilityLabel,
|
|
166
|
+
accessibilityHint: accessibilityHint,
|
|
167
|
+
accessibilityRole: accessibilityRole,
|
|
168
|
+
testID: testID,
|
|
169
|
+
style: [containerStyle, style],
|
|
170
|
+
children: content
|
|
171
|
+
});
|
|
159
172
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
});
|
|
173
|
+
if (loading) {
|
|
174
|
+
return /*#__PURE__*/_jsx(SkeletonContent, {
|
|
175
|
+
loading: true,
|
|
176
|
+
mode: "auto",
|
|
177
|
+
children: rendered
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
return rendered;
|
|
169
181
|
});
|
|
170
182
|
Card.displayName = 'Card';
|
|
171
183
|
const buildStyles = theme => StyleSheet.create({
|
|
@@ -6,6 +6,7 @@ import { useTheme } from "../../theme/index.js";
|
|
|
6
6
|
import { usePressAnimation } from "../../hooks/usePressAnimation.js";
|
|
7
7
|
import { triggerHaptic } from "../../utils/hapticUtils.js";
|
|
8
8
|
import { Swipeable } from "../Swipeable/index.js";
|
|
9
|
+
import { SkeletonContent } from "../Skeleton/index.js";
|
|
9
10
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
10
11
|
const sizeFor = (theme, size) => {
|
|
11
12
|
switch (size) {
|
|
@@ -51,6 +52,7 @@ const chevronStyles = StyleSheet.create({
|
|
|
51
52
|
const ListItem = /*#__PURE__*/forwardRef((props, ref) => {
|
|
52
53
|
const {
|
|
53
54
|
title,
|
|
55
|
+
loading = false,
|
|
54
56
|
subtitle,
|
|
55
57
|
description,
|
|
56
58
|
left,
|
|
@@ -103,7 +105,7 @@ const ListItem = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
103
105
|
color: disabled ? theme.colors.text.disabled : theme.colors.text.primary
|
|
104
106
|
}],
|
|
105
107
|
numberOfLines: 1,
|
|
106
|
-
children: title
|
|
108
|
+
children: title ?? ' '
|
|
107
109
|
}), subtitle ? /*#__PURE__*/_jsx(Text, {
|
|
108
110
|
style: [styles.subtitle, {
|
|
109
111
|
fontSize: sz.subtitleSize,
|
|
@@ -174,15 +176,20 @@ const ListItem = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
174
176
|
|
|
175
177
|
// Wrap in Swipeable only when at least one side has actions; otherwise keep zero gesture overhead.
|
|
176
178
|
const hasSwipe = leftActions && leftActions.length > 0 || rightActions && rightActions.length > 0;
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
179
|
+
const final = hasSwipe ? /*#__PURE__*/_jsx(Swipeable, {
|
|
180
|
+
leftActions: leftActions,
|
|
181
|
+
rightActions: rightActions,
|
|
182
|
+
accessibilityLabel: a11yLabel,
|
|
183
|
+
children: rendered
|
|
184
|
+
}) : rendered;
|
|
185
|
+
if (loading) {
|
|
186
|
+
return /*#__PURE__*/_jsx(SkeletonContent, {
|
|
187
|
+
loading: true,
|
|
188
|
+
mode: "auto",
|
|
189
|
+
children: final
|
|
183
190
|
});
|
|
184
191
|
}
|
|
185
|
-
return
|
|
192
|
+
return final;
|
|
186
193
|
});
|
|
187
194
|
ListItem.displayName = 'ListItem';
|
|
188
195
|
const buildStyles = theme => StyleSheet.create({
|
|
@@ -108,6 +108,7 @@ const SkeletonContent = ({
|
|
|
108
108
|
variant = 'shimmer',
|
|
109
109
|
speed = 'normal',
|
|
110
110
|
mode = 'auto',
|
|
111
|
+
count = 1,
|
|
111
112
|
style,
|
|
112
113
|
testID
|
|
113
114
|
}) => {
|
|
@@ -116,13 +117,18 @@ const SkeletonContent = ({
|
|
|
116
117
|
children: children
|
|
117
118
|
});
|
|
118
119
|
}
|
|
120
|
+
const repeated = count > 1 ? Array.from({
|
|
121
|
+
length: count
|
|
122
|
+
}, (_, i) => /*#__PURE__*/_jsx(React.Fragment, {
|
|
123
|
+
children: children
|
|
124
|
+
}, `sk-rep-${i}`)) : children;
|
|
119
125
|
if (mode === 'block') {
|
|
120
126
|
return /*#__PURE__*/_jsx(BlockSkeleton, {
|
|
121
127
|
style: style,
|
|
122
128
|
testID: testID,
|
|
123
129
|
variant: variant,
|
|
124
130
|
speed: speed,
|
|
125
|
-
children:
|
|
131
|
+
children: repeated
|
|
126
132
|
});
|
|
127
133
|
}
|
|
128
134
|
return /*#__PURE__*/_jsx(View, {
|
|
@@ -132,7 +138,7 @@ const SkeletonContent = ({
|
|
|
132
138
|
accessibilityLabel: "Loading",
|
|
133
139
|
accessibilityRole: "progressbar",
|
|
134
140
|
accessibilityLiveRegion: "polite",
|
|
135
|
-
children: skeletonizeNode(
|
|
141
|
+
children: skeletonizeNode(repeated, variant, speed)
|
|
136
142
|
});
|
|
137
143
|
};
|
|
138
144
|
SkeletonContent.displayName = 'SkeletonContent';
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { FlatList, View } from 'react-native';
|
|
5
|
+
import { SkeletonContent } from "./SkeletonContent.js";
|
|
6
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
|
+
/**
|
|
8
|
+
* Drop-in FlatList replacement that renders `placeholderCount` skeleton rows while
|
|
9
|
+
* `loading` is true, then transitions to a real `<FlatList>` of `data` once loaded.
|
|
10
|
+
*
|
|
11
|
+
* Solves the "FlatList with empty data renders nothing" problem so consumer screens
|
|
12
|
+
* don't have to maintain a separate placeholder branch.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* <SkeletonList
|
|
16
|
+
* loading={isLoading}
|
|
17
|
+
* data={sites}
|
|
18
|
+
* renderItem={({ item }) => <SiteCard item={item} />}
|
|
19
|
+
* renderPlaceholder={() => <SiteCard loading />}
|
|
20
|
+
* placeholderCount={3}
|
|
21
|
+
* horizontal
|
|
22
|
+
* />
|
|
23
|
+
*/
|
|
24
|
+
function SkeletonListInner(props) {
|
|
25
|
+
const {
|
|
26
|
+
loading,
|
|
27
|
+
data,
|
|
28
|
+
renderItem,
|
|
29
|
+
renderPlaceholder,
|
|
30
|
+
placeholderCount = 3,
|
|
31
|
+
variant,
|
|
32
|
+
speed,
|
|
33
|
+
placeholderContainerStyle,
|
|
34
|
+
horizontal,
|
|
35
|
+
contentContainerStyle,
|
|
36
|
+
style,
|
|
37
|
+
testID,
|
|
38
|
+
...rest
|
|
39
|
+
} = props;
|
|
40
|
+
if (loading) {
|
|
41
|
+
const slots = Array.from({
|
|
42
|
+
length: Math.max(0, placeholderCount)
|
|
43
|
+
}, (_, index) => /*#__PURE__*/_jsx(React.Fragment, {
|
|
44
|
+
children: renderPlaceholder ? renderPlaceholder(index) : null
|
|
45
|
+
}, `sk-list-${index}`));
|
|
46
|
+
return /*#__PURE__*/_jsx(SkeletonContent, {
|
|
47
|
+
loading: true,
|
|
48
|
+
variant: variant,
|
|
49
|
+
speed: speed,
|
|
50
|
+
style: style,
|
|
51
|
+
testID: testID,
|
|
52
|
+
children: /*#__PURE__*/_jsx(View, {
|
|
53
|
+
style: [horizontal ? styles.row : styles.column, placeholderContainerStyle],
|
|
54
|
+
children: slots
|
|
55
|
+
})
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return /*#__PURE__*/_jsx(FlatList, {
|
|
59
|
+
data: data ?? [],
|
|
60
|
+
renderItem: renderItem,
|
|
61
|
+
horizontal: horizontal,
|
|
62
|
+
contentContainerStyle: contentContainerStyle,
|
|
63
|
+
style: style,
|
|
64
|
+
testID: testID,
|
|
65
|
+
...rest
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
const styles = {
|
|
69
|
+
row: {
|
|
70
|
+
flexDirection: 'row'
|
|
71
|
+
},
|
|
72
|
+
column: {
|
|
73
|
+
flexDirection: 'column'
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
export const SkeletonList = SkeletonListInner;
|
|
77
|
+
//# sourceMappingURL=SkeletonList.js.map
|
|
@@ -2,4 +2,5 @@
|
|
|
2
2
|
|
|
3
3
|
export { Skeleton, SkeletonCircle, SkeletonText, SkeletonAvatar, SkeletonCard, SkeletonListItem, default } from "./Skeleton.js";
|
|
4
4
|
export { SkeletonContent } from "./SkeletonContent.js";
|
|
5
|
+
export { SkeletonList } from "./SkeletonList.js";
|
|
5
6
|
//# 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, SkeletonListItem, SkeletonText } from "./Skeleton/index.js";
|
|
39
|
+
export { Skeleton, SkeletonAvatar, SkeletonCard, SkeletonCircle, SkeletonContent, SkeletonList, SkeletonListItem, SkeletonText } 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";
|
|
@@ -14,6 +14,12 @@ export interface AvatarProps {
|
|
|
14
14
|
statusPosition?: AvatarStatusPosition;
|
|
15
15
|
backgroundColor?: string;
|
|
16
16
|
color?: string;
|
|
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>;
|
|
@@ -12,6 +12,12 @@ export interface BadgeProps {
|
|
|
12
12
|
tone?: BadgeTone;
|
|
13
13
|
size?: BadgeSize;
|
|
14
14
|
invisible?: boolean;
|
|
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
|
children?: React.ReactNode;
|
|
16
22
|
anchor?: BadgeAnchor;
|
|
17
23
|
pulse?: boolean;
|
|
@@ -18,6 +18,12 @@ export interface CardProps extends Omit<PressableProps, 'style' | 'children'> {
|
|
|
18
18
|
imageHeight?: number;
|
|
19
19
|
imageAspectRatio?: number;
|
|
20
20
|
imageOverlay?: React.ReactNode;
|
|
21
|
+
/**
|
|
22
|
+
* When true, renders the component as a skeleton placeholder via SkeletonContent's auto walker.
|
|
23
|
+
* Component still renders its normal layout — the walker replaces Text/Image/sized View leaves
|
|
24
|
+
* with shimmer blocks. Use this when the data driving the component is still being fetched.
|
|
25
|
+
*/
|
|
26
|
+
loading?: boolean;
|
|
21
27
|
onPress?: (event: GestureResponderEvent) => void;
|
|
22
28
|
accessibilityLabel?: string;
|
|
23
29
|
style?: StyleProp<ViewStyle>;
|
|
@@ -5,6 +5,12 @@ import type { SwipeableAction } from '../Swipeable';
|
|
|
5
5
|
export type ListItemSize = 'sm' | 'md' | 'lg';
|
|
6
6
|
export interface ListItemProps {
|
|
7
7
|
title: string;
|
|
8
|
+
/**
|
|
9
|
+
* When true, renders the component as a skeleton placeholder via SkeletonContent's auto walker.
|
|
10
|
+
* Component still renders its normal layout — the walker replaces Text/Image/sized View leaves
|
|
11
|
+
* with shimmer blocks. Use this when the data driving the component is still being fetched.
|
|
12
|
+
*/
|
|
13
|
+
loading?: boolean;
|
|
8
14
|
subtitle?: string;
|
|
9
15
|
description?: string;
|
|
10
16
|
left?: React.ReactNode;
|
|
@@ -20,6 +20,12 @@ export interface SkeletonContentProps {
|
|
|
20
20
|
* cannot inspect.
|
|
21
21
|
*/
|
|
22
22
|
mode?: SkeletonContentMode;
|
|
23
|
+
/**
|
|
24
|
+
* Repeat `children` this many times while loading. Useful for list layouts where the
|
|
25
|
+
* placeholder shape should appear N times (e.g. 3 site cards, 5 list rows). Ignored when
|
|
26
|
+
* `loading` is false. Default: `1`.
|
|
27
|
+
*/
|
|
28
|
+
count?: number;
|
|
23
29
|
style?: StyleProp<ViewStyle>;
|
|
24
30
|
testID?: string;
|
|
25
31
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import type { FlatListProps, StyleProp, ViewStyle } from 'react-native';
|
|
3
|
+
import type { SkeletonSpeed, SkeletonVariant } from './Skeleton';
|
|
4
|
+
export interface SkeletonListProps<ItemT> extends Omit<FlatListProps<ItemT>, 'data' | 'renderItem'> {
|
|
5
|
+
/** Whether the list is in its initial loading state. */
|
|
6
|
+
loading: boolean;
|
|
7
|
+
/** The data to render once loading is complete. */
|
|
8
|
+
data: readonly ItemT[] | null | undefined;
|
|
9
|
+
/** Renders a single real item once data is available. */
|
|
10
|
+
renderItem: FlatListProps<ItemT>['renderItem'];
|
|
11
|
+
/**
|
|
12
|
+
* Renders one placeholder row. Index is provided so callers may vary
|
|
13
|
+
* placeholder shape per slot if desired. Defaults to `null`.
|
|
14
|
+
*/
|
|
15
|
+
renderPlaceholder?: (index: number) => ReactNode;
|
|
16
|
+
/** How many placeholder rows to render while loading. Default: 3. */
|
|
17
|
+
placeholderCount?: number;
|
|
18
|
+
/** Animation style — same as Skeleton. */
|
|
19
|
+
variant?: SkeletonVariant;
|
|
20
|
+
/** Animation speed — same as Skeleton. */
|
|
21
|
+
speed?: SkeletonSpeed;
|
|
22
|
+
/** Style applied to the wrapper View around the placeholders. */
|
|
23
|
+
placeholderContainerStyle?: StyleProp<ViewStyle>;
|
|
24
|
+
testID?: string;
|
|
25
|
+
}
|
|
26
|
+
export declare const SkeletonList: <ItemT>(props: SkeletonListProps<ItemT>) => ReactElement;
|
|
27
|
+
//# sourceMappingURL=SkeletonList.d.ts.map
|
|
@@ -2,4 +2,6 @@ export { Skeleton, SkeletonCircle, SkeletonText, SkeletonAvatar, SkeletonCard, S
|
|
|
2
2
|
export type { SkeletonProps, SkeletonCircleProps, SkeletonTextProps, SkeletonAvatarProps, SkeletonCardProps, SkeletonListItemProps, SkeletonVariant, SkeletonSpeed, SkeletonRadius, SkeletonWidth, SkeletonAvatarSize } from './Skeleton';
|
|
3
3
|
export { SkeletonContent } from './SkeletonContent';
|
|
4
4
|
export type { SkeletonContentProps, SkeletonContentMode } from './SkeletonContent';
|
|
5
|
+
export { SkeletonList } from './SkeletonList';
|
|
6
|
+
export type { SkeletonListProps } from './SkeletonList';
|
|
5
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -70,8 +70,8 @@ export { Select } from './Select';
|
|
|
70
70
|
export type { SelectProps, SelectOption, SelectSize } from './Select';
|
|
71
71
|
export { Stepper } from './Stepper';
|
|
72
72
|
export type { StepperProps, StepperVariant, StepperStep, StepperTone } from './Stepper';
|
|
73
|
-
export { Skeleton, SkeletonAvatar, SkeletonCard, SkeletonCircle, SkeletonContent, SkeletonListItem, SkeletonText } from './Skeleton';
|
|
74
|
-
export type { SkeletonProps, SkeletonAvatarProps, SkeletonCardProps, SkeletonCircleProps, SkeletonContentMode, SkeletonContentProps, SkeletonListItemProps, SkeletonTextProps, SkeletonVariant, SkeletonSpeed } from './Skeleton';
|
|
73
|
+
export { Skeleton, SkeletonAvatar, SkeletonCard, SkeletonCircle, SkeletonContent, SkeletonList, SkeletonListItem, SkeletonText } from './Skeleton';
|
|
74
|
+
export type { SkeletonProps, SkeletonAvatarProps, SkeletonCardProps, SkeletonCircleProps, SkeletonContentMode, SkeletonContentProps, SkeletonListItemProps, SkeletonListProps, SkeletonTextProps, SkeletonVariant, SkeletonSpeed } from './Skeleton';
|
|
75
75
|
export { Slider } from './Slider';
|
|
76
76
|
export type { SliderProps, SliderTone, SliderSize } from './Slider';
|
|
77
77
|
export { Swipeable } from './Swipeable';
|
|
@@ -14,6 +14,12 @@ export interface AvatarProps {
|
|
|
14
14
|
statusPosition?: AvatarStatusPosition;
|
|
15
15
|
backgroundColor?: string;
|
|
16
16
|
color?: string;
|
|
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>;
|
|
@@ -12,6 +12,12 @@ export interface BadgeProps {
|
|
|
12
12
|
tone?: BadgeTone;
|
|
13
13
|
size?: BadgeSize;
|
|
14
14
|
invisible?: boolean;
|
|
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
|
children?: React.ReactNode;
|
|
16
22
|
anchor?: BadgeAnchor;
|
|
17
23
|
pulse?: boolean;
|
|
@@ -18,6 +18,12 @@ export interface CardProps extends Omit<PressableProps, 'style' | 'children'> {
|
|
|
18
18
|
imageHeight?: number;
|
|
19
19
|
imageAspectRatio?: number;
|
|
20
20
|
imageOverlay?: React.ReactNode;
|
|
21
|
+
/**
|
|
22
|
+
* When true, renders the component as a skeleton placeholder via SkeletonContent's auto walker.
|
|
23
|
+
* Component still renders its normal layout — the walker replaces Text/Image/sized View leaves
|
|
24
|
+
* with shimmer blocks. Use this when the data driving the component is still being fetched.
|
|
25
|
+
*/
|
|
26
|
+
loading?: boolean;
|
|
21
27
|
onPress?: (event: GestureResponderEvent) => void;
|
|
22
28
|
accessibilityLabel?: string;
|
|
23
29
|
style?: StyleProp<ViewStyle>;
|
|
@@ -5,6 +5,12 @@ import type { SwipeableAction } from '../Swipeable';
|
|
|
5
5
|
export type ListItemSize = 'sm' | 'md' | 'lg';
|
|
6
6
|
export interface ListItemProps {
|
|
7
7
|
title: string;
|
|
8
|
+
/**
|
|
9
|
+
* When true, renders the component as a skeleton placeholder via SkeletonContent's auto walker.
|
|
10
|
+
* Component still renders its normal layout — the walker replaces Text/Image/sized View leaves
|
|
11
|
+
* with shimmer blocks. Use this when the data driving the component is still being fetched.
|
|
12
|
+
*/
|
|
13
|
+
loading?: boolean;
|
|
8
14
|
subtitle?: string;
|
|
9
15
|
description?: string;
|
|
10
16
|
left?: React.ReactNode;
|
|
@@ -20,6 +20,12 @@ export interface SkeletonContentProps {
|
|
|
20
20
|
* cannot inspect.
|
|
21
21
|
*/
|
|
22
22
|
mode?: SkeletonContentMode;
|
|
23
|
+
/**
|
|
24
|
+
* Repeat `children` this many times while loading. Useful for list layouts where the
|
|
25
|
+
* placeholder shape should appear N times (e.g. 3 site cards, 5 list rows). Ignored when
|
|
26
|
+
* `loading` is false. Default: `1`.
|
|
27
|
+
*/
|
|
28
|
+
count?: number;
|
|
23
29
|
style?: StyleProp<ViewStyle>;
|
|
24
30
|
testID?: string;
|
|
25
31
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import type { FlatListProps, StyleProp, ViewStyle } from 'react-native';
|
|
3
|
+
import type { SkeletonSpeed, SkeletonVariant } from './Skeleton';
|
|
4
|
+
export interface SkeletonListProps<ItemT> extends Omit<FlatListProps<ItemT>, 'data' | 'renderItem'> {
|
|
5
|
+
/** Whether the list is in its initial loading state. */
|
|
6
|
+
loading: boolean;
|
|
7
|
+
/** The data to render once loading is complete. */
|
|
8
|
+
data: readonly ItemT[] | null | undefined;
|
|
9
|
+
/** Renders a single real item once data is available. */
|
|
10
|
+
renderItem: FlatListProps<ItemT>['renderItem'];
|
|
11
|
+
/**
|
|
12
|
+
* Renders one placeholder row. Index is provided so callers may vary
|
|
13
|
+
* placeholder shape per slot if desired. Defaults to `null`.
|
|
14
|
+
*/
|
|
15
|
+
renderPlaceholder?: (index: number) => ReactNode;
|
|
16
|
+
/** How many placeholder rows to render while loading. Default: 3. */
|
|
17
|
+
placeholderCount?: number;
|
|
18
|
+
/** Animation style — same as Skeleton. */
|
|
19
|
+
variant?: SkeletonVariant;
|
|
20
|
+
/** Animation speed — same as Skeleton. */
|
|
21
|
+
speed?: SkeletonSpeed;
|
|
22
|
+
/** Style applied to the wrapper View around the placeholders. */
|
|
23
|
+
placeholderContainerStyle?: StyleProp<ViewStyle>;
|
|
24
|
+
testID?: string;
|
|
25
|
+
}
|
|
26
|
+
export declare const SkeletonList: <ItemT>(props: SkeletonListProps<ItemT>) => ReactElement;
|
|
27
|
+
//# sourceMappingURL=SkeletonList.d.ts.map
|
|
@@ -2,4 +2,6 @@ export { Skeleton, SkeletonCircle, SkeletonText, SkeletonAvatar, SkeletonCard, S
|
|
|
2
2
|
export type { SkeletonProps, SkeletonCircleProps, SkeletonTextProps, SkeletonAvatarProps, SkeletonCardProps, SkeletonListItemProps, SkeletonVariant, SkeletonSpeed, SkeletonRadius, SkeletonWidth, SkeletonAvatarSize } from './Skeleton';
|
|
3
3
|
export { SkeletonContent } from './SkeletonContent';
|
|
4
4
|
export type { SkeletonContentProps, SkeletonContentMode } from './SkeletonContent';
|
|
5
|
+
export { SkeletonList } from './SkeletonList';
|
|
6
|
+
export type { SkeletonListProps } from './SkeletonList';
|
|
5
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -70,8 +70,8 @@ export { Select } from './Select';
|
|
|
70
70
|
export type { SelectProps, SelectOption, SelectSize } from './Select';
|
|
71
71
|
export { Stepper } from './Stepper';
|
|
72
72
|
export type { StepperProps, StepperVariant, StepperStep, StepperTone } from './Stepper';
|
|
73
|
-
export { Skeleton, SkeletonAvatar, SkeletonCard, SkeletonCircle, SkeletonContent, SkeletonListItem, SkeletonText } from './Skeleton';
|
|
74
|
-
export type { SkeletonProps, SkeletonAvatarProps, SkeletonCardProps, SkeletonCircleProps, SkeletonContentMode, SkeletonContentProps, SkeletonListItemProps, SkeletonTextProps, SkeletonVariant, SkeletonSpeed } from './Skeleton';
|
|
73
|
+
export { Skeleton, SkeletonAvatar, SkeletonCard, SkeletonCircle, SkeletonContent, SkeletonList, SkeletonListItem, SkeletonText } from './Skeleton';
|
|
74
|
+
export type { SkeletonProps, SkeletonAvatarProps, SkeletonCardProps, SkeletonCircleProps, SkeletonContentMode, SkeletonContentProps, SkeletonListItemProps, SkeletonListProps, SkeletonTextProps, SkeletonVariant, SkeletonSpeed } from './Skeleton';
|
|
75
75
|
export { Slider } from './Slider';
|
|
76
76
|
export type { SliderProps, SliderTone, SliderSize } from './Slider';
|
|
77
77
|
export { Swipeable } from './Swipeable';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webority-technologies/mobile",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
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",
|