jfs-components 0.1.56 → 0.1.57
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/CHANGELOG.md +5 -0
- package/lib/commonjs/components/CardCTA/CardCTA.js +4 -5
- package/lib/commonjs/components/Carousel/Carousel.js +50 -9
- package/lib/commonjs/icons/registry.js +1 -1
- package/lib/module/components/CardCTA/CardCTA.js +4 -5
- package/lib/module/components/Carousel/Carousel.js +51 -10
- package/lib/module/icons/registry.js +1 -1
- package/lib/typescript/src/icons/registry.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/CardCTA/CardCTA.tsx +3 -4
- package/src/components/Carousel/Carousel.tsx +66 -7
- package/src/icons/registry.ts +1 -1
|
@@ -210,12 +210,11 @@ function CardCTA({
|
|
|
210
210
|
borderColor,
|
|
211
211
|
flexDirection: isRating || isSip ? 'column' : 'row',
|
|
212
212
|
overflow: 'visible',
|
|
213
|
-
//
|
|
214
|
-
//
|
|
213
|
+
// Pin footer to the bottom when a parent (e.g. equal-height Carousel)
|
|
214
|
+
// assigns an explicit height. Do not flexGrow — that unbounded-grows
|
|
215
|
+
// inside horizontal ScrollViews and blows cards to infinite height.
|
|
215
216
|
...(isRating ? {
|
|
216
|
-
|
|
217
|
-
justifyContent: 'space-between',
|
|
218
|
-
flexGrow: 1
|
|
217
|
+
justifyContent: 'space-between'
|
|
219
218
|
} : {})
|
|
220
219
|
};
|
|
221
220
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import React, { createContext, useContext, useRef, useState, useEffect, useCallback, useMemo } from 'react';
|
|
4
|
-
import { View, ScrollView, Animated, Pressable } from 'react-native';
|
|
4
|
+
import { View, ScrollView, Animated, Pressable, StyleSheet } from 'react-native';
|
|
5
5
|
import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
|
|
6
6
|
import { EMPTY_MODES } from '../../utils/react-utils';
|
|
7
7
|
import AutoplayControl from '../AutoplayControl/AutoplayControl';
|
|
@@ -96,6 +96,35 @@ export function Carousel({
|
|
|
96
96
|
return containerWidth - containerPaddingH * 4;
|
|
97
97
|
}, [itemWidthProp, itemInset, containerWidth, containerPaddingH, isNumbered]);
|
|
98
98
|
|
|
99
|
+
// Equal-height: measure each slide's intrinsic height, then lock every slot
|
|
100
|
+
// to the tallest. Do NOT use contentContainerStyle.alignItems:'stretch' or
|
|
101
|
+
// height:'100%' without a bounded cross-axis — in a horizontal ScrollView
|
|
102
|
+
// that resolves to an unbounded/infinite height.
|
|
103
|
+
const slideHeightsRef = useRef({});
|
|
104
|
+
const [equalizedHeight, setEqualizedHeight] = useState();
|
|
105
|
+
const equalizedHeightRef = useRef(undefined);
|
|
106
|
+
equalizedHeightRef.current = equalizedHeight;
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
slideHeightsRef.current = {};
|
|
109
|
+
equalizedHeightRef.current = undefined;
|
|
110
|
+
setEqualizedHeight(undefined);
|
|
111
|
+
}, [totalItems, effectiveItemWidth, equalHeight]);
|
|
112
|
+
const handleSlideLayout = useCallback(index => event => {
|
|
113
|
+
if (!equalHeight) return;
|
|
114
|
+
// Only measure while unconstrained. After lock, the slot height is forced
|
|
115
|
+
// and onLayout would just echo equalizedHeight.
|
|
116
|
+
if (equalizedHeightRef.current != null) return;
|
|
117
|
+
const height = Math.ceil(event.nativeEvent.layout.height);
|
|
118
|
+
if (height <= 0) return;
|
|
119
|
+
const previous = slideHeightsRef.current[index] ?? 0;
|
|
120
|
+
if (height <= previous) return;
|
|
121
|
+
slideHeightsRef.current[index] = height;
|
|
122
|
+
const measured = items.map((_, i) => slideHeightsRef.current[i]);
|
|
123
|
+
if (measured.some(value => value == null)) return;
|
|
124
|
+
const next = Math.max(...measured);
|
|
125
|
+
setEqualizedHeight(next);
|
|
126
|
+
}, [equalHeight, items]);
|
|
127
|
+
|
|
99
128
|
// Snap interval = item width + gap
|
|
100
129
|
const snapInterval = effectiveItemWidth + gap;
|
|
101
130
|
|
|
@@ -250,8 +279,9 @@ export function Carousel({
|
|
|
250
279
|
const contentContainerStyle = {
|
|
251
280
|
paddingHorizontal: effectivePaddingH,
|
|
252
281
|
gap,
|
|
253
|
-
//
|
|
254
|
-
|
|
282
|
+
// Always flex-start on the cross axis. Stretch + unbounded ScrollView
|
|
283
|
+
// height is what caused infinite-tall slides.
|
|
284
|
+
alignItems: 'flex-start'
|
|
255
285
|
};
|
|
256
286
|
return /*#__PURE__*/_jsx(CarouselContext.Provider, {
|
|
257
287
|
value: contextValue,
|
|
@@ -273,6 +303,8 @@ export function Carousel({
|
|
|
273
303
|
onScrollEndDrag: handleScrollEndDrag,
|
|
274
304
|
onMomentumScrollEnd: finishProgrammaticScroll,
|
|
275
305
|
children: items.map((child, index) => {
|
|
306
|
+
const hasEqualizedHeight = equalHeight && equalizedHeight != null && equalizedHeight > 0;
|
|
307
|
+
|
|
276
308
|
// Strict slot box: width must be honored; never grow or shrink with
|
|
277
309
|
// content, and clip anything that misbehaves (e.g. a child whose
|
|
278
310
|
// inner flex layout would otherwise leak into the next slot on
|
|
@@ -283,8 +315,8 @@ export function Carousel({
|
|
|
283
315
|
flexShrink: 0,
|
|
284
316
|
flexBasis: effectiveItemWidth > 0 ? effectiveItemWidth : 'auto',
|
|
285
317
|
overflow: 'hidden',
|
|
286
|
-
...(
|
|
287
|
-
|
|
318
|
+
...(hasEqualizedHeight ? {
|
|
319
|
+
height: equalizedHeight
|
|
288
320
|
} : {})
|
|
289
321
|
};
|
|
290
322
|
|
|
@@ -294,11 +326,11 @@ export function Carousel({
|
|
|
294
326
|
const childOverrideStyle = {
|
|
295
327
|
width: effectiveItemWidth > 0 ? effectiveItemWidth : undefined,
|
|
296
328
|
maxWidth: effectiveItemWidth > 0 ? effectiveItemWidth : undefined,
|
|
297
|
-
flexGrow:
|
|
329
|
+
flexGrow: 0,
|
|
298
330
|
flexShrink: 0,
|
|
299
|
-
...(
|
|
300
|
-
|
|
301
|
-
|
|
331
|
+
...(hasEqualizedHeight ? {
|
|
332
|
+
height: '100%',
|
|
333
|
+
alignSelf: 'stretch'
|
|
302
334
|
} : {})
|
|
303
335
|
};
|
|
304
336
|
|
|
@@ -312,7 +344,11 @@ export function Carousel({
|
|
|
312
344
|
}) : child;
|
|
313
345
|
return /*#__PURE__*/_jsx(View, {
|
|
314
346
|
style: slotStyle,
|
|
315
|
-
children:
|
|
347
|
+
children: /*#__PURE__*/_jsx(View, {
|
|
348
|
+
style: hasEqualizedHeight ? styles.equalizedFill : undefined,
|
|
349
|
+
onLayout: handleSlideLayout(index),
|
|
350
|
+
children: childWithModes
|
|
351
|
+
})
|
|
316
352
|
}, index);
|
|
317
353
|
})
|
|
318
354
|
}), !isNumbered && showPagination && totalItems > 1 && /*#__PURE__*/_jsx(Pagination, {
|
|
@@ -461,6 +497,11 @@ function AnimatedDot({
|
|
|
461
497
|
}
|
|
462
498
|
});
|
|
463
499
|
}
|
|
500
|
+
const styles = StyleSheet.create({
|
|
501
|
+
equalizedFill: {
|
|
502
|
+
flex: 1
|
|
503
|
+
}
|
|
504
|
+
});
|
|
464
505
|
|
|
465
506
|
// ---------------------------------------------------------------------------
|
|
466
507
|
// Attach sub-components
|