overlapping-cards-scroll 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -0
- package/dist/react-native-web.cjs +20 -2
- package/dist/react-native-web.js +20 -2
- package/dist/react-native.cjs +257 -30
- package/dist/react-native.js +258 -30
- package/dist/types/rn/OverlappingCardsScrollRN.native.d.ts +4 -26
- package/dist/types/rn/OverlappingCardsScrollRN.types.d.ts +74 -0
- package/dist/types/rn/OverlappingCardsScrollRN.web.d.ts +4 -18
- package/package.json +8 -3
- package/src/lib/OverlappingCardsScroll.css +206 -0
- package/src/lib/OverlappingCardsScroll.tsx +943 -0
- package/src/lib/index.ts +10 -0
- package/src/rn/OverlappingCardsScrollRN.native.tsx +868 -0
- package/src/rn/OverlappingCardsScrollRN.types.ts +102 -0
- package/src/rn/OverlappingCardsScrollRN.web.tsx +90 -0
- package/src/rn/RNWebDemo.tsx +241 -0
package/dist/react-native.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/rn/OverlappingCardsScrollRN.native.tsx
|
|
2
2
|
import {
|
|
3
3
|
Children,
|
|
4
|
+
Fragment,
|
|
4
5
|
createContext,
|
|
5
6
|
useCallback,
|
|
6
7
|
useContext,
|
|
@@ -13,7 +14,43 @@ import { Animated, Easing, Platform, Pressable, StyleSheet, Text, View } from "r
|
|
|
13
14
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
15
|
var clamp = (value, min, max) => Math.min(Math.max(value, min), max);
|
|
15
16
|
var PAGE_DOT_POSITIONS = /* @__PURE__ */ new Set(["above", "below", "overlay"]);
|
|
17
|
+
var TAB_POSITIONS = /* @__PURE__ */ new Set(["above", "below"]);
|
|
16
18
|
var normalizePageDotsPosition = (value) => PAGE_DOT_POSITIONS.has(value) ? value : "below";
|
|
19
|
+
var normalizeTabsPosition = (value) => TAB_POSITIONS.has(value) ? value : "above";
|
|
20
|
+
var toNumericOffset = (value, fallback = 0) => {
|
|
21
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
if (typeof value === "string") {
|
|
25
|
+
const parsed = Number.parseFloat(value.trim());
|
|
26
|
+
if (Number.isFinite(parsed)) {
|
|
27
|
+
return parsed;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return fallback;
|
|
31
|
+
};
|
|
32
|
+
var toNativeDimension = (value, fallback = 0) => {
|
|
33
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
if (typeof value === "string") {
|
|
37
|
+
const trimmed = value.trim();
|
|
38
|
+
if (trimmed === "auto") {
|
|
39
|
+
return "auto";
|
|
40
|
+
}
|
|
41
|
+
if (trimmed.endsWith("%")) {
|
|
42
|
+
const percent = Number.parseFloat(trimmed.slice(0, -1));
|
|
43
|
+
if (Number.isFinite(percent)) {
|
|
44
|
+
return `${percent}%`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const numeric = Number.parseFloat(trimmed);
|
|
48
|
+
if (Number.isFinite(numeric)) {
|
|
49
|
+
return numeric;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return fallback;
|
|
53
|
+
};
|
|
17
54
|
var resolveCardXAtProgress = (index, progress, layout) => {
|
|
18
55
|
const principalIndex = Math.floor(progress);
|
|
19
56
|
const transitionProgress = progress - principalIndex;
|
|
@@ -51,26 +88,69 @@ function OverlappingCardsScrollRNFocusTrigger({
|
|
|
51
88
|
children = "Make principal",
|
|
52
89
|
style = void 0,
|
|
53
90
|
textStyle = void 0,
|
|
91
|
+
behavior = "smooth",
|
|
54
92
|
transitionMode = "swoop",
|
|
93
|
+
disabled = false,
|
|
94
|
+
accessibilityLabel = void 0,
|
|
95
|
+
testID = void 0,
|
|
55
96
|
onPress = void 0,
|
|
97
|
+
onClick = void 0,
|
|
56
98
|
...pressableProps
|
|
57
99
|
}) {
|
|
58
100
|
const { canFocus, focusCard } = useOverlappingCardsScrollRNCardControl();
|
|
59
101
|
const handlePress = (event) => {
|
|
102
|
+
onClick == null ? void 0 : onClick(event);
|
|
60
103
|
onPress == null ? void 0 : onPress(event);
|
|
61
|
-
focusCard({
|
|
104
|
+
focusCard({
|
|
105
|
+
animated: behavior !== "auto",
|
|
106
|
+
transitionMode
|
|
107
|
+
});
|
|
62
108
|
};
|
|
63
109
|
return /* @__PURE__ */ jsx(
|
|
64
110
|
Pressable,
|
|
65
111
|
{
|
|
66
112
|
style: ({ pressed }) => [styles.focusTrigger, pressed && styles.focusTriggerPressed, style],
|
|
67
|
-
disabled: !canFocus,
|
|
113
|
+
disabled: disabled || !canFocus,
|
|
114
|
+
accessibilityLabel,
|
|
115
|
+
testID,
|
|
68
116
|
onPress: handlePress,
|
|
69
117
|
...pressableProps,
|
|
70
118
|
children: /* @__PURE__ */ jsx(Text, { style: [styles.focusTriggerText, textStyle], children })
|
|
71
119
|
}
|
|
72
120
|
);
|
|
73
121
|
}
|
|
122
|
+
function DefaultTabsContainerComponent({
|
|
123
|
+
children,
|
|
124
|
+
style,
|
|
125
|
+
ariaLabel
|
|
126
|
+
}) {
|
|
127
|
+
return /* @__PURE__ */ jsx(View, { accessibilityRole: "tablist", accessibilityLabel: ariaLabel, style, children });
|
|
128
|
+
}
|
|
129
|
+
function DefaultTabsComponent({
|
|
130
|
+
name,
|
|
131
|
+
style,
|
|
132
|
+
textStyle,
|
|
133
|
+
accessibilityLabel,
|
|
134
|
+
accessibilityState,
|
|
135
|
+
onPress,
|
|
136
|
+
onClick
|
|
137
|
+
}) {
|
|
138
|
+
const handlePress = () => {
|
|
139
|
+
onClick();
|
|
140
|
+
onPress();
|
|
141
|
+
};
|
|
142
|
+
return /* @__PURE__ */ jsx(
|
|
143
|
+
Pressable,
|
|
144
|
+
{
|
|
145
|
+
accessibilityRole: "tab",
|
|
146
|
+
accessibilityLabel,
|
|
147
|
+
accessibilityState,
|
|
148
|
+
onPress: handlePress,
|
|
149
|
+
style: ({ pressed }) => [styles.tab, pressed && styles.tabPressed, style],
|
|
150
|
+
children: /* @__PURE__ */ jsx(Text, { style: [styles.tabText, textStyle], children: name })
|
|
151
|
+
}
|
|
152
|
+
);
|
|
153
|
+
}
|
|
74
154
|
var resolveCardWidth = (cardWidth, viewportWidth, fallbackRatio) => {
|
|
75
155
|
if (typeof cardWidth === "number" && Number.isFinite(cardWidth) && cardWidth > 0) {
|
|
76
156
|
return cardWidth;
|
|
@@ -90,26 +170,66 @@ var resolveCardWidth = (cardWidth, viewportWidth, fallbackRatio) => {
|
|
|
90
170
|
}
|
|
91
171
|
return viewportWidth * fallbackRatio;
|
|
92
172
|
};
|
|
93
|
-
function OverlappingCardsScrollRN({
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
173
|
+
function OverlappingCardsScrollRN(props) {
|
|
174
|
+
const {
|
|
175
|
+
style = void 0,
|
|
176
|
+
cardHeight = 300,
|
|
177
|
+
cardWidth = void 0,
|
|
178
|
+
cardWidthRatio = 1 / 3,
|
|
179
|
+
basePeek = 64,
|
|
180
|
+
minPeek = 10,
|
|
181
|
+
maxPeek = 84,
|
|
182
|
+
showsHorizontalScrollIndicator = true,
|
|
183
|
+
snapToCardOnRelease = true,
|
|
184
|
+
snapDecelerationRate = "normal",
|
|
185
|
+
snapDisableIntervalMomentum = false,
|
|
186
|
+
showPageDots = false,
|
|
187
|
+
pageDotsPosition = "below",
|
|
188
|
+
pageDotsOffset = 10,
|
|
189
|
+
focusTransitionDuration = 420,
|
|
190
|
+
cardContainerStyle = void 0,
|
|
191
|
+
showTabs = false,
|
|
192
|
+
tabsPosition = "above",
|
|
193
|
+
tabsOffset = 10,
|
|
194
|
+
tabsComponent: TabsComponent = DefaultTabsComponent,
|
|
195
|
+
tabsContainerComponent: TabsContainerComponent = DefaultTabsContainerComponent
|
|
196
|
+
} = props;
|
|
197
|
+
const hasItems = "items" in props && Array.isArray(props.items);
|
|
198
|
+
const hasChildren = "children" in props && props.children != null;
|
|
199
|
+
useEffect(() => {
|
|
200
|
+
if (hasItems && hasChildren) {
|
|
201
|
+
console.warn(
|
|
202
|
+
"OverlappingCardsScrollRN: Both `items` and `children` were provided. `items` takes precedence."
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
}, [hasItems, hasChildren]);
|
|
206
|
+
const itemsProp = hasItems ? props.items : null;
|
|
207
|
+
const childrenProp = hasChildren ? props.children : null;
|
|
208
|
+
const cards = useMemo(() => {
|
|
209
|
+
if (itemsProp) {
|
|
210
|
+
return itemsProp.map((item) => /* @__PURE__ */ jsx(Fragment, { children: item.jsx }, item.id));
|
|
211
|
+
}
|
|
212
|
+
return Children.toArray(childrenProp);
|
|
213
|
+
}, [childrenProp, itemsProp]);
|
|
214
|
+
const cardNames = useMemo(() => {
|
|
215
|
+
if (itemsProp) {
|
|
216
|
+
return itemsProp.map((item) => item.name);
|
|
217
|
+
}
|
|
218
|
+
return null;
|
|
219
|
+
}, [itemsProp]);
|
|
112
220
|
const cardCount = cards.length;
|
|
221
|
+
const resolvedTabsPosition = normalizeTabsPosition(tabsPosition);
|
|
222
|
+
const showNavigationTabs = showTabs && cardCount > 1 && cardNames !== null;
|
|
223
|
+
const resolvedPageDotsOffset = toNumericOffset(pageDotsOffset, 10);
|
|
224
|
+
const resolvedTabsOffset = toNumericOffset(tabsOffset, 10);
|
|
225
|
+
const resolvedCardHeight = toNativeDimension(cardHeight, 300);
|
|
226
|
+
useEffect(() => {
|
|
227
|
+
if (showTabs && cardNames === null) {
|
|
228
|
+
console.warn(
|
|
229
|
+
"OverlappingCardsScrollRN: `showTabs` requires the `items` prop to provide card names. Tabs will not render."
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
}, [cardNames, showTabs]);
|
|
113
233
|
const scrollRef = useRef(null);
|
|
114
234
|
const scrollX = useRef(new Animated.Value(0)).current;
|
|
115
235
|
const scrollXValueRef = useRef(0);
|
|
@@ -118,6 +238,7 @@ function OverlappingCardsScrollRN({
|
|
|
118
238
|
const focusTransitionIdRef = useRef(0);
|
|
119
239
|
const [viewportWidth, setViewportWidth] = useState(1);
|
|
120
240
|
const [focusTransition, setFocusTransition] = useState(null);
|
|
241
|
+
const [scrollProgress, setScrollProgress] = useState(0);
|
|
121
242
|
const layout = useMemo(() => {
|
|
122
243
|
const safeWidth = Math.max(1, viewportWidth);
|
|
123
244
|
const safeRatio = clamp(cardWidthRatio, 0.2, 0.95);
|
|
@@ -160,11 +281,26 @@ function OverlappingCardsScrollRN({
|
|
|
160
281
|
useEffect(() => {
|
|
161
282
|
const id = scrollX.addListener(({ value }) => {
|
|
162
283
|
scrollXValueRef.current = value;
|
|
284
|
+
if (!showNavigationTabs) {
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
const nextProgress = cardCount > 1 ? clamp(value / layout.stepDistance, 0, cardCount - 1) : 0;
|
|
288
|
+
setScrollProgress(
|
|
289
|
+
(currentProgress) => Math.abs(currentProgress - nextProgress) < 1e-3 ? currentProgress : nextProgress
|
|
290
|
+
);
|
|
163
291
|
});
|
|
164
292
|
return () => {
|
|
165
293
|
scrollX.removeListener(id);
|
|
166
294
|
};
|
|
167
|
-
}, [scrollX]);
|
|
295
|
+
}, [cardCount, layout.stepDistance, scrollX, showNavigationTabs]);
|
|
296
|
+
useEffect(() => {
|
|
297
|
+
if (!showNavigationTabs) {
|
|
298
|
+
setScrollProgress(0);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
const nextProgress = cardCount > 1 ? clamp(scrollXValueRef.current / layout.stepDistance, 0, cardCount - 1) : 0;
|
|
302
|
+
setScrollProgress(nextProgress);
|
|
303
|
+
}, [cardCount, layout.stepDistance, showNavigationTabs]);
|
|
168
304
|
useEffect(() => () => stopFocusTransitionAnimation(), [stopFocusTransitionAnimation]);
|
|
169
305
|
useEffect(() => {
|
|
170
306
|
if (cardCount > 1) {
|
|
@@ -199,6 +335,9 @@ function OverlappingCardsScrollRN({
|
|
|
199
335
|
const nextScrollLeft = clamp(safeIndex * layout.stepDistance, 0, layout.scrollRange);
|
|
200
336
|
const transitionMode = (_a = options.transitionMode) != null ? _a : "swoop";
|
|
201
337
|
if (transitionMode === "swoop" && cardCount > 1) {
|
|
338
|
+
if (showNavigationTabs) {
|
|
339
|
+
setScrollProgress(safeIndex);
|
|
340
|
+
}
|
|
202
341
|
const fromProgress = clamp(
|
|
203
342
|
scrollXValueRef.current / layout.stepDistance,
|
|
204
343
|
0,
|
|
@@ -255,6 +394,9 @@ function OverlappingCardsScrollRN({
|
|
|
255
394
|
if (((_c = options.animated) != null ? _c : true) === false) {
|
|
256
395
|
scrollX.setValue(nextScrollLeft);
|
|
257
396
|
scrollXValueRef.current = nextScrollLeft;
|
|
397
|
+
if (showNavigationTabs) {
|
|
398
|
+
setScrollProgress(safeIndex);
|
|
399
|
+
}
|
|
258
400
|
}
|
|
259
401
|
},
|
|
260
402
|
[
|
|
@@ -265,6 +407,7 @@ function OverlappingCardsScrollRN({
|
|
|
265
407
|
layout.scrollRange,
|
|
266
408
|
layout.stepDistance,
|
|
267
409
|
scrollX,
|
|
410
|
+
showNavigationTabs,
|
|
268
411
|
stopFocusTransitionAnimation
|
|
269
412
|
]
|
|
270
413
|
);
|
|
@@ -289,11 +432,13 @@ function OverlappingCardsScrollRN({
|
|
|
289
432
|
extrapolate: "clamp"
|
|
290
433
|
});
|
|
291
434
|
}, [focusTransition, focusTransitionProgress, layout.stepDistance, scrollX]);
|
|
435
|
+
const progress = showNavigationTabs ? scrollProgress : 0;
|
|
436
|
+
const activeIndex = Math.floor(progress);
|
|
292
437
|
const renderPageDots = (placement) => {
|
|
293
438
|
if (!showNavigationDots || resolvedPageDotsPosition !== placement) {
|
|
294
439
|
return null;
|
|
295
440
|
}
|
|
296
|
-
const rowStyle = placement === "above" ? [styles.pageDotsRow, { marginBottom:
|
|
441
|
+
const rowStyle = placement === "above" ? [styles.pageDotsRow, { marginBottom: resolvedPageDotsOffset }] : placement === "below" ? [styles.pageDotsRow, { marginTop: resolvedPageDotsOffset }] : [styles.pageDotsRow, styles.pageDotsOverlay, { bottom: resolvedPageDotsOffset }];
|
|
297
442
|
return /* @__PURE__ */ jsx(
|
|
298
443
|
View,
|
|
299
444
|
{
|
|
@@ -329,12 +474,63 @@ function OverlappingCardsScrollRN({
|
|
|
329
474
|
}
|
|
330
475
|
);
|
|
331
476
|
};
|
|
477
|
+
const renderTabs = (position) => {
|
|
478
|
+
if (!showNavigationTabs || resolvedTabsPosition !== position || cardNames === null) {
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
const containerStyle = position === "above" ? [styles.tabsRow, { marginBottom: resolvedTabsOffset }] : [styles.tabsRow, { marginTop: resolvedTabsOffset }];
|
|
482
|
+
return /* @__PURE__ */ jsx(
|
|
483
|
+
TabsContainerComponent,
|
|
484
|
+
{
|
|
485
|
+
position,
|
|
486
|
+
className: `rn-ocs-tabs rn-ocs-tabs--${position}`,
|
|
487
|
+
style: containerStyle,
|
|
488
|
+
ariaLabel: "Card tabs",
|
|
489
|
+
cardNames,
|
|
490
|
+
activeIndex,
|
|
491
|
+
progress,
|
|
492
|
+
children: cardNames.map((name, index) => {
|
|
493
|
+
const influence = clamp(1 - Math.abs(progress - index), 0, 1);
|
|
494
|
+
const isPrincipal = influence > 0.98;
|
|
495
|
+
const animate = {
|
|
496
|
+
opacity: 0.45 + influence * 0.55
|
|
497
|
+
};
|
|
498
|
+
const pressTab = () => focusCard(index, {
|
|
499
|
+
animated: true,
|
|
500
|
+
transitionMode: "swoop"
|
|
501
|
+
});
|
|
502
|
+
return /* @__PURE__ */ jsx(
|
|
503
|
+
TabsComponent,
|
|
504
|
+
{
|
|
505
|
+
name,
|
|
506
|
+
index,
|
|
507
|
+
position,
|
|
508
|
+
isPrincipal,
|
|
509
|
+
influence,
|
|
510
|
+
animate,
|
|
511
|
+
className: isPrincipal ? "rn-ocs-tab rn-ocs-tab--active" : "rn-ocs-tab",
|
|
512
|
+
style: { opacity: animate.opacity },
|
|
513
|
+
textStyle: isPrincipal ? styles.tabTextActive : void 0,
|
|
514
|
+
ariaLabel: `Go to ${name}`,
|
|
515
|
+
ariaCurrent: isPrincipal ? "page" : void 0,
|
|
516
|
+
accessibilityLabel: `Go to ${name}`,
|
|
517
|
+
accessibilityState: { selected: isPrincipal },
|
|
518
|
+
onPress: pressTab,
|
|
519
|
+
onClick: pressTab
|
|
520
|
+
},
|
|
521
|
+
`rn-ocs-tab-${position}-${index}`
|
|
522
|
+
);
|
|
523
|
+
})
|
|
524
|
+
}
|
|
525
|
+
);
|
|
526
|
+
};
|
|
332
527
|
return /* @__PURE__ */ jsx(OverlappingCardsScrollRNControllerContext.Provider, { value: controllerContextValue, children: /* @__PURE__ */ jsxs(View, { style: [styles.shell, style], children: [
|
|
528
|
+
renderTabs("above"),
|
|
333
529
|
renderPageDots("above"),
|
|
334
530
|
/* @__PURE__ */ jsxs(
|
|
335
531
|
View,
|
|
336
532
|
{
|
|
337
|
-
style: [styles.root, { height:
|
|
533
|
+
style: [styles.root, { height: resolvedCardHeight }],
|
|
338
534
|
onLayout: (event) => {
|
|
339
535
|
const width = event.nativeEvent.layout.width || 1;
|
|
340
536
|
setViewportWidth(Math.max(1, width));
|
|
@@ -345,8 +541,8 @@ function OverlappingCardsScrollRN({
|
|
|
345
541
|
{
|
|
346
542
|
ref: scrollRef,
|
|
347
543
|
horizontal: true,
|
|
348
|
-
style: [styles.scrollRegion, { height:
|
|
349
|
-
contentContainerStyle: { width: layout.trackWidth, height:
|
|
544
|
+
style: [styles.scrollRegion, { height: resolvedCardHeight }],
|
|
545
|
+
contentContainerStyle: { width: layout.trackWidth, height: resolvedCardHeight },
|
|
350
546
|
onScroll,
|
|
351
547
|
onScrollBeginDrag: cancelFocusTransition,
|
|
352
548
|
onMomentumScrollBegin: cancelFocusTransition,
|
|
@@ -356,7 +552,7 @@ function OverlappingCardsScrollRN({
|
|
|
356
552
|
snapToAlignment: shouldSnapToCard ? "start" : void 0,
|
|
357
553
|
decelerationRate: shouldSnapToCard ? snapDecelerationRate : "normal",
|
|
358
554
|
disableIntervalMomentum: shouldSnapToCard ? snapDisableIntervalMomentum : false,
|
|
359
|
-
children: /* @__PURE__ */ jsx(View, { style: [styles.track, { width: layout.trackWidth, height:
|
|
555
|
+
children: /* @__PURE__ */ jsx(View, { style: [styles.track, { width: layout.trackWidth, height: resolvedCardHeight }], children: cards.map((card, index) => {
|
|
360
556
|
var _a;
|
|
361
557
|
const restingRightX = index === 0 ? 0 : (index - 1) * layout.peek + layout.cardWidth;
|
|
362
558
|
const restingLeftX = index * layout.peek;
|
|
@@ -381,13 +577,14 @@ function OverlappingCardsScrollRN({
|
|
|
381
577
|
styles.card,
|
|
382
578
|
{
|
|
383
579
|
width: layout.cardWidth,
|
|
384
|
-
height:
|
|
580
|
+
height: resolvedCardHeight,
|
|
385
581
|
transform: [
|
|
386
582
|
{
|
|
387
583
|
translateX: Animated.add(scrollX, animatedCardX)
|
|
388
584
|
}
|
|
389
585
|
]
|
|
390
|
-
}
|
|
586
|
+
},
|
|
587
|
+
cardContainerStyle
|
|
391
588
|
],
|
|
392
589
|
children: /* @__PURE__ */ jsx(OverlappingCardsScrollRNCardIndexContext.Provider, { value: index, children: card })
|
|
393
590
|
},
|
|
@@ -400,7 +597,8 @@ function OverlappingCardsScrollRN({
|
|
|
400
597
|
]
|
|
401
598
|
}
|
|
402
599
|
),
|
|
403
|
-
renderPageDots("below")
|
|
600
|
+
renderPageDots("below"),
|
|
601
|
+
renderTabs("below")
|
|
404
602
|
] }) });
|
|
405
603
|
}
|
|
406
604
|
var styles = StyleSheet.create({
|
|
@@ -451,6 +649,36 @@ var styles = StyleSheet.create({
|
|
|
451
649
|
borderRadius: 999,
|
|
452
650
|
backgroundColor: "#1f4666"
|
|
453
651
|
},
|
|
652
|
+
tabsRow: {
|
|
653
|
+
width: "100%",
|
|
654
|
+
flexDirection: "row",
|
|
655
|
+
alignItems: "center",
|
|
656
|
+
justifyContent: "center",
|
|
657
|
+
flexWrap: "wrap",
|
|
658
|
+
zIndex: 6
|
|
659
|
+
},
|
|
660
|
+
tab: {
|
|
661
|
+
borderRadius: 999,
|
|
662
|
+
borderWidth: 1,
|
|
663
|
+
borderColor: "rgba(30, 67, 99, 0.2)",
|
|
664
|
+
backgroundColor: "#eef5ff",
|
|
665
|
+
paddingHorizontal: 12,
|
|
666
|
+
paddingVertical: 6,
|
|
667
|
+
marginHorizontal: 4,
|
|
668
|
+
marginVertical: 4
|
|
669
|
+
},
|
|
670
|
+
tabPressed: {
|
|
671
|
+
opacity: 0.85
|
|
672
|
+
},
|
|
673
|
+
tabText: {
|
|
674
|
+
color: "#275070",
|
|
675
|
+
fontSize: 12,
|
|
676
|
+
fontWeight: "700",
|
|
677
|
+
letterSpacing: 0.2
|
|
678
|
+
},
|
|
679
|
+
tabTextActive: {
|
|
680
|
+
color: "#173047"
|
|
681
|
+
},
|
|
454
682
|
focusTrigger: {
|
|
455
683
|
alignSelf: "flex-start",
|
|
456
684
|
borderRadius: 99,
|
|
@@ -1,26 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
textStyle?: any;
|
|
6
|
-
transitionMode?: string;
|
|
7
|
-
onPress?: any;
|
|
8
|
-
}): import("react/jsx-runtime").JSX.Element;
|
|
9
|
-
export declare function OverlappingCardsScrollRN({ children, style, cardHeight, cardWidth, cardWidthRatio, basePeek, minPeek, maxPeek, showsHorizontalScrollIndicator, snapToCardOnRelease, snapDecelerationRate, snapDisableIntervalMomentum, showPageDots, pageDotsPosition, pageDotsOffset, focusTransitionDuration, }: {
|
|
10
|
-
children: any;
|
|
11
|
-
style?: any;
|
|
12
|
-
cardHeight?: number;
|
|
13
|
-
cardWidth?: any;
|
|
14
|
-
cardWidthRatio?: number;
|
|
15
|
-
basePeek?: number;
|
|
16
|
-
minPeek?: number;
|
|
17
|
-
maxPeek?: number;
|
|
18
|
-
showsHorizontalScrollIndicator?: boolean;
|
|
19
|
-
snapToCardOnRelease?: boolean;
|
|
20
|
-
snapDecelerationRate?: string;
|
|
21
|
-
snapDisableIntervalMomentum?: boolean;
|
|
22
|
-
showPageDots?: boolean;
|
|
23
|
-
pageDotsPosition?: string;
|
|
24
|
-
pageDotsOffset?: number;
|
|
25
|
-
focusTransitionDuration?: number;
|
|
26
|
-
}): import("react/jsx-runtime").JSX.Element;
|
|
1
|
+
import type { OverlappingCardsScrollRNFocusTriggerProps, OverlappingCardsScrollRNProps } from './OverlappingCardsScrollRN.types';
|
|
2
|
+
export type { OverlappingCardsScrollRNFocusTransitionMode, OverlappingCardsScrollRNFocusTriggerBehavior, OverlappingCardsScrollRNFocusTriggerProps, OverlappingCardsScrollRNItem, OverlappingCardsScrollRNPageDotsPosition, OverlappingCardsScrollRNProps, OverlappingCardsScrollRNSnapDecelerationRate, OverlappingCardsScrollRNTabsContainerProps, OverlappingCardsScrollRNTabProps, OverlappingCardsScrollRNTabsPosition, } from './OverlappingCardsScrollRN.types';
|
|
3
|
+
export declare function OverlappingCardsScrollRNFocusTrigger({ children, style, textStyle, behavior, transitionMode, disabled, accessibilityLabel, testID, onPress, onClick, ...pressableProps }: OverlappingCardsScrollRNFocusTriggerProps): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
export declare function OverlappingCardsScrollRN(props: OverlappingCardsScrollRNProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { ComponentProps, ComponentType, ReactNode } from 'react';
|
|
2
|
+
import type { StyleProp, TextStyle, ViewStyle } from 'react-native';
|
|
3
|
+
import type { CardItem as OverlappingCardsScrollWebCardItem, OverlappingCardsScroll, OverlappingCardsScrollFocusTriggerProps as OverlappingCardsScrollWebFocusTriggerProps } from '../lib/OverlappingCardsScroll';
|
|
4
|
+
type OverlappingCardsScrollWebProps = ComponentProps<typeof OverlappingCardsScroll>;
|
|
5
|
+
type OverlappingCardsScrollRNSharedProps = Omit<OverlappingCardsScrollWebProps, 'children' | 'items' | 'cardContainerStyle' | 'tabsComponent' | 'tabsContainerComponent'>;
|
|
6
|
+
export type OverlappingCardsScrollRNPageDotsPosition = NonNullable<OverlappingCardsScrollWebProps['pageDotsPosition']>;
|
|
7
|
+
export type OverlappingCardsScrollRNFocusTriggerBehavior = OverlappingCardsScrollWebFocusTriggerProps['behavior'];
|
|
8
|
+
export type OverlappingCardsScrollRNFocusTransitionMode = NonNullable<OverlappingCardsScrollWebFocusTriggerProps['transitionMode']>;
|
|
9
|
+
export type OverlappingCardsScrollRNSnapDecelerationRate = 'normal' | 'fast' | number;
|
|
10
|
+
export type OverlappingCardsScrollRNItem = OverlappingCardsScrollWebCardItem;
|
|
11
|
+
export type OverlappingCardsScrollRNTabsPosition = 'above' | 'below';
|
|
12
|
+
export interface OverlappingCardsScrollRNTabProps {
|
|
13
|
+
name: string;
|
|
14
|
+
index: number;
|
|
15
|
+
position: OverlappingCardsScrollRNTabsPosition;
|
|
16
|
+
isPrincipal: boolean;
|
|
17
|
+
influence: number;
|
|
18
|
+
animate: {
|
|
19
|
+
opacity: number;
|
|
20
|
+
};
|
|
21
|
+
className: string;
|
|
22
|
+
style: StyleProp<ViewStyle>;
|
|
23
|
+
textStyle: StyleProp<TextStyle>;
|
|
24
|
+
ariaLabel: string;
|
|
25
|
+
ariaCurrent?: 'page';
|
|
26
|
+
accessibilityLabel: string;
|
|
27
|
+
accessibilityState?: {
|
|
28
|
+
selected?: boolean;
|
|
29
|
+
};
|
|
30
|
+
onPress: () => void;
|
|
31
|
+
onClick: () => void;
|
|
32
|
+
}
|
|
33
|
+
export interface OverlappingCardsScrollRNTabsContainerProps {
|
|
34
|
+
children: ReactNode;
|
|
35
|
+
position: OverlappingCardsScrollRNTabsPosition;
|
|
36
|
+
className: string;
|
|
37
|
+
style: StyleProp<ViewStyle>;
|
|
38
|
+
ariaLabel: string;
|
|
39
|
+
cardNames: string[];
|
|
40
|
+
activeIndex: number;
|
|
41
|
+
progress: number;
|
|
42
|
+
}
|
|
43
|
+
type OverlappingCardsScrollRNWithChildren = OverlappingCardsScrollRNSharedProps & {
|
|
44
|
+
children: ReactNode;
|
|
45
|
+
items?: never;
|
|
46
|
+
};
|
|
47
|
+
type OverlappingCardsScrollRNWithItems = OverlappingCardsScrollRNSharedProps & {
|
|
48
|
+
items: OverlappingCardsScrollRNItem[];
|
|
49
|
+
children?: never;
|
|
50
|
+
};
|
|
51
|
+
type OverlappingCardsScrollRNContentProps = OverlappingCardsScrollRNWithChildren | OverlappingCardsScrollRNWithItems;
|
|
52
|
+
export type OverlappingCardsScrollRNProps = OverlappingCardsScrollRNContentProps & {
|
|
53
|
+
style?: StyleProp<ViewStyle>;
|
|
54
|
+
cardContainerStyle?: StyleProp<ViewStyle>;
|
|
55
|
+
tabsComponent?: ComponentType<OverlappingCardsScrollRNTabProps>;
|
|
56
|
+
tabsContainerComponent?: ComponentType<OverlappingCardsScrollRNTabsContainerProps>;
|
|
57
|
+
showsHorizontalScrollIndicator?: boolean;
|
|
58
|
+
snapDecelerationRate?: OverlappingCardsScrollRNSnapDecelerationRate;
|
|
59
|
+
snapDisableIntervalMomentum?: boolean;
|
|
60
|
+
};
|
|
61
|
+
export interface OverlappingCardsScrollRNFocusTriggerProps {
|
|
62
|
+
children?: ReactNode;
|
|
63
|
+
className?: string;
|
|
64
|
+
style?: StyleProp<ViewStyle>;
|
|
65
|
+
textStyle?: StyleProp<TextStyle>;
|
|
66
|
+
behavior?: OverlappingCardsScrollRNFocusTriggerBehavior;
|
|
67
|
+
transitionMode?: OverlappingCardsScrollRNFocusTransitionMode;
|
|
68
|
+
disabled?: boolean;
|
|
69
|
+
accessibilityLabel?: string;
|
|
70
|
+
testID?: string;
|
|
71
|
+
onPress?: (event: unknown) => void;
|
|
72
|
+
onClick?: (event: unknown) => void;
|
|
73
|
+
}
|
|
74
|
+
export {};
|
|
@@ -1,18 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
children?: ReactNode;
|
|
6
|
-
className?: string;
|
|
7
|
-
onPress?: (event: unknown) => void;
|
|
8
|
-
onClick?: (event: unknown) => void;
|
|
9
|
-
}
|
|
10
|
-
export declare function OverlappingCardsScrollRNFocusTrigger({ children, className, onPress, onClick, ...buttonProps }: OverlappingCardsScrollRNFocusTriggerProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
-
type OverlappingCardsScrollRNProps = Omit<ComponentProps<typeof OverlappingCardsScroll>, 'items'> & {
|
|
12
|
-
style?: StyleProp<ViewStyle>;
|
|
13
|
-
showsHorizontalScrollIndicator?: boolean;
|
|
14
|
-
snapDecelerationRate?: string;
|
|
15
|
-
snapDisableIntervalMomentum?: boolean;
|
|
16
|
-
};
|
|
17
|
-
export declare function OverlappingCardsScrollRN({ children, style, showsHorizontalScrollIndicator, snapDecelerationRate, snapDisableIntervalMomentum, ...overlappingCardsScrollProps }: OverlappingCardsScrollRNProps): import("react/jsx-runtime").JSX.Element;
|
|
18
|
-
export {};
|
|
1
|
+
import type { OverlappingCardsScrollRNFocusTriggerProps, OverlappingCardsScrollRNProps } from './OverlappingCardsScrollRN.types';
|
|
2
|
+
export type { OverlappingCardsScrollRNFocusTransitionMode, OverlappingCardsScrollRNFocusTriggerBehavior, OverlappingCardsScrollRNFocusTriggerProps, OverlappingCardsScrollRNItem, OverlappingCardsScrollRNPageDotsPosition, OverlappingCardsScrollRNProps, OverlappingCardsScrollRNSnapDecelerationRate, OverlappingCardsScrollRNTabsContainerProps, OverlappingCardsScrollRNTabProps, OverlappingCardsScrollRNTabsPosition, } from './OverlappingCardsScrollRN.types';
|
|
3
|
+
export declare function OverlappingCardsScrollRNFocusTrigger({ children, className, style, textStyle, behavior, transitionMode, disabled, accessibilityLabel, testID, onPress, onClick, ...buttonProps }: OverlappingCardsScrollRNFocusTriggerProps): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
export declare function OverlappingCardsScrollRN({ style, showsHorizontalScrollIndicator, snapDecelerationRate, snapDisableIntervalMomentum, ...overlappingCardsScrollProps }: OverlappingCardsScrollRNProps): import("react/jsx-runtime").JSX.Element;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "overlapping-cards-scroll",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Overlapping cards scroll component for React, React Native, and React Native Web.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -40,6 +40,8 @@
|
|
|
40
40
|
},
|
|
41
41
|
"files": [
|
|
42
42
|
"dist",
|
|
43
|
+
"src/lib",
|
|
44
|
+
"src/rn",
|
|
43
45
|
"README.md",
|
|
44
46
|
"LICENSE"
|
|
45
47
|
],
|
|
@@ -67,7 +69,7 @@
|
|
|
67
69
|
},
|
|
68
70
|
"scripts": {
|
|
69
71
|
"dev": "vite",
|
|
70
|
-
"dev:expo": "expo start",
|
|
72
|
+
"dev:expo": "node ./node_modules/expo/bin/cli start ./expo-demo",
|
|
71
73
|
"build": "npm run build:package",
|
|
72
74
|
"build:package": "node ./scripts/build-package.mjs && npm run build:types",
|
|
73
75
|
"build:types": "tsc -p tsconfig.package.json",
|
|
@@ -75,7 +77,10 @@
|
|
|
75
77
|
"typecheck": "tsc --noEmit",
|
|
76
78
|
"lint": "eslint .",
|
|
77
79
|
"preview": "vite preview --outDir web-build",
|
|
78
|
-
"prepack": "npm run build:package"
|
|
80
|
+
"prepack": "npm run build:package",
|
|
81
|
+
"patch": "npm version patch",
|
|
82
|
+
"publish": "npm publish --access public",
|
|
83
|
+
"npmlogin": "npm login"
|
|
79
84
|
},
|
|
80
85
|
"peerDependencies": {
|
|
81
86
|
"react": "^18.0.0 || ^19.0.0",
|