jfs-components 0.0.53 → 0.0.55

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.
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  import React, { useCallback, useEffect, useState, useRef } from 'react';
4
- import { StyleSheet, Text, useWindowDimensions, View } from 'react-native';
4
+ import { Platform, StyleSheet, Text, useWindowDimensions, View } from 'react-native';
5
5
  import { Gesture, GestureDetector, GestureHandlerRootView, ScrollView } from 'react-native-gesture-handler';
6
6
  import Animated, { runOnJS, useAnimatedProps, useAnimatedScrollHandler, useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
7
7
  import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
@@ -181,17 +181,24 @@ function Drawer({
181
181
  const totalRange = maxTranslateY - minTranslateY;
182
182
  const currentRatio = totalRange > 0 ? (translateY.value - minTranslateY) / totalRange : 0;
183
183
 
184
- // Fast fling always follow the fling direction
185
- if (event.velocityY < -500) {
184
+ // How far the drawer sheet itself moved from its position at gesture
185
+ // start. When the scroll view consumed the gesture (content was not
186
+ // at the top), the drawer stays put and displacement ≈ 0 — even
187
+ // though the finger moved fast. We must NOT use velocity to snap in
188
+ // that case; otherwise a fast content-scroll collapses the drawer.
189
+ const drawerDisplacement = Math.abs(translateY.value - context.value.y);
190
+ const drawerMovedEnough = drawerDisplacement > 10;
191
+ if (drawerMovedEnough && event.velocityY < -500) {
186
192
  scrollTo(minTranslateY);
187
193
  isFullyExpanded.value = true;
188
194
  runOnJS(updateMode)('expanded');
189
- } else if (event.velocityY > 500) {
195
+ } else if (drawerMovedEnough && event.velocityY > 500) {
190
196
  scrollTo(maxTranslateY);
191
197
  isFullyExpanded.value = false;
192
198
  runOnJS(updateMode)('collapsed');
193
199
  } else {
194
- // Slow / medium gesture use asymmetric snap thresholds.
200
+ // Slow / medium gesture, or the drawer barely moved → position
201
+ // based snap with asymmetric thresholds.
195
202
  // Down stroke: must cross 75% to collapse (hard to dismiss).
196
203
  // Up stroke: must reach top 35% to expand (35% from top).
197
204
  const isDraggingDown = event.velocityY >= 0;
@@ -258,7 +265,9 @@ function Drawer({
258
265
  rowGap: drawerGap
259
266
  }, sheetStyle, animatedStyle],
260
267
  accessible: true,
261
- accessibilityRole: 'dialog',
268
+ ...(Platform.OS === 'web' ? {
269
+ accessibilityRole: 'dialog'
270
+ } : undefined),
262
271
  accessibilityLabel: undefined,
263
272
  accessibilityHint: accessibilityHint || 'Swipe up to expand, swipe down to collapse',
264
273
  children: [/*#__PURE__*/_jsx(View, {
@@ -15,17 +15,21 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
15
15
  *
16
16
  * This component supports:
17
17
  * - **label** text at the top
18
- * - **listGroupSlot** for custom content (typically ListItem components)
18
+ * - **listGroupSlot** or **children** for content (typically ListItem components)
19
19
  * - **design-token driven styling** via `getVariableByName` and `modes`
20
20
  *
21
- * Wherever the Figma layer name contains "Slot", this component exposes a
22
- * dedicated React "slot" prop:
23
- * - Slot "List group" → `listGroupSlot`
21
+ * Content can be provided in two interchangeable ways:
22
+ * - Via the `listGroupSlot` prop (Figma Slot "List group")
23
+ * - Via `children`
24
+ *
25
+ * Both produce identical results. If both are provided, they are merged
26
+ * (listGroupSlot items render first, then children).
24
27
  *
25
28
  * @component
26
29
  * @param {Object} props
27
30
  * @param {string} [props.label=''] - Label text displayed at the top of the list group
28
- * @param {React.ReactNode} [props.listGroupSlot] - Optional custom slot for list items (Figma Slot "List group")
31
+ * @param {React.ReactNode} [props.listGroupSlot] - Slot for list items (Figma Slot "List group")
32
+ * @param {React.ReactNode} [props.children] - Children for list items (equivalent to listGroupSlot)
29
33
  * @param {Object} [props.modes={}] - Modes object passed to `getVariableByName` for all design tokens
30
34
  * @param {Object} [props.style] - Optional container style overrides
31
35
  * @param {string} [props.accessibilityLabel] - Accessibility label for the list group. If not provided, uses label
@@ -34,6 +38,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
34
38
  function ListGroup({
35
39
  label = '',
36
40
  listGroupSlot,
41
+ children,
37
42
  modes = {},
38
43
  style,
39
44
  accessibilityLabel,
@@ -70,10 +75,11 @@ function ListGroup({
70
75
  fontWeight: labelFontWeight
71
76
  };
72
77
 
73
- // Clone listGroupSlot children and pass modes to all children that accept it
74
- // We flatten children first so that if a Fragment is passed, the items inside
75
- // become direct children of the container, allowing `gap` to apply correctly between them.
76
- const processedSlot = listGroupSlot ? cloneChildrenWithModes(flattenChildren(listGroupSlot), modes) : null;
78
+ // Merge listGroupSlot and children into a single list, then flatten and
79
+ // propagate modes. Both props are interchangeable; when both are provided
80
+ // the slot items render first, followed by children.
81
+ const rawItems = [...(listGroupSlot ? flattenChildren(listGroupSlot) : []), ...(children ? flattenChildren(children) : [])];
82
+ const processedSlot = rawItems.length > 0 ? cloneChildrenWithModes(rawItems, modes) : null;
77
83
 
78
84
  // Use provided accessibilityLabel or fall back to label
79
85
  const defaultAccessibilityLabel = accessibilityLabel || label || "List group";
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  import React, { useState } from 'react';
4
- import { View, Text, Pressable } from 'react-native';
4
+ import { View, Text, Pressable, Platform } from 'react-native';
5
5
  import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
6
6
  import NavArrow from '../NavArrow/NavArrow';
7
7
  import { usePressableWebSupport } from '../../utils/web-platform-utils';
@@ -152,7 +152,9 @@ function Section({
152
152
  });
153
153
  return /*#__PURE__*/_jsxs(View, {
154
154
  style: [containerStyle, style],
155
- accessibilityRole: 'region',
155
+ ...(Platform.OS === 'web' ? {
156
+ accessibilityRole: 'region'
157
+ } : undefined),
156
158
  accessibilityLabel: undefined,
157
159
  accessibilityHint: accessibilityHint,
158
160
  ...rest,
@@ -252,7 +254,9 @@ function SectionBento({
252
254
  const processedUpiSlot = upiSlot ? cloneChildrenWithModes(React.Children.toArray(upiSlot), modes) : null;
253
255
  return /*#__PURE__*/_jsxs(View, {
254
256
  style: [containerStyle, style],
255
- accessibilityRole: 'region',
257
+ ...(Platform.OS === 'web' ? {
258
+ accessibilityRole: 'region'
259
+ } : undefined),
256
260
  accessibilityLabel: undefined,
257
261
  accessibilityHint: accessibilityHint,
258
262
  ...rest,