@seed-design/lynx-react 0.6.3 → 0.7.0

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 (234) hide show
  1. package/lib/components/Accordion/Accordion.d.ts.map +1 -1
  2. package/lib/components/Accordion/Accordion.jsx +24 -14
  3. package/lib/components/ActionButton/ActionButton.d.ts +1 -1
  4. package/lib/components/ActionButton/ActionButton.d.ts.map +1 -1
  5. package/lib/components/ActionButton/ActionButton.jsx +12 -4
  6. package/lib/components/AppBar/AppBar.d.ts.map +1 -1
  7. package/lib/components/AppBar/AppBar.jsx +9 -8
  8. package/lib/components/Badge/Badge.d.ts.map +1 -1
  9. package/lib/components/Badge/Badge.jsx +2 -1
  10. package/lib/components/BottomSheet/BottomSheet.d.ts.map +1 -1
  11. package/lib/components/BottomSheet/BottomSheet.jsx +9 -9
  12. package/lib/components/Box/Box.d.ts.map +1 -1
  13. package/lib/components/Box/Box.jsx +2 -1
  14. package/lib/components/Callout/Callout.d.ts +2 -2
  15. package/lib/components/Callout/Callout.d.ts.map +1 -1
  16. package/lib/components/Callout/Callout.jsx +20 -10
  17. package/lib/components/Checkbox/Checkbox.d.ts +4 -2
  18. package/lib/components/Checkbox/Checkbox.d.ts.map +1 -1
  19. package/lib/components/Checkbox/Checkbox.jsx +33 -17
  20. package/lib/components/Chip/Chip.d.ts +1 -1
  21. package/lib/components/Chip/Chip.d.ts.map +1 -1
  22. package/lib/components/Chip/Chip.jsx +36 -16
  23. package/lib/components/Count/Count.d.ts +7 -0
  24. package/lib/components/Count/Count.d.ts.map +1 -0
  25. package/lib/components/Count/Count.jsx +19 -0
  26. package/lib/components/Count/index.d.ts +2 -0
  27. package/lib/components/Count/index.d.ts.map +1 -0
  28. package/lib/components/Divider/Divider.d.ts.map +1 -1
  29. package/lib/components/Divider/Divider.jsx +2 -1
  30. package/lib/components/Field/Field.d.ts.map +1 -1
  31. package/lib/components/Field/Field.jsx +11 -15
  32. package/lib/components/Icon/Icon.d.ts.map +1 -1
  33. package/lib/components/Icon/Icon.jsx +4 -3
  34. package/lib/components/InputButton/InputButton.d.ts +40 -0
  35. package/lib/components/InputButton/InputButton.d.ts.map +1 -0
  36. package/lib/components/InputButton/InputButton.jsx +118 -0
  37. package/lib/components/InputButton/InputButton.namespace.d.ts +2 -0
  38. package/lib/components/InputButton/InputButton.namespace.d.ts.map +1 -0
  39. package/lib/components/InputButton/InputButton.namespace.js +16 -0
  40. package/lib/components/InputButton/index.d.ts +3 -0
  41. package/lib/components/InputButton/index.d.ts.map +1 -0
  42. package/lib/components/KeyboardAvoidingScrollView/KeyboardAvoidingScrollView.d.ts.map +1 -1
  43. package/lib/components/KeyboardAvoidingScrollView/KeyboardAvoidingScrollView.jsx +12 -8
  44. package/lib/components/List/List.d.ts +51 -0
  45. package/lib/components/List/List.d.ts.map +1 -0
  46. package/lib/components/List/List.jsx +176 -0
  47. package/lib/components/List/List.namespace.d.ts +2 -0
  48. package/lib/components/List/List.namespace.d.ts.map +1 -0
  49. package/lib/components/List/List.namespace.js +18 -0
  50. package/lib/components/List/index.d.ts +3 -0
  51. package/lib/components/List/index.d.ts.map +1 -0
  52. package/lib/components/MannerTemp/MannerTemp.d.ts.map +1 -1
  53. package/lib/components/MannerTemp/MannerTemp.jsx +3 -2
  54. package/lib/components/MannerTempBadge/MannerTempBadge.d.ts.map +1 -1
  55. package/lib/components/MannerTempBadge/MannerTempBadge.jsx +2 -1
  56. package/lib/components/Menu/Menu.d.ts +69 -0
  57. package/lib/components/Menu/Menu.d.ts.map +1 -0
  58. package/lib/components/Menu/Menu.jsx +520 -0
  59. package/lib/components/Menu/Menu.namespace.d.ts +2 -0
  60. package/lib/components/Menu/Menu.namespace.d.ts.map +1 -0
  61. package/lib/components/Menu/Menu.namespace.js +21 -0
  62. package/lib/components/Menu/index.d.ts +3 -0
  63. package/lib/components/Menu/index.d.ts.map +1 -0
  64. package/lib/components/NotificationBadge/NotificationBadge.d.ts.map +1 -1
  65. package/lib/components/NotificationBadge/NotificationBadge.jsx +3 -2
  66. package/lib/components/PageBanner/PageBanner.d.ts +5 -5
  67. package/lib/components/PageBanner/PageBanner.d.ts.map +1 -1
  68. package/lib/components/PageBanner/PageBanner.jsx +25 -14
  69. package/lib/components/ProgressCircle/ProgressCircle.d.ts +2 -2
  70. package/lib/components/ProgressCircle/ProgressCircle.d.ts.map +1 -1
  71. package/lib/components/ProgressCircle/ProgressCircle.jsx +4 -3
  72. package/lib/components/RadioGroup/RadioGroup.d.ts +5 -3
  73. package/lib/components/RadioGroup/RadioGroup.d.ts.map +1 -1
  74. package/lib/components/RadioGroup/RadioGroup.jsx +22 -9
  75. package/lib/components/ReactionButton/ReactionButton.d.ts +20 -0
  76. package/lib/components/ReactionButton/ReactionButton.d.ts.map +1 -0
  77. package/lib/components/ReactionButton/ReactionButton.jsx +88 -0
  78. package/lib/components/ReactionButton/index.d.ts +2 -0
  79. package/lib/components/ReactionButton/index.d.ts.map +1 -0
  80. package/lib/components/ScaleFeedback/ScaleFeedback.d.ts +11 -0
  81. package/lib/components/ScaleFeedback/ScaleFeedback.d.ts.map +1 -0
  82. package/lib/components/ScaleFeedback/ScaleFeedback.jsx +16 -0
  83. package/lib/components/ScaleFeedback/index.d.ts +2 -0
  84. package/lib/components/ScaleFeedback/index.d.ts.map +1 -0
  85. package/lib/components/SegmentedControl/SegmentedControl.d.ts +1 -0
  86. package/lib/components/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  87. package/lib/components/SegmentedControl/SegmentedControl.jsx +23 -10
  88. package/lib/components/SelectBox/SelectBox.d.ts.map +1 -1
  89. package/lib/components/SelectBox/SelectBox.jsx +23 -13
  90. package/lib/components/Stack/Stack.d.ts.map +1 -1
  91. package/lib/components/Stack/Stack.jsx +2 -1
  92. package/lib/components/SwipeableMenuSheet/SwipeableMenuSheet.d.ts +85 -0
  93. package/lib/components/SwipeableMenuSheet/SwipeableMenuSheet.d.ts.map +1 -0
  94. package/lib/components/SwipeableMenuSheet/SwipeableMenuSheet.jsx +256 -0
  95. package/lib/components/SwipeableMenuSheet/SwipeableMenuSheet.namespace.d.ts +2 -0
  96. package/lib/components/SwipeableMenuSheet/SwipeableMenuSheet.namespace.d.ts.map +1 -0
  97. package/lib/components/SwipeableMenuSheet/SwipeableMenuSheet.namespace.js +24 -0
  98. package/lib/components/SwipeableMenuSheet/index.d.ts +3 -0
  99. package/lib/components/SwipeableMenuSheet/index.d.ts.map +1 -0
  100. package/lib/components/Switch/Switch.d.ts +27 -3
  101. package/lib/components/Switch/Switch.d.ts.map +1 -1
  102. package/lib/components/Switch/Switch.jsx +22 -9
  103. package/lib/components/Tabs/Tabs.d.ts +4 -2
  104. package/lib/components/Tabs/Tabs.d.ts.map +1 -1
  105. package/lib/components/Tabs/Tabs.jsx +37 -22
  106. package/lib/components/TagGroup/TagGroup.d.ts.map +1 -1
  107. package/lib/components/TagGroup/TagGroup.jsx +4 -3
  108. package/lib/components/Text/Text.d.ts.map +1 -1
  109. package/lib/components/Text/Text.jsx +2 -1
  110. package/lib/components/TextField/TextField.d.ts.map +1 -1
  111. package/lib/components/TextField/TextField.jsx +35 -23
  112. package/lib/components/index.d.ts +7 -0
  113. package/lib/components/index.d.ts.map +1 -1
  114. package/lib/components/private/Positioning.d.ts +69 -0
  115. package/lib/components/private/Positioning.d.ts.map +1 -0
  116. package/lib/components/private/Positioning.js +109 -0
  117. package/lib/components/private/TrackPositioning.d.ts +22 -0
  118. package/lib/components/private/TrackPositioning.d.ts.map +1 -0
  119. package/lib/contexts/ScaleFeedbackContentContext.d.ts +4 -0
  120. package/lib/contexts/ScaleFeedbackContentContext.d.ts.map +1 -0
  121. package/lib/contexts/ScaleFeedbackContentContext.js +6 -0
  122. package/lib/contexts/index.d.ts +2 -0
  123. package/lib/contexts/index.d.ts.map +1 -0
  124. package/lib/hooks/index.d.ts +1 -0
  125. package/lib/hooks/index.d.ts.map +1 -1
  126. package/lib/hooks/useIconColor.d.ts.map +1 -1
  127. package/lib/hooks/useIconColor.js +1 -1
  128. package/lib/hooks/usePressTap.d.ts +4 -3
  129. package/lib/hooks/usePressTap.d.ts.map +1 -1
  130. package/lib/hooks/useScaleFeedback.d.ts +48 -0
  131. package/lib/hooks/useScaleFeedback.d.ts.map +1 -0
  132. package/lib/hooks/useScaleFeedback.js +108 -0
  133. package/lib/index.d.ts +1 -0
  134. package/lib/index.d.ts.map +1 -1
  135. package/lib/index.js +17 -3
  136. package/lib/node_modules/.bun/@floating-ui_core@1.8.0/node_modules/@floating-ui/core/dist/floating-ui.core.js +493 -0
  137. package/lib/node_modules/.bun/@floating-ui_utils@0.2.12/node_modules/@floating-ui/utils/dist/floating-ui.utils.js +114 -0
  138. package/lib/utils/calculate-scale-feedback.d.ts +5 -0
  139. package/lib/utils/calculate-scale-feedback.d.ts.map +1 -0
  140. package/lib/utils/calculate-scale-feedback.js +13 -0
  141. package/lib/utils/compose-event-handlers.d.ts +5 -0
  142. package/lib/utils/compose-event-handlers.d.ts.map +1 -0
  143. package/lib/utils/compose-event-handlers.js +16 -0
  144. package/lib/utils/create-slot-recipe-context.d.ts.map +1 -1
  145. package/lib/utils/create-slot-recipe-context.jsx +6 -16
  146. package/lib/utils/index.d.ts +1 -0
  147. package/lib/utils/index.d.ts.map +1 -1
  148. package/lib/utils/merge-props.d.ts +15 -0
  149. package/lib/utils/merge-props.d.ts.map +1 -0
  150. package/lib/utils/merge-props.js +36 -0
  151. package/lib/utils/merge-refs.d.ts +8 -0
  152. package/lib/utils/merge-refs.d.ts.map +1 -0
  153. package/lib/utils/merge-refs.js +38 -0
  154. package/package.json +6 -5
  155. package/src/components/Accordion/Accordion.tsx +36 -27
  156. package/src/components/ActionButton/ActionButton.tsx +27 -12
  157. package/src/components/AppBar/AppBar.tsx +17 -18
  158. package/src/components/Badge/Badge.tsx +2 -2
  159. package/src/components/BottomSheet/BottomSheet.tsx +9 -17
  160. package/src/components/Box/Box.tsx +2 -2
  161. package/src/components/Callout/Callout.tsx +39 -22
  162. package/src/components/Checkbox/Checkbox.test.tsx +44 -0
  163. package/src/components/Checkbox/Checkbox.tsx +52 -21
  164. package/src/components/Chip/Chip.test.tsx +50 -1
  165. package/src/components/Chip/Chip.tsx +75 -31
  166. package/src/components/Count/Count.tsx +35 -0
  167. package/src/components/Count/index.ts +1 -0
  168. package/src/components/Divider/Divider.tsx +2 -2
  169. package/src/components/Field/Field.tsx +15 -28
  170. package/src/components/Icon/Icon.tsx +14 -7
  171. package/src/components/InputButton/InputButton.namespace.ts +20 -0
  172. package/src/components/InputButton/InputButton.test.tsx +82 -0
  173. package/src/components/InputButton/InputButton.tsx +295 -0
  174. package/src/components/InputButton/index.ts +2 -0
  175. package/src/components/KeyboardAvoidingScrollView/KeyboardAvoidingScrollView.tsx +16 -21
  176. package/src/components/List/List.namespace.ts +24 -0
  177. package/src/components/List/List.test.tsx +162 -0
  178. package/src/components/List/List.tsx +476 -0
  179. package/src/components/List/index.ts +3 -0
  180. package/src/components/MannerTemp/MannerTemp.tsx +3 -4
  181. package/src/components/MannerTempBadge/MannerTempBadge.tsx +2 -2
  182. package/src/components/Menu/Menu.namespace.ts +26 -0
  183. package/src/components/Menu/Menu.tsx +883 -0
  184. package/src/components/Menu/index.ts +31 -0
  185. package/src/components/NotificationBadge/NotificationBadge.tsx +4 -9
  186. package/src/components/PageBanner/PageBanner.test.tsx +3 -0
  187. package/src/components/PageBanner/PageBanner.tsx +54 -45
  188. package/src/components/ProgressCircle/ProgressCircle.test.tsx +48 -0
  189. package/src/components/ProgressCircle/ProgressCircle.tsx +22 -3
  190. package/src/components/RadioGroup/RadioGroup.test.tsx +87 -0
  191. package/src/components/RadioGroup/RadioGroup.tsx +50 -14
  192. package/src/components/ReactionButton/ReactionButton.test.tsx +122 -0
  193. package/src/components/ReactionButton/ReactionButton.tsx +139 -0
  194. package/src/components/ReactionButton/index.ts +1 -0
  195. package/src/components/ScaleFeedback/ScaleFeedback.test.tsx +41 -0
  196. package/src/components/ScaleFeedback/ScaleFeedback.tsx +32 -0
  197. package/src/components/ScaleFeedback/index.ts +1 -0
  198. package/src/components/SegmentedControl/SegmentedControl.test.tsx +15 -3
  199. package/src/components/SegmentedControl/SegmentedControl.tsx +35 -14
  200. package/src/components/SelectBox/SelectBox.test.tsx +39 -1
  201. package/src/components/SelectBox/SelectBox.tsx +27 -16
  202. package/src/components/Stack/Stack.tsx +2 -2
  203. package/src/components/SwipeableMenuSheet/SwipeableMenuSheet.namespace.ts +37 -0
  204. package/src/components/SwipeableMenuSheet/SwipeableMenuSheet.test.tsx +258 -0
  205. package/src/components/SwipeableMenuSheet/SwipeableMenuSheet.tsx +655 -0
  206. package/src/components/SwipeableMenuSheet/index.ts +43 -0
  207. package/src/components/Switch/Switch.test.tsx +57 -0
  208. package/src/components/Switch/Switch.tsx +60 -16
  209. package/src/components/Tabs/Tabs.test.tsx +19 -0
  210. package/src/components/Tabs/Tabs.tsx +72 -40
  211. package/src/components/TagGroup/TagGroup.tsx +4 -6
  212. package/src/components/Text/Text.tsx +2 -2
  213. package/src/components/TextField/TextField.tsx +60 -54
  214. package/src/components/index.ts +7 -0
  215. package/src/components/private/Positioning.test.ts +235 -0
  216. package/src/components/private/Positioning.ts +223 -0
  217. package/src/components/private/TrackPositioning.test.ts +58 -0
  218. package/src/components/private/TrackPositioning.ts +37 -0
  219. package/src/contexts/ScaleFeedbackContentContext.ts +4 -0
  220. package/src/contexts/index.ts +1 -0
  221. package/src/hooks/index.ts +1 -0
  222. package/src/hooks/useIconColor.ts +5 -4
  223. package/src/hooks/usePressTap.ts +4 -3
  224. package/src/hooks/useScaleFeedback.integration.test.tsx +85 -0
  225. package/src/hooks/useScaleFeedback.test.ts +50 -0
  226. package/src/hooks/useScaleFeedback.ts +199 -0
  227. package/src/index.ts +1 -0
  228. package/src/utils/calculate-scale-feedback.ts +12 -0
  229. package/src/utils/compose-event-handlers.ts +16 -0
  230. package/src/utils/create-slot-recipe-context.tsx +6 -7
  231. package/src/utils/index.ts +1 -0
  232. package/src/utils/merge-props.test.tsx +152 -0
  233. package/src/utils/merge-props.ts +62 -0
  234. package/src/utils/merge-refs.ts +44 -0
@@ -7,6 +7,8 @@ import {
7
7
  type SelectBoxCheckmarkVariantProps,
8
8
  } from "@seed-design/lynx-css/recipes/select-box-checkmark";
9
9
  import { selectBoxGroup } from "@seed-design/lynx-css/recipes/select-box-group";
10
+ import type { ScaleFeedbackTargetProps } from "../../hooks/useScaleFeedback";
11
+ import { ScaleFeedbackContentContext } from "../../contexts";
10
12
 
11
13
  import type {
12
14
  LynxAccessibilityProps,
@@ -23,6 +25,7 @@ import {
23
25
  type RadioGroupItemProps,
24
26
  useRadioGroupItemContext,
25
27
  } from "../RadioGroup/RadioGroup";
28
+ import { mergeProps } from "../../utils/merge-props";
26
29
 
27
30
  /**
28
31
  * @platform Lynx
@@ -46,6 +49,7 @@ interface SelectBoxRuntimeContextValue {
46
49
  footerVisibility: FooterVisibility;
47
50
  variantProps: PublicSelectBoxVariantProps;
48
51
  accessibilityRole: "checkbox" | "radio";
52
+ scaleFeedbackTargetProps: ScaleFeedbackTargetProps;
49
53
  }
50
54
 
51
55
  const SelectBoxRuntimeContext = React.createContext<SelectBoxRuntimeContextValue | null>(null);
@@ -99,7 +103,11 @@ function SelectBoxSurface({
99
103
  accessibility-traits={context.disabled ? "disabled" : undefined}
100
104
  {...accessibilityProps}
101
105
  >
102
- {children}
106
+ <view className={classes.scaleContent} {...context.scaleFeedbackTargetProps}>
107
+ <ScaleFeedbackContentContext.Provider value={true}>
108
+ {children}
109
+ </ScaleFeedbackContentContext.Provider>
110
+ </view>
103
111
  <view className={classes.selectedStroke} accessibility-elements-hidden={true} />
104
112
  </view>
105
113
  </IconSlotProvider>
@@ -125,10 +133,9 @@ const SelectBoxGroup = React.forwardRef<unknown, SelectBoxGroupProps>((props, re
125
133
  return (
126
134
  <SelectBoxLayoutContext.Provider value={{ layout }}>
127
135
  <view
128
- {...(ref ? { ref: ref as LynxViewRef } : {})}
136
+ {...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
129
137
  className={clsx(classes, className)}
130
138
  style={{ ...style, gridTemplateColumns: `repeat(${columns}, 1fr)` }}
131
- {...nativeProps}
132
139
  >
133
140
  {children}
134
141
  </view>
@@ -172,11 +179,13 @@ function CheckSelectBoxSurface(props: CheckSelectBoxSurfaceProps) {
172
179
  footerVisibility: props.footerVisibility,
173
180
  variantProps: props.variantProps,
174
181
  accessibilityRole: "checkbox",
182
+ scaleFeedbackTargetProps: checkbox.scaleFeedbackTargetProps,
175
183
  }),
176
184
  [
177
185
  checkbox.checked,
178
186
  checkbox.disabled,
179
187
  checkbox.pressed,
188
+ checkbox.scaleFeedbackTargetProps,
180
189
  props.footerVisibility,
181
190
  props.variantProps,
182
191
  ],
@@ -263,8 +272,16 @@ function RadioSelectBoxSurface(props: RadioSelectBoxSurfaceProps) {
263
272
  footerVisibility: props.footerVisibility,
264
273
  variantProps: props.variantProps,
265
274
  accessibilityRole: "radio",
275
+ scaleFeedbackTargetProps: item.scaleFeedbackTargetProps,
266
276
  }),
267
- [item.checked, item.disabled, item.pressed, props.footerVisibility, props.variantProps],
277
+ [
278
+ item.checked,
279
+ item.disabled,
280
+ item.pressed,
281
+ item.scaleFeedbackTargetProps,
282
+ props.footerVisibility,
283
+ props.variantProps,
284
+ ],
268
285
  );
269
286
 
270
287
  return (
@@ -325,9 +342,8 @@ function createViewSlot(displayName: string, slot: keyof ReturnType<typeof selec
325
342
 
326
343
  return (
327
344
  <view
328
- {...(ref ? { ref: ref as LynxViewRef } : {})}
345
+ {...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
329
346
  className={clsx(classes[slot], className)}
330
- {...nativeProps}
331
347
  >
332
348
  {children}
333
349
  </view>
@@ -344,9 +360,8 @@ function createTextSlot(displayName: string, slot: keyof ReturnType<typeof selec
344
360
 
345
361
  return (
346
362
  <text
347
- {...(ref ? { ref: ref as LynxTextRef } : {})}
363
+ {...mergeProps(ref ? { ref: ref as LynxTextRef } : {}, nativeProps)}
348
364
  className={clsx(classes[slot], className)}
349
- {...nativeProps}
350
365
  >
351
366
  {children}
352
367
  </text>
@@ -369,9 +384,8 @@ function createLabelSlot(displayName: string) {
369
384
 
370
385
  return (
371
386
  <view
372
- {...(ref ? { ref: ref as LynxViewRef } : {})}
387
+ {...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
373
388
  className={clsx(classes.label, className)}
374
- {...nativeProps}
375
389
  >
376
390
  {labelChildren}
377
391
  </view>
@@ -437,7 +451,7 @@ const SelectBoxFooter = React.forwardRef<unknown, SelectBoxFooterProps>((props,
437
451
 
438
452
  return (
439
453
  <view
440
- {...(ref ? { ref: ref as LynxViewRef } : {})}
454
+ {...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
441
455
  className={clsx(classes.footer, className)}
442
456
  style={{
443
457
  ...style,
@@ -449,7 +463,6 @@ const SelectBoxFooter = React.forwardRef<unknown, SelectBoxFooterProps>((props,
449
463
  : "0px",
450
464
  }}
451
465
  accessibility-elements-hidden={!open || accessibilityElementsHidden}
452
- {...nativeProps}
453
466
  >
454
467
  <view className={classes.footerInner} bindlayoutchange={handleLayoutChange}>
455
468
  {children}
@@ -491,10 +504,9 @@ export const CheckSelectBoxCheckmarkControl = React.forwardRef<
491
504
  return (
492
505
  <SelectBoxCheckmarkContext.Provider value={{ iconClassName: classes.icon, variantProps }}>
493
506
  <view
494
- {...(ref ? { ref: ref as LynxViewRef } : {})}
507
+ {...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
495
508
  className={clsx(classes.root, className)}
496
509
  accessibility-elements-hidden={true}
497
- {...nativeProps}
498
510
  >
499
511
  {children}
500
512
  </view>
@@ -519,14 +531,13 @@ export const CheckSelectBoxCheckmarkIcon = React.forwardRef<
519
531
 
520
532
  return (
521
533
  <InternalIcon
522
- ref={ref}
534
+ {...mergeProps({ ref }, otherProps)}
523
535
  className={clsx(context.iconClassName, className)}
524
536
  deps={[
525
537
  context.variantProps.selected,
526
538
  context.variantProps.pressed,
527
539
  context.variantProps.disabled,
528
540
  ]}
529
- {...otherProps}
530
541
  />
531
542
  );
532
543
  });
@@ -3,6 +3,7 @@ import * as React from "@lynx-js/react";
3
3
 
4
4
  import type { LynxPressableProps, LynxStyledElementProps, LynxViewRef } from "../../types";
5
5
  import { useStyleProps, type StyleProps } from "../../utils/styled";
6
+ import { mergeProps } from "../../utils/merge-props";
6
7
 
7
8
  type StackStyleProps =
8
9
  | "display"
@@ -84,8 +85,7 @@ function renderStackView(
84
85
 
85
86
  return (
86
87
  <view
87
- {...(ref ? { ref: ref as LynxViewRef } : {})}
88
- {...nativeProps}
88
+ {...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
89
89
  className={clsx(className)}
90
90
  style={style}
91
91
  >
@@ -0,0 +1,37 @@
1
+ export {
2
+ SwipeableMenuSheetBackdrop as Backdrop,
3
+ SwipeableMenuSheetCloseButton as CloseButton,
4
+ SwipeableMenuSheetContent as Content,
5
+ SwipeableMenuSheetDescription as Description,
6
+ SwipeableMenuSheetFooter as Footer,
7
+ SwipeableMenuSheetGroup as Group,
8
+ SwipeableMenuSheetHandle as Handle,
9
+ SwipeableMenuSheetHeader as Header,
10
+ SwipeableMenuSheetItem as Item,
11
+ SwipeableMenuSheetItemContent as ItemContent,
12
+ SwipeableMenuSheetItemDescription as ItemDescription,
13
+ SwipeableMenuSheetItemLabel as ItemLabel,
14
+ SwipeableMenuSheetList as List,
15
+ SwipeableMenuSheetPositioner as Positioner,
16
+ SwipeableMenuSheetRoot as Root,
17
+ SwipeableMenuSheetTitle as Title,
18
+ SwipeableMenuSheetTrigger as Trigger,
19
+ type SwipeableMenuSheetBackdropProps as BackdropProps,
20
+ type SwipeableMenuSheetCloseButtonProps as CloseButtonProps,
21
+ type SwipeableMenuSheetContentProps as ContentProps,
22
+ type SwipeableMenuSheetDescriptionProps as DescriptionProps,
23
+ type SwipeableMenuSheetFooterProps as FooterProps,
24
+ type SwipeableMenuSheetGroupProps as GroupProps,
25
+ type SwipeableMenuSheetHandleProps as HandleProps,
26
+ type SwipeableMenuSheetHeaderProps as HeaderProps,
27
+ type SwipeableMenuSheetItemContentProps as ItemContentProps,
28
+ type SwipeableMenuSheetItemDescriptionProps as ItemDescriptionProps,
29
+ type SwipeableMenuSheetItemLabelProps as ItemLabelProps,
30
+ type SwipeableMenuSheetItemProps as ItemProps,
31
+ type SwipeableMenuSheetListProps as ListProps,
32
+ type SwipeableMenuSheetPositionerProps as PositionerProps,
33
+ type SwipeableMenuSheetRootProps as RootProps,
34
+ type SwipeableMenuSheetRootRef as RootRef,
35
+ type SwipeableMenuSheetTitleProps as TitleProps,
36
+ type SwipeableMenuSheetTriggerProps as TriggerProps,
37
+ } from "./SwipeableMenuSheet";
@@ -0,0 +1,258 @@
1
+ import { fireEvent, render } from "@lynx-js/react/testing-library";
2
+ import { beforeEach, describe, expect, it, vi } from "vitest";
3
+
4
+ import type { LynxPressableProps } from "../../types";
5
+
6
+ const sheetMocks = vi.hoisted(() => ({
7
+ contentProps: [] as Array<Record<string, unknown>>,
8
+ rootProps: [] as Array<Record<string, unknown>>,
9
+ rootRef: {
10
+ close: vi.fn(),
11
+ open: vi.fn(),
12
+ },
13
+ }));
14
+
15
+ vi.mock("@lynx-js/lynx-ui-sheet", async () => {
16
+ const React = await vi.importActual<typeof import("@lynx-js/react")>("@lynx-js/react");
17
+
18
+ const SheetRoot = React.forwardRef<
19
+ unknown,
20
+ Record<string, unknown> & { children?: React.ReactNode }
21
+ >((props, ref) => {
22
+ sheetMocks.rootProps.push(props);
23
+ React.useImperativeHandle(ref, () => sheetMocks.rootRef);
24
+ return <>{props["children"]}</>;
25
+ });
26
+ SheetRoot.displayName = "MockSheetRoot";
27
+
28
+ const SheetView = React.forwardRef<unknown, { children?: React.ReactNode }>((props) => {
29
+ return <>{props.children}</>;
30
+ });
31
+ SheetView.displayName = "MockSheetView";
32
+
33
+ const SheetContent = React.forwardRef<
34
+ unknown,
35
+ Record<string, unknown> & { children?: React.ReactNode }
36
+ >((props) => {
37
+ sheetMocks.contentProps.push(props);
38
+ return <>{props["children"]}</>;
39
+ });
40
+ SheetContent.displayName = "MockSheetContent";
41
+
42
+ const SheetBackdrop = (
43
+ props: Record<string, unknown> & {
44
+ children?: React.ReactNode;
45
+ onClick?: () => void;
46
+ },
47
+ ) => {
48
+ const handlers: Pick<LynxPressableProps, "bindtap"> = {
49
+ bindtap: props["onClick"],
50
+ };
51
+
52
+ return <view {...handlers}>{props["children"]}</view>;
53
+ };
54
+
55
+ const SheetHandle = (props: Record<string, unknown> & { children?: React.ReactNode }) => {
56
+ return <view className={props["className"] as string}>{props["children"]}</view>;
57
+ };
58
+
59
+ return { SheetBackdrop, SheetContent, SheetHandle, SheetRoot, SheetView };
60
+ });
61
+
62
+ vi.mock("../../hooks/useSafeArea", () => ({
63
+ useSafeArea: () => ({ safeAreaInsetBottom: "34px", safeAreaInsetTop: "0px" }),
64
+ }));
65
+
66
+ import * as SwipeableMenuSheet from "./SwipeableMenuSheet.namespace";
67
+
68
+ describe("SwipeableMenuSheet", () => {
69
+ beforeEach(() => {
70
+ sheetMocks.contentProps = [];
71
+ sheetMocks.rootProps = [];
72
+ sheetMocks.rootRef.close.mockClear();
73
+ sheetMocks.rootRef.open.mockClear();
74
+ });
75
+
76
+ it("fixes the engine to a bottom, fit-height sheet", () => {
77
+ render(
78
+ <SwipeableMenuSheet.Root forceMount>
79
+ <SwipeableMenuSheet.Positioner>
80
+ <SwipeableMenuSheet.Content />
81
+ </SwipeableMenuSheet.Positioner>
82
+ </SwipeableMenuSheet.Root>,
83
+ );
84
+
85
+ expect(sheetMocks.rootProps.at(-1)).toMatchObject({
86
+ forceMount: true,
87
+ side: "bottom",
88
+ snapPoints: ["fit"],
89
+ });
90
+ });
91
+
92
+ it("exposes the Trigger as an accessible button", () => {
93
+ const { getByText } = render(
94
+ <SwipeableMenuSheet.Root>
95
+ <SwipeableMenuSheet.Trigger>
96
+ <text>Open</text>
97
+ </SwipeableMenuSheet.Trigger>
98
+ </SwipeableMenuSheet.Root>,
99
+ );
100
+
101
+ const trigger = (getByText("Open") as HTMLElement).parentElement;
102
+ if (!trigger) throw new Error("Expected menu sheet trigger.");
103
+
104
+ expect(trigger.getAttribute("accessibility-element")).to.equal("true");
105
+ expect(trigger.hasAttribute("accessibility-role-description")).to.equal(true);
106
+ expect(trigger.getAttribute("accessibility-role-description")).to.equal("button");
107
+ });
108
+
109
+ it("keeps outer and inner Content classes separate while preserving safe-area padding", () => {
110
+ render(
111
+ <SwipeableMenuSheet.Root>
112
+ <SwipeableMenuSheet.Content
113
+ accessibility-label="Menu options"
114
+ className="outer"
115
+ innerClassName="inner"
116
+ innerStyle={{ paddingTop: "8px" }}
117
+ />
118
+ </SwipeableMenuSheet.Root>,
119
+ );
120
+
121
+ expect(sheetMocks.contentProps.at(-1)).toMatchObject({
122
+ "accessibility-label": "Menu options",
123
+ className: expect.stringContaining("outer"),
124
+ innerClassName: expect.stringContaining("inner"),
125
+ innerStyle: {
126
+ paddingBottom: "calc(16px + 34px)",
127
+ display: "flex",
128
+ flexDirection: "column",
129
+ minHeight: "0",
130
+ paddingTop: "8px",
131
+ },
132
+ });
133
+ });
134
+
135
+ it("records trigger and close button reasons without dropping user handlers", () => {
136
+ const onOpenChange = vi.fn();
137
+ const onTriggerTap = vi.fn();
138
+ const onCloseTap = vi.fn();
139
+ const { getByText } = render(
140
+ <SwipeableMenuSheet.Root onOpenChange={onOpenChange}>
141
+ <SwipeableMenuSheet.Trigger bindtap={onTriggerTap}>
142
+ <text>Open</text>
143
+ </SwipeableMenuSheet.Trigger>
144
+ <SwipeableMenuSheet.CloseButton bindtap={onCloseTap}>Close</SwipeableMenuSheet.CloseButton>
145
+ </SwipeableMenuSheet.Root>,
146
+ );
147
+
148
+ const trigger = (getByText("Open") as HTMLElement).parentElement;
149
+ const closeButtonLabel = getByText("Close") as HTMLElement;
150
+ const closeButton = closeButtonLabel.parentElement;
151
+ if (!trigger || !closeButton || closeButtonLabel.tagName.toLowerCase() !== "text") {
152
+ throw new Error("Expected menu sheet controls with a native close button label.");
153
+ }
154
+
155
+ expect(closeButtonLabel.className).toContain("seed-menu-sheet__closeButtonLabel");
156
+
157
+ fireEvent.tap(trigger);
158
+ expect(sheetMocks.rootRef.open).toHaveBeenCalledWith();
159
+ expect(onTriggerTap).toHaveBeenCalledOnce();
160
+ (sheetMocks.rootProps.at(-1)?.["onShowChange"] as (open: boolean) => void)(true);
161
+ expect(onOpenChange).toHaveBeenLastCalledWith(true, { reason: "trigger" });
162
+
163
+ fireEvent.tap(closeButton);
164
+ expect(sheetMocks.rootRef.close).toHaveBeenCalledWith();
165
+ expect(onCloseTap).toHaveBeenCalledOnce();
166
+ (sheetMocks.rootProps.at(-1)?.["onShowChange"] as (open: boolean) => void)(false);
167
+ expect(onOpenChange).toHaveBeenLastCalledWith(false, { reason: "closeButton" });
168
+ });
169
+
170
+ it("uses an outside-interaction reason for a closing backdrop", () => {
171
+ const onOpenChange = vi.fn();
172
+ const { getByText } = render(
173
+ <SwipeableMenuSheet.Root onOpenChange={onOpenChange}>
174
+ <SwipeableMenuSheet.Backdrop>
175
+ <text>Dismiss</text>
176
+ </SwipeableMenuSheet.Backdrop>
177
+ </SwipeableMenuSheet.Root>,
178
+ );
179
+
180
+ const backdrop = (getByText("Dismiss") as HTMLElement).parentElement;
181
+ if (!backdrop) throw new Error("Expected backdrop element.");
182
+ fireEvent.tap(backdrop);
183
+ (sheetMocks.rootProps.at(-1)?.["onShowChange"] as (open: boolean) => void)(false);
184
+
185
+ expect(sheetMocks.rootRef.close).toHaveBeenCalledWith();
186
+ expect(onOpenChange).toHaveBeenCalledWith(false, { reason: "interactOutside" });
187
+ });
188
+
189
+ it("inherits label alignment, supports wrapped items, omits the final divider, and leaves item taps open", () => {
190
+ const onItemTap = vi.fn();
191
+ function WrappedItem() {
192
+ return (
193
+ <SwipeableMenuSheet.Item bindtap={onItemTap}>
194
+ <SwipeableMenuSheet.ItemContent>
195
+ <SwipeableMenuSheet.ItemLabel>First item</SwipeableMenuSheet.ItemLabel>
196
+ </SwipeableMenuSheet.ItemContent>
197
+ </SwipeableMenuSheet.Item>
198
+ );
199
+ }
200
+
201
+ const { container, getByText } = render(
202
+ <SwipeableMenuSheet.Root>
203
+ <SwipeableMenuSheet.Content labelAlign="center">
204
+ <SwipeableMenuSheet.List>
205
+ <SwipeableMenuSheet.Group labelAlign="left">
206
+ <WrappedItem />
207
+ <SwipeableMenuSheet.Item labelAlign="center">
208
+ <SwipeableMenuSheet.ItemContent>
209
+ <SwipeableMenuSheet.ItemLabel>Second item</SwipeableMenuSheet.ItemLabel>
210
+ </SwipeableMenuSheet.ItemContent>
211
+ </SwipeableMenuSheet.Item>
212
+ </SwipeableMenuSheet.Group>
213
+ </SwipeableMenuSheet.List>
214
+ </SwipeableMenuSheet.Content>
215
+ </SwipeableMenuSheet.Root>,
216
+ );
217
+
218
+ expect(container.querySelectorAll(".seed-menu-sheet-item__divider")).toHaveLength(1);
219
+ expect(
220
+ (getByText("First item") as HTMLElement).parentElement?.parentElement?.className,
221
+ ).toContain("labelAlign_left");
222
+ expect(
223
+ (getByText("Second item") as HTMLElement).parentElement?.parentElement?.className,
224
+ ).toContain("labelAlign_center");
225
+
226
+ const item = (getByText("First item") as HTMLElement).parentElement?.parentElement;
227
+ if (!item) throw new Error("Expected menu sheet item.");
228
+ fireEvent.tap(item);
229
+
230
+ expect(onItemTap).toHaveBeenCalledOnce();
231
+ expect(sheetMocks.rootRef.close).not.toHaveBeenCalled();
232
+ });
233
+
234
+ it("maps skipAnimation to both trigger and content motion behavior", () => {
235
+ const { getByText } = render(
236
+ <SwipeableMenuSheet.Root skipAnimation>
237
+ <SwipeableMenuSheet.Trigger>
238
+ <text>Open without motion</text>
239
+ </SwipeableMenuSheet.Trigger>
240
+ <SwipeableMenuSheet.Content />
241
+ </SwipeableMenuSheet.Root>,
242
+ );
243
+
244
+ const trigger = (getByText("Open without motion") as HTMLElement).parentElement;
245
+ if (!trigger) throw new Error("Expected trigger element.");
246
+ fireEvent.tap(trigger);
247
+
248
+ expect(sheetMocks.rootRef.open).toHaveBeenCalledWith({ animate: false });
249
+ expect(sheetMocks.contentProps.at(-1)).toMatchObject({
250
+ innerStyle: {
251
+ paddingBottom: "calc(16px + 34px)",
252
+ },
253
+ snapAnimation: { type: "tween", duration: 0 },
254
+ enterAnimation: { type: "tween", duration: 0 },
255
+ exitAnimation: { type: "tween", duration: 0 },
256
+ });
257
+ });
258
+ });