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.
@@ -210,12 +210,11 @@ function CardCTA({
210
210
  borderColor,
211
211
  flexDirection: isRating || isSip ? 'column' : 'row',
212
212
  overflow: 'visible',
213
- // Rating cards fill equal-height carousel slots and pin the footer down
214
- // when free space exists; intrinsic height is unchanged when not stretched.
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
- alignSelf: 'stretch',
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
- // Stretch so every slide matches the tallest (default). Opt out with equalHeight={false}.
254
- alignItems: equalHeight ? 'stretch' : 'flex-start'
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
- ...(equalHeight ? {
287
- alignSelf: 'stretch'
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: equalHeight ? 1 : 0,
329
+ flexGrow: 0,
298
330
  flexShrink: 0,
299
- ...(equalHeight ? {
300
- alignSelf: 'stretch',
301
- height: '100%'
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: childWithModes
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