jfs-components 0.0.54 → 0.0.56

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.
Files changed (55) hide show
  1. package/lib/commonjs/components/Accordion/Accordion.js +2 -34
  2. package/lib/commonjs/components/AppBar/AppBar.js +4 -36
  3. package/lib/commonjs/components/Drawer/Drawer.js +11 -4
  4. package/lib/commonjs/components/FilterBar/FilterBar.js +2 -34
  5. package/lib/commonjs/components/LazyList/LazyList.js +2 -34
  6. package/lib/commonjs/components/ListGroup/ListGroup.js +15 -9
  7. package/lib/commonjs/components/MoneyValue/MoneyValue.js +1 -1
  8. package/lib/commonjs/components/NavArrow/NavArrow.js +45 -44
  9. package/lib/commonjs/components/Numpad/Numpad.js +6 -5
  10. package/lib/commonjs/components/Section/Section.js +7 -8
  11. package/lib/commonjs/components/TextInput/TextInput.js +4 -38
  12. package/lib/commonjs/components/TransactionBubble/TransactionBubble.js +145 -0
  13. package/lib/commonjs/components/index.js +7 -0
  14. package/lib/commonjs/design-tokens/JFSThemeProvider.js +38 -3
  15. package/lib/commonjs/icons/registry.js +1 -1
  16. package/lib/commonjs/utils/react-utils.js +18 -13
  17. package/lib/module/components/Accordion/Accordion.js +1 -33
  18. package/lib/module/components/AppBar/AppBar.js +1 -34
  19. package/lib/module/components/Drawer/Drawer.js +11 -4
  20. package/lib/module/components/FilterBar/FilterBar.js +1 -35
  21. package/lib/module/components/LazyList/LazyList.js +1 -35
  22. package/lib/module/components/ListGroup/ListGroup.js +15 -9
  23. package/lib/module/components/MoneyValue/MoneyValue.js +1 -1
  24. package/lib/module/components/NavArrow/NavArrow.js +44 -44
  25. package/lib/module/components/Numpad/Numpad.js +5 -5
  26. package/lib/module/components/Section/Section.js +8 -9
  27. package/lib/module/components/TextInput/TextInput.js +2 -36
  28. package/lib/module/components/TransactionBubble/TransactionBubble.js +140 -0
  29. package/lib/module/components/index.js +1 -0
  30. package/lib/module/design-tokens/JFSThemeProvider.js +35 -3
  31. package/lib/module/icons/registry.js +1 -1
  32. package/lib/module/utils/react-utils.js +18 -13
  33. package/lib/typescript/src/components/ListGroup/ListGroup.d.ts +12 -7
  34. package/lib/typescript/src/components/NavArrow/NavArrow.d.ts +6 -11
  35. package/lib/typescript/src/components/TransactionBubble/TransactionBubble.d.ts +36 -0
  36. package/lib/typescript/src/components/index.d.ts +1 -0
  37. package/lib/typescript/src/design-tokens/JFSThemeProvider.d.ts +15 -0
  38. package/lib/typescript/src/icons/registry.d.ts +1 -1
  39. package/package.json +1 -1
  40. package/src/components/Accordion/Accordion.tsx +1 -44
  41. package/src/components/AppBar/AppBar.tsx +1 -44
  42. package/src/components/Drawer/Drawer.tsx +12 -4
  43. package/src/components/FilterBar/FilterBar.tsx +1 -44
  44. package/src/components/LazyList/LazyList.tsx +1 -41
  45. package/src/components/ListGroup/ListGroup.tsx +21 -11
  46. package/src/components/MoneyValue/MoneyValue.tsx +1 -1
  47. package/src/components/NavArrow/NavArrow.tsx +46 -43
  48. package/src/components/Numpad/Numpad.tsx +5 -5
  49. package/src/components/Section/Section.tsx +8 -8
  50. package/src/components/TextInput/TextInput.tsx +1 -44
  51. package/src/components/TransactionBubble/TransactionBubble.tsx +152 -0
  52. package/src/components/index.ts +1 -0
  53. package/src/design-tokens/JFSThemeProvider.tsx +37 -2
  54. package/src/icons/registry.ts +1 -1
  55. package/src/utils/react-utils.ts +29 -21
@@ -9,6 +9,7 @@ var _reactNative = require("react-native");
9
9
  var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
10
10
  var _Icon = _interopRequireDefault(require("../../icons/Icon"));
11
11
  var _webPlatformUtils = require("../../utils/web-platform-utils");
12
+ var _reactUtils = require("../../utils/react-utils");
12
13
  var _jsxRuntime = require("react/jsx-runtime");
13
14
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
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); }
@@ -16,39 +17,6 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
16
17
  if (_reactNative.Platform.OS === 'android' && _reactNative.UIManager.setLayoutAnimationEnabledExperimental) {
17
18
  _reactNative.UIManager.setLayoutAnimationEnabledExperimental(true);
18
19
  }
19
-
20
- /**
21
- * Helper function to recursively clone children and pass modes prop to components that accept it.
22
- * This ensures that all child components in slots receive the modes prop from the parent.
23
- */
24
- function cloneChildrenWithModes(children, modes) {
25
- const result = _react.default.Children.map(children, child => {
26
- if (! /*#__PURE__*/_react.default.isValidElement(child)) {
27
- return child;
28
- }
29
-
30
- // Get existing children
31
- const childChildren = child.props?.children;
32
- const hasChildren = childChildren !== undefined && childChildren !== null;
33
-
34
- // Merge modes: parent modes first, then child's explicit modes override them
35
- const existingModes = child.props?.modes;
36
- const mergedModes = existingModes ? {
37
- ...modes,
38
- ...existingModes
39
- } : modes;
40
-
41
- // Recursively process children if they exist
42
- const processedChildren = hasChildren ? cloneChildrenWithModes(_react.default.Children.toArray(childChildren), modes) : undefined;
43
-
44
- // Clone element with modes and processed children
45
- return /*#__PURE__*/_react.default.cloneElement(child, {
46
- ...child.props,
47
- modes: mergedModes
48
- }, processedChildren);
49
- });
50
- return result || [];
51
- }
52
20
  /**
53
21
  * Accordion component that mirrors the Figma "Accordion" component.
54
22
  *
@@ -173,7 +141,7 @@ function Accordion({
173
141
  });
174
142
 
175
143
  // Process children to pass modes
176
- const processedChildren = children ? cloneChildrenWithModes(_react.default.Children.toArray(children), modes) : null;
144
+ const processedChildren = children ? (0, _reactUtils.cloneChildrenWithModes)(_react.default.Children.toArray(children), modes) : null;
177
145
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
178
146
  style: [containerStyle, style],
179
147
  ...rest,
@@ -9,41 +9,9 @@ var _reactNative = require("react-native");
9
9
  var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
10
10
  var _JFSThemeProvider = require("../../design-tokens/JFSThemeProvider");
11
11
  var _NavArrow = _interopRequireDefault(require("../NavArrow/NavArrow"));
12
+ var _reactUtils = require("../../utils/react-utils");
12
13
  var _jsxRuntime = require("react/jsx-runtime");
13
14
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
- // We might need to import Image or Svg if we had the assets locally, but for now we'll use placeholders or standard icons for defaults.
15
- // The user prompt mentioned "Use getVariableByName... strict camelCase".
16
-
17
- /**
18
- * Helper function to recursively clone children and pass modes prop to components that accept it.
19
- */function cloneChildrenWithModes(children, modes) {
20
- return _react.default.Children.map(children, child => {
21
- if (! /*#__PURE__*/_react.default.isValidElement(child)) {
22
- return child;
23
- }
24
-
25
- // Get existing children
26
- const childChildren = child.props?.children;
27
- const hasChildren = childChildren !== undefined && childChildren !== null;
28
-
29
- // Clone the child with modes prop if it doesn't already have one
30
- // or merge with existing modes if it does
31
- const existingModes = child.props?.modes;
32
- const mergedModes = existingModes ? {
33
- ...modes,
34
- ...existingModes
35
- } : modes;
36
-
37
- // Recursively process children if they exist
38
- const processedChildren = hasChildren ? cloneChildrenWithModes(_react.default.Children.toArray(childChildren), modes) : undefined;
39
-
40
- // Clone element with modes and processed children
41
- return /*#__PURE__*/_react.default.cloneElement(child, {
42
- ...child.props,
43
- modes: mergedModes
44
- }, processedChildren);
45
- })?.filter(child => child !== null && child !== undefined) ?? [];
46
- }
47
15
  function AppBar({
48
16
  type = 'MainPage',
49
17
  leadingSlot,
@@ -133,8 +101,8 @@ function AppBar({
133
101
  }
134
102
 
135
103
  // --- Process Slots ---
136
- const processedLeading = leadingSlot ? cloneChildrenWithModes([leadingSlot], modes)[0] : defaultLeading;
137
- const processedMiddle = middleSlot ? cloneChildrenWithModes(_react.default.Children.toArray(middleSlot), modes) : null;
104
+ const processedLeading = leadingSlot ? (0, _reactUtils.cloneChildrenWithModes)([leadingSlot], modes)[0] : defaultLeading;
105
+ const processedMiddle = middleSlot ? (0, _reactUtils.cloneChildrenWithModes)(_react.default.Children.toArray(middleSlot), modes) : null;
138
106
 
139
107
  // Actions Gap wrapper
140
108
  // The Figma has "Actions" slot with a gap.
@@ -145,7 +113,7 @@ function AppBar({
145
113
  };
146
114
  const processedActions = actionsSlot ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
147
115
  style: actionsStyle,
148
- children: cloneChildrenWithModes(_react.default.Children.toArray(actionsSlot), modes)
116
+ children: (0, _reactUtils.cloneChildrenWithModes)(_react.default.Children.toArray(actionsSlot), modes)
149
117
  }) : null;
150
118
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
151
119
  style: [containerStyle, style],
@@ -186,17 +186,24 @@ function Drawer({
186
186
  const totalRange = maxTranslateY - minTranslateY;
187
187
  const currentRatio = totalRange > 0 ? (translateY.value - minTranslateY) / totalRange : 0;
188
188
 
189
- // Fast fling always follow the fling direction
190
- if (event.velocityY < -500) {
189
+ // How far the drawer sheet itself moved from its position at gesture
190
+ // start. When the scroll view consumed the gesture (content was not
191
+ // at the top), the drawer stays put and displacement ≈ 0 — even
192
+ // though the finger moved fast. We must NOT use velocity to snap in
193
+ // that case; otherwise a fast content-scroll collapses the drawer.
194
+ const drawerDisplacement = Math.abs(translateY.value - context.value.y);
195
+ const drawerMovedEnough = drawerDisplacement > 10;
196
+ if (drawerMovedEnough && event.velocityY < -500) {
191
197
  scrollTo(minTranslateY);
192
198
  isFullyExpanded.value = true;
193
199
  (0, _reactNativeReanimated.runOnJS)(updateMode)('expanded');
194
- } else if (event.velocityY > 500) {
200
+ } else if (drawerMovedEnough && event.velocityY > 500) {
195
201
  scrollTo(maxTranslateY);
196
202
  isFullyExpanded.value = false;
197
203
  (0, _reactNativeReanimated.runOnJS)(updateMode)('collapsed');
198
204
  } else {
199
- // Slow / medium gesture use asymmetric snap thresholds.
205
+ // Slow / medium gesture, or the drawer barely moved → position
206
+ // based snap with asymmetric thresholds.
200
207
  // Down stroke: must cross 75% to collapse (hard to dismiss).
201
208
  // Up stroke: must reach top 35% to expand (35% from top).
202
209
  const isDraggingDown = event.velocityY >= 0;
@@ -8,42 +8,10 @@ var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
10
10
  var _TextInput = _interopRequireDefault(require("../TextInput/TextInput"));
11
+ var _reactUtils = require("../../utils/react-utils");
11
12
  var _jsxRuntime = require("react/jsx-runtime");
12
13
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
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
- * Helper function to recursively clone children and pass modes prop to components that accept it.
16
- * This ensures that all child components in slots receive the modes prop from the parent.
17
- */function cloneChildrenWithModes(children, modes) {
18
- const result = _react.default.Children.map(children, child => {
19
- if (! /*#__PURE__*/_react.default.isValidElement(child)) {
20
- return child;
21
- }
22
-
23
- // Get existing children
24
- const childChildren = child.props?.children;
25
- const hasChildren = childChildren !== undefined && childChildren !== null;
26
-
27
- // Clone the child with modes prop if it doesn't already have one
28
- // or merge with existing modes if it does
29
- // Merge order: parent modes first, then child's explicit modes override them
30
- const existingModes = child.props?.modes;
31
- const mergedModes = existingModes ? {
32
- ...modes,
33
- ...existingModes
34
- } : modes;
35
-
36
- // Recursively process children if they exist
37
- const processedChildren = hasChildren ? cloneChildrenWithModes(_react.default.Children.toArray(childChildren), modes) : undefined;
38
-
39
- // Clone element with modes and processed children
40
- return /*#__PURE__*/_react.default.cloneElement(child, {
41
- ...child.props,
42
- modes: mergedModes
43
- }, processedChildren);
44
- });
45
- return result || [];
46
- }
47
15
  /**
48
16
  * FilterBar component that mirrors the Figma "filterBar" component.
49
17
  *
@@ -125,7 +93,7 @@ function FilterBar({
125
93
  });
126
94
  } else if (children) {
127
95
  // Clone custom children and inject onFocus/onBlur where possible.
128
- const cloned = cloneChildrenWithModes(_react.default.Children.toArray(children), modes);
96
+ const cloned = (0, _reactUtils.cloneChildrenWithModes)(_react.default.Children.toArray(children), modes);
129
97
  processedChildren = _react.default.Children.map(cloned, child => {
130
98
  if (! /*#__PURE__*/_react.default.isValidElement(child)) return child;
131
99
  const existingOnFocus = child.props?.onFocus;
@@ -7,41 +7,9 @@ exports.default = void 0;
7
7
  var _react = _interopRequireDefault(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
10
+ var _reactUtils = require("../../utils/react-utils");
10
11
  var _jsxRuntime = require("react/jsx-runtime");
11
12
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
- /**
13
- * Helper function to recursively clone children and pass modes prop to components that accept it.
14
- * This ensures that all child components in slots receive the modes prop from the parent.
15
- */function cloneChildrenWithModes(children, modes) {
16
- return _react.default.Children.map(children, child => {
17
- if (! /*#__PURE__*/_react.default.isValidElement(child)) {
18
- return child;
19
- }
20
-
21
- // Get existing children
22
- const childProps = child.props;
23
- const childChildren = childProps?.children;
24
- const hasChildren = childChildren !== undefined && childChildren !== null;
25
-
26
- // Clone the child with modes prop if it doesn't already have one
27
- // or merge with existing modes if it does
28
- // Merge order: parent modes first, then child's explicit modes override them
29
- const existingModes = childProps?.modes;
30
- const mergedModes = existingModes ? {
31
- ...modes,
32
- ...existingModes
33
- } : modes;
34
-
35
- // Recursively process children if they exist
36
- const processedChildren = hasChildren ? cloneChildrenWithModes(_react.default.Children.toArray(childChildren), modes) : undefined;
37
-
38
- // Clone element with modes and processed children
39
- return /*#__PURE__*/_react.default.cloneElement(child, {
40
- ...childProps,
41
- modes: mergedModes
42
- }, processedChildren);
43
- });
44
- }
45
13
  /**
46
14
  * LazyList component that mirrors the Figma "LazyList" component.
47
15
  *
@@ -85,7 +53,7 @@ function LazyList({
85
53
  };
86
54
 
87
55
  // Clone listGroupsSlot children and pass modes to all children that accept it
88
- const processedSlot = listGroupsSlot ? cloneChildrenWithModes(_react.default.Children.toArray(listGroupsSlot), modes) : null;
56
+ const processedSlot = listGroupsSlot ? (0, _reactUtils.cloneChildrenWithModes)(_react.default.Children.toArray(listGroupsSlot), modes) : null;
89
57
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
90
58
  style: [containerStyle, style],
91
59
  accessibilityRole: "list",
@@ -20,17 +20,21 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
20
20
  *
21
21
  * This component supports:
22
22
  * - **label** text at the top
23
- * - **listGroupSlot** for custom content (typically ListItem components)
23
+ * - **listGroupSlot** or **children** for content (typically ListItem components)
24
24
  * - **design-token driven styling** via `getVariableByName` and `modes`
25
25
  *
26
- * Wherever the Figma layer name contains "Slot", this component exposes a
27
- * dedicated React "slot" prop:
28
- * - Slot "List group" → `listGroupSlot`
26
+ * Content can be provided in two interchangeable ways:
27
+ * - Via the `listGroupSlot` prop (Figma Slot "List group")
28
+ * - Via `children`
29
+ *
30
+ * Both produce identical results. If both are provided, they are merged
31
+ * (listGroupSlot items render first, then children).
29
32
  *
30
33
  * @component
31
34
  * @param {Object} props
32
35
  * @param {string} [props.label=''] - Label text displayed at the top of the list group
33
- * @param {React.ReactNode} [props.listGroupSlot] - Optional custom slot for list items (Figma Slot "List group")
36
+ * @param {React.ReactNode} [props.listGroupSlot] - Slot for list items (Figma Slot "List group")
37
+ * @param {React.ReactNode} [props.children] - Children for list items (equivalent to listGroupSlot)
34
38
  * @param {Object} [props.modes={}] - Modes object passed to `getVariableByName` for all design tokens
35
39
  * @param {Object} [props.style] - Optional container style overrides
36
40
  * @param {string} [props.accessibilityLabel] - Accessibility label for the list group. If not provided, uses label
@@ -39,6 +43,7 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
39
43
  function ListGroup({
40
44
  label = '',
41
45
  listGroupSlot,
46
+ children,
42
47
  modes = {},
43
48
  style,
44
49
  accessibilityLabel,
@@ -75,10 +80,11 @@ function ListGroup({
75
80
  fontWeight: labelFontWeight
76
81
  };
77
82
 
78
- // Clone listGroupSlot children and pass modes to all children that accept it
79
- // We flatten children first so that if a Fragment is passed, the items inside
80
- // become direct children of the container, allowing `gap` to apply correctly between them.
81
- const processedSlot = listGroupSlot ? (0, _reactUtils.cloneChildrenWithModes)((0, _reactUtils.flattenChildren)(listGroupSlot), modes) : null;
83
+ // Merge listGroupSlot and children into a single list, then flatten and
84
+ // propagate modes. Both props are interchangeable; when both are provided
85
+ // the slot items render first, followed by children.
86
+ const rawItems = [...(listGroupSlot ? (0, _reactUtils.flattenChildren)(listGroupSlot) : []), ...(children ? (0, _reactUtils.flattenChildren)(children) : [])];
87
+ const processedSlot = rawItems.length > 0 ? (0, _reactUtils.cloneChildrenWithModes)(rawItems, modes) : null;
82
88
 
83
89
  // Use provided accessibilityLabel or fall back to label
84
90
  const defaultAccessibilityLabel = accessibilityLabel || label || "List group";
@@ -99,7 +99,7 @@ function MoneyValue({
99
99
  const fontWeightValue = (0, _figmaVariablesResolver.getVariableByName)('moneyValue/fontWeight', modes) || 500;
100
100
  const fontWeight = typeof fontWeightValue === 'number' ? fontWeightValue.toString() : fontWeightValue;
101
101
  const fontFamily = (0, _figmaVariablesResolver.getVariableByName)('moneyValue/fontFamily', modes) || 'System';
102
- const gap = (0, _figmaVariablesResolver.getVariableByName)('moneyValue/gap', modes) || 4;
102
+ const gap = (0, _figmaVariablesResolver.getVariableByName)('moneyValue/gap', modes) ?? 4;
103
103
 
104
104
  // Resolve currency to a symbol, supporting both symbols and ISO codes
105
105
  const resolvedCurrency = (0, _react.useMemo)(() => {
@@ -6,28 +6,24 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = NavArrow;
7
7
  var _react = _interopRequireDefault(require("react"));
8
8
  var _reactNative = require("react-native");
9
+ var _reactNativeSvg = _interopRequireWildcard(require("react-native-svg"));
9
10
  var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
10
- var _Icon = _interopRequireDefault(require("../../icons/Icon"));
11
11
  var _jsxRuntime = require("react/jsx-runtime");
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
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
14
  /**
14
- * NavArrow component that displays a small chevron arrow for navigation.
15
+ * NavArrow component that displays a chevron arrow for navigation.
15
16
  *
16
- * This component uses design tokens for all visual properties:
17
+ * Renders a stroked SVG chevron whose dimensions and thickness are
18
+ * fully driven by design tokens:
17
19
  * - navArrow/icon/color - chevron stroke color
18
- * - navArrow/icon/width - icon width
19
- * - navArrow/icon/height - icon height
20
- * - navArrow/icon/strokeWeight - stroke width
20
+ * - navArrow/icon/width - chevron arm width (horizontal spread)
21
+ * - navArrow/icon/height - chevron arm height (vertical spread)
22
+ * - navArrow/icon/strokeWeight - stroke thickness
21
23
  * - navArrow/width - container width
22
24
  * - navArrow/height - container height
23
25
  * - navArrow/radius - border radius
24
26
  * - navArrow/background - background color
25
- *
26
- * @component
27
- * @param {Object} props
28
- * @param {'Back'|'Forward'|'Down'} [props.direction='Back'] - Arrow direction
29
- * @param {Object} [props.modes={}] - Modes for design token resolution
30
- * @param {Object} [props.style] - Additional container styles
31
27
  */
32
28
  function NavArrow({
33
29
  direction = 'Back',
@@ -36,22 +32,20 @@ function NavArrow({
36
32
  accessibilityLabel,
37
33
  ...rest
38
34
  }) {
39
- // Resolve design tokens
40
35
  const iconColor = (0, _figmaVariablesResolver.getVariableByName)('navArrow/icon/color', modes) || '#24262b';
41
-
42
- // Dimensions from tokens
43
36
  const widthToken = Number((0, _figmaVariablesResolver.getVariableByName)('navArrow/width', modes)) || 6;
44
37
  const heightToken = Number((0, _figmaVariablesResolver.getVariableByName)('navArrow/height', modes)) || 10;
45
38
  const borderRadius = Number((0, _figmaVariablesResolver.getVariableByName)('navArrow/radius', modes)) || 0;
46
39
  const backgroundColor = (0, _figmaVariablesResolver.getVariableByName)('navArrow/background', modes) || 'transparent';
47
-
48
- // Swap dimensions if direction is Down
40
+ const iconWidth = Number((0, _figmaVariablesResolver.getVariableByName)('navArrow/icon/width', modes)) || 4;
41
+ const iconHeight = Number((0, _figmaVariablesResolver.getVariableByName)('navArrow/icon/height', modes)) || 8;
42
+ const strokeWeight = Number((0, _figmaVariablesResolver.getVariableByName)('navArrow/icon/strokeWeight', modes)) || 2;
49
43
  const isDown = direction === 'Down';
50
- const width = isDown ? heightToken : widthToken;
51
- const height = isDown ? widthToken : heightToken;
44
+ const containerWidth = isDown ? heightToken : widthToken;
45
+ const containerHeight = isDown ? widthToken : heightToken;
52
46
  const containerStyle = {
53
- width,
54
- height,
47
+ width: containerWidth,
48
+ height: containerHeight,
55
49
  borderRadius,
56
50
  backgroundColor,
57
51
  alignItems: 'center',
@@ -59,34 +53,41 @@ function NavArrow({
59
53
  ...(style || {})
60
54
  };
61
55
  const defaultAccessibilityLabel = accessibilityLabel || (direction === 'Back' ? 'Go back' : direction === 'Forward' ? 'Go forward' : 'Go down');
62
-
63
- // Map direction to icon name
64
- let iconName = 'ic_chevron_left'; // Default for Back
65
- if (direction === 'Forward') {
66
- iconName = 'ic_chevron_right';
67
- } else if (direction === 'Down') {
68
- iconName = 'ic_chevron_down';
56
+ const chevronW = isDown ? iconHeight : iconWidth;
57
+ const chevronH = isDown ? iconWidth : iconHeight;
58
+ const pad = strokeWeight / 2;
59
+ const svgWidth = chevronW + pad * 2;
60
+ const svgHeight = chevronH + pad * 2;
61
+ let points;
62
+ switch (direction) {
63
+ case 'Forward':
64
+ points = `${pad},${pad} ${chevronW + pad},${chevronH / 2 + pad} ${pad},${chevronH + pad}`;
65
+ break;
66
+ case 'Down':
67
+ points = `${pad},${pad} ${chevronW / 2 + pad},${chevronH + pad} ${chevronW + pad},${pad}`;
68
+ break;
69
+ case 'Back':
70
+ default:
71
+ points = `${chevronW + pad},${pad} ${pad},${chevronH / 2 + pad} ${chevronW + pad},${chevronH + pad}`;
72
+ break;
69
73
  }
70
74
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
71
75
  style: containerStyle,
72
76
  accessibilityRole: "image",
73
- accessibilityLabel: undefined,
77
+ accessibilityLabel: defaultAccessibilityLabel,
74
78
  ...rest,
75
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.default, {
76
- name: iconName,
77
- size: 24 // Internal icon size is fixed/clipped by container in design but Icon requires a size
78
- ,
79
- color: iconColor,
80
- style: {
81
- // Center the larger icon within the small container if needed,
82
- // though flex center on container handles this.
83
- // If the container is 6x10 and icon is 24, we might want to ensure it doesn't affect layout
84
- // but Flexbox 'center' centers the content.
85
- // However, if the icon component has its own frame, it might overflow.
86
- // React Native View has overflow: 'hidden' by default if borderRadius is set? No.
87
- // We might want overflow: 'hidden' if strictly following design clip.
88
- // Figma design had "overflow-clip" class.
89
- }
79
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.default, {
80
+ width: svgWidth,
81
+ height: svgHeight,
82
+ viewBox: `0 0 ${svgWidth} ${svgHeight}`,
83
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeSvg.Polyline, {
84
+ points: points,
85
+ stroke: iconColor,
86
+ strokeWidth: strokeWeight,
87
+ strokeLinecap: "round",
88
+ strokeLinejoin: "round",
89
+ fill: "none"
90
+ })
90
91
  })
91
92
  });
92
93
  }
@@ -7,8 +7,9 @@ exports.default = void 0;
7
7
  var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
10
- var _IconDeletebackspace = require("../../icons/components/IconDeletebackspace");
10
+ var _Icon = _interopRequireDefault(require("../../icons/Icon"));
11
11
  var _jsxRuntime = require("react/jsx-runtime");
12
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
13
  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); }
13
14
  function shuffleArray(arr) {
14
15
  const shuffled = [...arr];
@@ -92,10 +93,10 @@ function Numpad({
92
93
  onPress: () => handlePress(key),
93
94
  accessibilityRole: "button",
94
95
  accessibilityLabel: isBackspace ? 'Backspace' : key,
95
- children: isBackspace ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_IconDeletebackspace.IconDeletebackspace, {
96
- width: fontSize,
97
- height: fontSize,
98
- fill: foreground
96
+ children: isBackspace ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icon.default, {
97
+ name: "ic_delete_backspace",
98
+ size: fontSize,
99
+ color: foreground
99
100
  }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
100
101
  style: [textStyle, keyTextStyle],
101
102
  children: key
@@ -66,7 +66,8 @@ function Section({
66
66
  } : {};
67
67
  // Resolve section container tokens
68
68
  const backgroundColor = (0, _figmaVariablesResolver.getVariableByName)('section/background/color', modes) || '#ffffff';
69
- const gap = (0, _figmaVariablesResolver.getVariableByName)('slot/gap', modes) || 12;
69
+ const sectionGap = (0, _figmaVariablesResolver.getVariableByName)('section/gap', modes) || 12;
70
+ const slotGap = (0, _figmaVariablesResolver.getVariableByName)('slot/gap', modes) || 12;
70
71
  const paddingHorizontal = (0, _figmaVariablesResolver.getVariableByName)('section/padding/horizontal', modes) || 12;
71
72
  const paddingVertical = (0, _figmaVariablesResolver.getVariableByName)('section/padding/vertical', modes) || 16;
72
73
  const radius = (0, _figmaVariablesResolver.getVariableByName)('section/radius', modes) || 12;
@@ -96,7 +97,7 @@ function Section({
96
97
  paddingHorizontal,
97
98
  paddingVertical,
98
99
  borderRadius: radius,
99
- gap
100
+ gap: sectionGap
100
101
  };
101
102
  const headerStyle = {
102
103
  paddingHorizontal: headerPaddingHorizontal,
@@ -204,9 +205,9 @@ function Section({
204
205
  }), slot && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
205
206
  style: {
206
207
  flexDirection: slotDirection,
207
- gap
208
+ gap: slotGap
208
209
  },
209
- children: (0, _reactUtils.cloneChildrenWithModes)(_react.default.Children.toArray(slot), modes)
210
+ children: (0, _reactUtils.cloneChildrenWithModes)((0, _reactUtils.flattenChildren)(slot), modes)
210
211
  })]
211
212
  });
212
213
  }
@@ -254,10 +255,8 @@ function SectionBento({
254
255
  borderRadius: radius,
255
256
  gap
256
257
  };
257
-
258
- // Process slots to pass modes to children
259
- const processedNavSlot = navSlot ? (0, _reactUtils.cloneChildrenWithModes)(_react.default.Children.toArray(navSlot), modes) : null;
260
- const processedUpiSlot = upiSlot ? (0, _reactUtils.cloneChildrenWithModes)(_react.default.Children.toArray(upiSlot), modes) : null;
258
+ const processedNavSlot = navSlot ? (0, _reactUtils.cloneChildrenWithModes)((0, _reactUtils.flattenChildren)(navSlot), modes) : null;
259
+ const processedUpiSlot = upiSlot ? (0, _reactUtils.cloneChildrenWithModes)((0, _reactUtils.flattenChildren)(upiSlot), modes) : null;
261
260
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
262
261
  style: [containerStyle, style],
263
262
  ...(_reactNative.Platform.OS === 'web' ? {
@@ -8,43 +8,10 @@ var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
10
10
  var _Icon = _interopRequireDefault(require("../../icons/Icon"));
11
+ var _reactUtils = require("../../utils/react-utils");
11
12
  var _jsxRuntime = require("react/jsx-runtime");
12
13
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
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
- * Helper function to recursively clone children and pass modes prop to components that accept it.
16
- * This ensures that all child components in slots receive the modes prop from the parent.
17
- */function cloneChildrenWithModes(children, modes) {
18
- const result = _react.default.Children.map(children, child => {
19
- if (! /*#__PURE__*/_react.default.isValidElement(child)) {
20
- return child;
21
- }
22
-
23
- // Get existing children
24
- const childChildren = child.props?.children;
25
- const hasChildren = childChildren !== undefined && childChildren !== null;
26
-
27
- // Clone the child with modes prop if it doesn't already have one
28
- // or merge with existing modes if it does
29
- // Merge order: parent modes first, then child's explicit modes override them
30
- const existingModes = child.props?.modes;
31
- const mergedModes = existingModes ? {
32
- ...modes,
33
- ...existingModes
34
- } : modes;
35
-
36
- // Recursively process children if they exist
37
- const processedChildren = hasChildren ? cloneChildrenWithModes(_react.default.Children.toArray(childChildren), modes) : undefined;
38
-
39
- // Clone element with modes and processed children
40
- return /*#__PURE__*/_react.default.cloneElement(child, {
41
- ...child.props,
42
- modes: mergedModes
43
- }, processedChildren);
44
- });
45
- return result || [];
46
- }
47
-
48
15
  /**
49
16
  * TextInput component that mirrors the Figma "textInput" component.
50
17
  *
@@ -76,8 +43,7 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
76
43
  /**
77
44
  * Helper function to convert a color to a more transparent version for placeholder text.
78
45
  * Takes a color string (hex, rgb, rgba) and returns it with reduced opacity.
79
- */
80
- function makePlaceholderColor(color, opacity = 0.5) {
46
+ */function makePlaceholderColor(color, opacity = 0.5) {
81
47
  if (!color || typeof color !== 'string') {
82
48
  return color || '';
83
49
  }
@@ -220,8 +186,8 @@ function TextInput({
220
186
  });
221
187
 
222
188
  // Clone leading and trailing slots and pass modes to all children that accept it
223
- const processedLeading = leadingElement ? cloneChildrenWithModes(_react.default.Children.toArray(leadingElement), modes) : null;
224
- const processedTrailing = trailing ? cloneChildrenWithModes(_react.default.Children.toArray(trailing), modes) : null;
189
+ const processedLeading = leadingElement ? (0, _reactUtils.cloneChildrenWithModes)(_react.default.Children.toArray(leadingElement), modes) : null;
190
+ const processedTrailing = trailing ? (0, _reactUtils.cloneChildrenWithModes)(_react.default.Children.toArray(trailing), modes) : null;
225
191
 
226
192
  // Handle focus events
227
193
  const handleFocus = e => {