@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
@@ -1,3 +1,4 @@
1
+ import { mergeProps } from "./merge-props.js";
1
2
  import { createContext, forwardRef, useContext } from "@lynx-js/react";
2
3
  import clsx from "clsx";
3
4
  //#region src/utils/create-slot-recipe-context.tsx
@@ -30,11 +31,7 @@ function createSlotRecipeContext(recipe) {
30
31
  assertNotIntrinsicComponent(Component, "withRootProvider");
31
32
  const { defaultProps } = options ?? {};
32
33
  const StyledComponent = (innerProps) => {
33
- const props = {
34
- ...defaultProps ?? {},
35
- ...useProps(),
36
- ...innerProps
37
- };
34
+ const props = mergeProps(defaultProps ?? {}, useProps() ?? {}, innerProps);
38
35
  restoreDefaultProps(props, defaultProps);
39
36
  const [variantProps, otherProps] = recipe.splitVariantProps(props);
40
37
  const classNames = recipe(variantProps);
@@ -51,11 +48,7 @@ function createSlotRecipeContext(recipe) {
51
48
  assertNotIntrinsicComponent(Component, "withProvider");
52
49
  const { defaultProps } = options ?? {};
53
50
  const StyledComponent = forwardRef((innerProps, ref) => {
54
- const props = {
55
- ...defaultProps ?? {},
56
- ...useProps(),
57
- ...innerProps
58
- };
51
+ const props = mergeProps(defaultProps ?? {}, useProps() ?? {}, innerProps);
59
52
  restoreDefaultProps(props, defaultProps);
60
53
  const [variantProps, otherProps] = recipe.splitVariantProps(props);
61
54
  const classNames = recipe(variantProps);
@@ -63,7 +56,7 @@ function createSlotRecipeContext(recipe) {
63
56
  const userClassName = props["className"];
64
57
  return <ClassNamesProvider value={classNames}>
65
58
  <PropsProvider value={variantProps}>
66
- <Component {...ref ? { ref } : {}} {...otherProps} className={clsx(slotClassName, userClassName)} />
59
+ <Component {...mergeProps(ref ? { ref } : {}, otherProps)} className={clsx(slotClassName, userClassName)} />
67
60
  </PropsProvider>
68
61
  </ClassNamesProvider>;
69
62
  });
@@ -74,15 +67,12 @@ function createSlotRecipeContext(recipe) {
74
67
  assertNotIntrinsicComponent(Component, "withContext");
75
68
  const { defaultProps } = options ?? {};
76
69
  const StyledComponent = forwardRef((innerProps, ref) => {
77
- const props = {
78
- ...defaultProps ?? {},
79
- ...innerProps
80
- };
70
+ const props = mergeProps(defaultProps ?? {}, innerProps);
81
71
  restoreDefaultProps(props, defaultProps);
82
72
  const classNames = useClassNames();
83
73
  const slotClassName = slot ? classNames[slot] : void 0;
84
74
  const userClassName = props["className"];
85
- return <Component {...ref ? { ref } : {}} {...props} className={clsx(slotClassName, userClassName)} />;
75
+ return <Component {...mergeProps(ref ? { ref } : {}, props)} className={clsx(slotClassName, userClassName)} />;
86
76
  });
87
77
  StyledComponent.displayName = Component.displayName || Component.name;
88
78
  return StyledComponent;
@@ -2,4 +2,5 @@ export * from './create-slot-recipe-context';
2
2
  export * from './get-seed-class-name';
3
3
  export * from './resolve-recipe-token';
4
4
  export * from './split-multiple-variants-props';
5
+ export * from './merge-props';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,iCAAiC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,iCAAiC,CAAC;AAChD,cAAc,eAAe,CAAC"}
@@ -0,0 +1,15 @@
1
+ type Merge<A, B> = Omit<A, keyof B> & {
2
+ [K in keyof B]: undefined extends B[K] ? Exclude<B[K], undefined> | (K extends keyof A ? A[K] : undefined) : B[K];
3
+ };
4
+ type Merged<T extends object[], Result = {}> = T extends [
5
+ infer First extends object,
6
+ ...infer Rest extends object[]
7
+ ] ? Merged<Rest, Merge<Result, First>> : Result;
8
+ /**
9
+ * Merges props without changing event threads or propagation modes.
10
+ * Same-key handlers run last-source first, matching SEED React. Return values
11
+ * and preventDefault do not cancel another handler. Ref cleanup is preserved.
12
+ */
13
+ export declare function mergeProps<T extends object[]>(...sources: T): Merged<T>;
14
+ export {};
15
+ //# sourceMappingURL=merge-props.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge-props.d.ts","sourceRoot":"","sources":["../../src/utils/merge-props.ts"],"names":[],"mappings":"AAKA,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG;KACnC,CAAC,IAAI,MAAM,CAAC,GAAG,SAAS,SAAS,CAAC,CAAC,CAAC,CAAC,GAClC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,GACjE,CAAC,CAAC,CAAC,CAAC;CACT,CAAC;AACF,KAAK,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,EAAE,MAAM,GAAG,EAAE,IAAI,CAAC,SAAS;IACvD,MAAM,KAAK,SAAS,MAAM;IAC1B,GAAG,MAAM,IAAI,SAAS,MAAM,EAAE;CAC/B,GACG,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,GAClC,MAAM,CAAC;AAKX;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAoCvE"}
@@ -0,0 +1,36 @@
1
+ import { composeEventHandlers, composeMainThreadEventHandlers } from "./compose-event-handlers.js";
2
+ import { mergeMainThreadRefs, mergeRefs } from "./merge-refs.js";
3
+ import clsx from "clsx";
4
+ //#region src/utils/merge-props.ts
5
+ var nativeEvent = /^(?:main-thread:)?(?:(?:capture|global)-)?(?:bind|catch)[a-z]/;
6
+ var callbackEvent = /^on[A-Z]/;
7
+ /**
8
+ * Merges props without changing event threads or propagation modes.
9
+ * Same-key handlers run last-source first, matching SEED React. Return values
10
+ * and preventDefault do not cancel another handler. Ref cleanup is preserved.
11
+ */
12
+ function mergeProps(...sources) {
13
+ const result = {};
14
+ const refs = [];
15
+ const mainThreadRefs = [];
16
+ for (const source of sources) for (const [key, value] of Object.entries(source)) {
17
+ if (value === void 0) continue;
18
+ const previous = result[key];
19
+ if (key === "ref" || key === "main-thread:ref") {
20
+ if (value == null) continue;
21
+ (key === "ref" ? refs : mainThreadRefs).push(value);
22
+ } else if (key === "className") result[key] = clsx(previous, value);
23
+ else if (key === "style" && typeof value === "object" && value !== null) result[key] = {
24
+ ...typeof previous === "object" ? previous : {},
25
+ ...value
26
+ };
27
+ else if (nativeEvent.test(key) || callbackEvent.test(key)) if (previous && value) result[key] = (key.startsWith("main-thread:") ? composeMainThreadEventHandlers : composeEventHandlers)(value, previous);
28
+ else result[key] = value;
29
+ else result[key] = value;
30
+ }
31
+ if (refs.length) result["ref"] = refs.length === 1 ? refs[0] : mergeRefs(...refs);
32
+ if (mainThreadRefs.length) result["main-thread:ref"] = mainThreadRefs.length === 1 ? mainThreadRefs[0] : mergeMainThreadRefs(...mainThreadRefs);
33
+ return result;
34
+ }
35
+ //#endregion
36
+ export { mergeProps };
@@ -0,0 +1,8 @@
1
+ type Cleanup = void | (() => void);
2
+ export type Ref<T> = {
3
+ current: T | null;
4
+ } | ((value: T | null) => Cleanup);
5
+ export declare function mergeRefs<T>(...refs: Ref<T>[]): Ref<T>;
6
+ export declare function mergeMainThreadRefs<T>(...refs: Ref<T>[]): Ref<T>;
7
+ export {};
8
+ //# sourceMappingURL=merge-refs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge-refs.d.ts","sourceRoot":"","sources":["../../src/utils/merge-refs.ts"],"names":[],"mappings":"AAAA,KAAK,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC;AACnC,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI;IAAE,OAAO,EAAE,CAAC,GAAG,IAAI,CAAA;CAAE,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,KAAK,OAAO,CAAC,CAAC;AAa5E,wBAAgB,SAAS,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAWtD;AAED,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAgBhE"}
@@ -0,0 +1,38 @@
1
+ //#region src/utils/merge-refs.ts
2
+ function setRef(ref, value) {
3
+ if (typeof ref === "function") return ref(value);
4
+ ref.current = value;
5
+ }
6
+ function setMainThreadRef(ref, value) {
7
+ "main thread";
8
+ if (typeof ref === "function") return ref(value);
9
+ ref.current = value;
10
+ }
11
+ function mergeRefs(...refs) {
12
+ return (value) => {
13
+ const cleanups = refs.map((ref) => setRef(ref, value));
14
+ return () => {
15
+ refs.forEach((ref, index) => {
16
+ const cleanup = cleanups[index];
17
+ if (cleanup) cleanup();
18
+ else setRef(ref, null);
19
+ });
20
+ };
21
+ };
22
+ }
23
+ function mergeMainThreadRefs(...refs) {
24
+ return (value) => {
25
+ "main thread";
26
+ const cleanups = [];
27
+ for (let index = 0; index < refs.length; index++) cleanups.push(setMainThreadRef(refs[index], value));
28
+ return () => {
29
+ for (let index = 0; index < refs.length; index++) {
30
+ const cleanup = cleanups[index];
31
+ if (cleanup) cleanup();
32
+ else setMainThreadRef(refs[index], null);
33
+ }
34
+ };
35
+ };
36
+ }
37
+ //#endregion
38
+ export { mergeMainThreadRefs, mergeRefs };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seed-design/lynx-react",
3
- "version": "0.6.3",
3
+ "version": "0.7.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/daangn/seed-design.git",
@@ -33,13 +33,13 @@
33
33
  },
34
34
  "peerDependencies": {
35
35
  "@lynx-js/react": ">=0.117.0",
36
- "@lynx-js/types": ">=3.7.0",
37
- "@seed-design/lynx-css": "0.0.0 || >=0.10.0 <1.0.0"
36
+ "@lynx-js/types": ">=3.9.0",
37
+ "@seed-design/lynx-css": "0.0.0 || >=0.11.0 <1.0.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@lynx-js/react": "^0.117.0",
41
- "@lynx-js/types": "^3.7.0",
42
- "@seed-design/lynx-css": "0.10.2",
41
+ "@lynx-js/types": "^3.9.0",
42
+ "@seed-design/lynx-css": "0.11.0",
43
43
  "@testing-library/jest-dom": "^6.9.1",
44
44
  "jsdom": "^29.0.2",
45
45
  "preact": "npm:@lynx-js/internal-preact@10.28.4-ee7bb26",
@@ -51,6 +51,7 @@
51
51
  "access": "public"
52
52
  },
53
53
  "dependencies": {
54
+ "@floating-ui/core": "^1.8.0",
54
55
  "@lynx-js/lynx-ui-common": "^3.130.0",
55
56
  "@lynx-js/lynx-ui-sheet": "^3.130.1",
56
57
  "clsx": "^2.1.1",
@@ -6,6 +6,7 @@ import { accordion, type AccordionVariantProps } from "@seed-design/lynx-css/rec
6
6
 
7
7
  import { useControllableState } from "../../hooks/useControllableState";
8
8
  import { usePressTap } from "../../hooks/usePressTap";
9
+ import { useScaleFeedback } from "../../hooks/useScaleFeedback";
9
10
  import type {
10
11
  LynxAccessibilityProps,
11
12
  LynxIconElementProps,
@@ -18,6 +19,7 @@ import type {
18
19
  import { toArray } from "../../utils/children";
19
20
  import { createSlotRecipeContext } from "../../utils/create-slot-recipe-context";
20
21
  import { InternalIcon } from "../Icon/Icon";
22
+ import { mergeProps } from "../../utils/merge-props";
21
23
 
22
24
  /**
23
25
  * @platform Lynx
@@ -126,9 +128,8 @@ export const AccordionRoot = React.forwardRef<unknown, AccordionRootProps>((prop
126
128
  return (
127
129
  <AccordionContext.Provider value={contextValue}>
128
130
  <view
129
- {...(ref ? { ref: ref as LynxViewRef } : {})}
131
+ {...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
130
132
  className={clsx(classes.root, className)}
131
- {...nativeProps}
132
133
  >
133
134
  {items.map((item, index) => (
134
135
  <AccordionItemPositionContext.Provider
@@ -173,9 +174,8 @@ export const AccordionItem = React.forwardRef<unknown, AccordionItemProps>((prop
173
174
  <AccordionItemContext.Provider value={contextValue}>
174
175
  <ClassNamesProvider value={classes}>
175
176
  <view
176
- {...(ref ? { ref: ref as LynxViewRef } : {})}
177
+ {...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
177
178
  className={clsx(classes.item, className)}
178
- {...nativeProps}
179
179
  >
180
180
  {children}
181
181
  {!isLast ? (
@@ -203,10 +203,9 @@ export const AccordionHeader = React.forwardRef<unknown, AccordionHeaderProps>((
203
203
 
204
204
  return (
205
205
  <view
206
- {...(ref ? { ref: ref as LynxViewRef } : {})}
206
+ {...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
207
207
  className={clsx(classes.header, className)}
208
208
  accessibility-heading={accessibilityHeading}
209
- {...nativeProps}
210
209
  >
211
210
  {children}
212
211
  </view>
@@ -245,10 +244,16 @@ export const AccordionTrigger = React.forwardRef<unknown, AccordionTriggerProps>
245
244
  },
246
245
  [bindtap, context],
247
246
  );
248
- const { pressed, ...pressHandlers } = usePressTap({
247
+ const { pressed, bindtouchstart, bindtouchend, bindtouchcancel, ...pressHandlers } = usePressTap({
249
248
  disabled: context.disabled,
250
249
  onTap: handleTap,
251
250
  });
251
+ const { scaleFeedbackTriggerProps, scaleFeedbackTargetProps } = useScaleFeedback({
252
+ disabled: context.disabled,
253
+ onTouchStart: bindtouchstart,
254
+ onTouchEnd: bindtouchend,
255
+ onTouchCancel: bindtouchcancel,
256
+ });
252
257
  const classes = accordion({
253
258
  ...context.variantProps,
254
259
  open: context.open,
@@ -259,7 +264,12 @@ export const AccordionTrigger = React.forwardRef<unknown, AccordionTriggerProps>
259
264
  return (
260
265
  <ClassNamesProvider value={classes}>
261
266
  <view
262
- {...(ref ? { ref: ref as LynxViewRef } : {})}
267
+ {...mergeProps(
268
+ ref ? { ref: ref as LynxViewRef } : {},
269
+ pressHandlers,
270
+ scaleFeedbackTriggerProps,
271
+ nativeProps,
272
+ )}
263
273
  className={clsx(classes.trigger, className)}
264
274
  accessibility-element={accessibilityElement}
265
275
  accessibility-role-description={accessibilityRoleDescription}
@@ -268,11 +278,11 @@ export const AccordionTrigger = React.forwardRef<unknown, AccordionTriggerProps>
268
278
  accessibilityValue ??
269
279
  (context.open ? expandedAccessibilityValue : collapsedAccessibilityValue)
270
280
  }
271
- {...pressHandlers}
272
- {...nativeProps}
273
281
  >
274
282
  <view className={classes.pressedOverlay} accessibility-elements-hidden={true} />
275
- {children}
283
+ <view className={classes.triggerContent} {...scaleFeedbackTargetProps}>
284
+ {children}
285
+ </view>
276
286
  </view>
277
287
  </ClassNamesProvider>
278
288
  );
@@ -311,11 +321,10 @@ export const AccordionContent = React.forwardRef<unknown, AccordionContentProps>
311
321
 
312
322
  return (
313
323
  <view
314
- {...(ref ? { ref: ref as LynxViewRef } : {})}
324
+ {...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
315
325
  className={clsx(classes.content, className)}
316
326
  style={{ ...style, height: context.open ? `${contentHeight}px` : "0px" }}
317
327
  accessibility-elements-hidden={!context.open || accessibilityElementsHidden}
318
- {...nativeProps}
319
328
  >
320
329
  <view className={classes.contentInner} bindlayoutchange={handleContentLayoutChange}>
321
330
  {children}
@@ -335,9 +344,8 @@ export const AccordionBody = React.forwardRef<unknown, AccordionBodyProps>((prop
335
344
 
336
345
  return (
337
346
  <view
338
- {...(ref ? { ref: ref as LynxViewRef } : {})}
347
+ {...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
339
348
  className={clsx(classes.body, className)}
340
- {...nativeProps}
341
349
  >
342
350
  {children}
343
351
  </view>
@@ -355,9 +363,8 @@ export const AccordionTitle = React.forwardRef<unknown, AccordionTitleProps>((pr
355
363
 
356
364
  return (
357
365
  <text
358
- {...(ref ? { ref: ref as LynxTextRef } : {})}
366
+ {...mergeProps(ref ? { ref: ref as LynxTextRef } : {}, nativeProps)}
359
367
  className={clsx(classes.title, className)}
360
- {...nativeProps}
361
368
  >
362
369
  {children}
363
370
  </text>
@@ -376,9 +383,8 @@ export const AccordionDescription = React.forwardRef<unknown, AccordionDescripti
376
383
 
377
384
  return (
378
385
  <text
379
- {...(ref ? { ref: ref as LynxTextRef } : {})}
386
+ {...mergeProps(ref ? { ref: ref as LynxTextRef } : {}, nativeProps)}
380
387
  className={clsx(classes.description, className)}
381
- {...nativeProps}
382
388
  >
383
389
  {children}
384
390
  </text>
@@ -397,9 +403,8 @@ export const AccordionPrefix = React.forwardRef<unknown, AccordionPrefixProps>((
397
403
 
398
404
  return (
399
405
  <view
400
- {...(ref ? { ref: ref as LynxViewRef } : {})}
406
+ {...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
401
407
  className={clsx(classes.prefix, className)}
402
- {...nativeProps}
403
408
  >
404
409
  {children}
405
410
  </view>
@@ -423,9 +428,11 @@ export const AccordionSuffixIcon = React.forwardRef<unknown, AccordionSuffixIcon
423
428
  if (icon) {
424
429
  return (
425
430
  <view
426
- {...(ref ? { ref: ref as LynxViewRef } : {})}
427
- accessibility-elements-hidden={true}
428
- {...nativeProps}
431
+ {...mergeProps(
432
+ { "accessibility-elements-hidden": true },
433
+ ref ? { ref: ref as LynxViewRef } : {},
434
+ nativeProps,
435
+ )}
429
436
  >
430
437
  <InternalIcon
431
438
  icon={icon}
@@ -439,11 +446,13 @@ export const AccordionSuffixIcon = React.forwardRef<unknown, AccordionSuffixIcon
439
446
 
440
447
  return (
441
448
  <view
442
- {...(ref ? { ref: ref as LynxViewRef } : {})}
449
+ {...mergeProps(
450
+ { "accessibility-elements-hidden": true },
451
+ ref ? { ref: ref as LynxViewRef } : {},
452
+ nativeProps,
453
+ )}
443
454
  className={mergedClassName}
444
455
  style={style}
445
- accessibility-elements-hidden={true}
446
- {...nativeProps}
447
456
  >
448
457
  {children}
449
458
  </view>
@@ -7,6 +7,7 @@ import * as React from "@lynx-js/react";
7
7
  import { isValidElement, useMemo } from "@lynx-js/react";
8
8
 
9
9
  import { usePressTap } from "../../hooks/usePressTap";
10
+ import { useScaleFeedback } from "../../hooks/useScaleFeedback";
10
11
  import type {
11
12
  LynxElementProps,
12
13
  LynxPressableProps,
@@ -36,6 +37,7 @@ import {
36
37
  type PrefixIconProps,
37
38
  type SuffixIconProps,
38
39
  } from "../Icon/Icon";
40
+ import { mergeProps } from "../../utils/merge-props";
39
41
 
40
42
  // Root/TextSlot 은 `withProvider("view", ...)` / `withContext("text", ...)` 를 쓰지 않는다.
41
43
  // intrinsic string 인자는 `React.createElement("view", ...)` 로 컴파일되어 Lynx 컴파일러의
@@ -63,7 +65,9 @@ interface ActionButtonRootOwnProps
63
65
  LynxTouchProps,
64
66
  ActionButtonAccessibilityProps {}
65
67
 
66
- interface ActionButtonRootProps extends ActionButtonVariantProps, ActionButtonRootOwnProps {}
68
+ interface ActionButtonRootProps extends ActionButtonVariantProps, ActionButtonRootOwnProps {
69
+ flatten?: false;
70
+ }
67
71
 
68
72
  function resolveProgressCircleSize(
69
73
  actionButtonSize: ActionButtonVariantProps["size"],
@@ -131,8 +135,7 @@ const ActionButtonRoot = React.forwardRef<unknown, ActionButtonRootProps>((inner
131
135
  <PropsProvider value={propsForContext}>
132
136
  <IconSlotProvider value={iconSlotContextValue}>
133
137
  <view
134
- {...(ref ? { ref: ref as LynxViewRef } : {})}
135
- {...rest}
138
+ {...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, rest)}
136
139
  className={clsx(classNames.root, userClassName)}
137
140
  >
138
141
  {children as React.ReactNode}
@@ -153,8 +156,7 @@ const ActionButtonTextSlot = React.forwardRef<unknown, ActionButtonTextSlotProps
153
156
  const classNames = useClassNames();
154
157
  return (
155
158
  <text
156
- {...(ref ? { ref: ref as LynxTextRef } : {})}
157
- {...rest}
159
+ {...mergeProps(ref ? { ref: ref as LynxTextRef } : {}, rest)}
158
160
  className={clsx(classNames.text, userClassName)}
159
161
  >
160
162
  {children}
@@ -276,7 +278,8 @@ function ActionButtonLoadingIndicator({ size }: { size: ActionButtonVariantProps
276
278
  export interface ActionButtonProps
277
279
  extends Omit<ActionButtonVariantProps, "pressed">,
278
280
  Pick<StyleProps, "flexGrow">,
279
- LynxElementProps,
281
+ // Keep the scale target's Android View even if shared props later expose flatten.
282
+ Omit<LynxElementProps, "flatten">,
280
283
  LynxPressableProps,
281
284
  ActionButtonAccessibilityProps {
282
285
  icon?: IconProps["icon"];
@@ -315,24 +318,36 @@ export const ActionButton = React.forwardRef<unknown, ActionButtonProps>((props,
315
318
  );
316
319
  }
317
320
 
318
- const { pressed, ...pressTapHandlers } = usePressTap({
321
+ const { pressed, bindtouchstart, bindtouchend, bindtouchcancel, ...pressTapHandlers } =
322
+ usePressTap({
323
+ disabled: !isInteractive,
324
+ onTap: bindtap,
325
+ mainThreadOnTap: mainThreadBindtap,
326
+ });
327
+ const { scaleFeedbackTriggerProps, scaleFeedbackTargetProps } = useScaleFeedback({
319
328
  disabled: !isInteractive,
320
- onTap: bindtap,
321
- mainThreadOnTap: mainThreadBindtap,
329
+ onTouchStart: bindtouchstart,
330
+ onTouchEnd: bindtouchend,
331
+ onTouchCancel: bindtouchcancel,
322
332
  });
323
333
 
324
334
  return (
325
335
  <IconRequired enabled={isIconOnly}>
326
336
  <ActionButtonRoot
327
- {...variantAndRest}
337
+ {...mergeProps(
338
+ { ref },
339
+ scaleFeedbackTargetProps,
340
+ scaleFeedbackTriggerProps,
341
+ pressTapHandlers,
342
+ variantAndRest,
343
+ )}
328
344
  layout={layout}
329
345
  pressed={pressed}
330
- ref={ref}
331
346
  style={flexGrow != null ? { flexGrow: resolveFlexValue(flexGrow) } : undefined}
332
347
  accessibility-element={accessibilityElement}
333
348
  accessibility-label={accessibilityLabel}
334
349
  accessibility-traits={accessibilityTraits}
335
- {...pressTapHandlers}
350
+ flatten={false}
336
351
  >
337
352
  {loading ? (
338
353
  <>
@@ -19,6 +19,7 @@ import { createSlotRecipeContext } from "../../utils/create-slot-recipe-context"
19
19
  import { Icon } from "../Icon";
20
20
  import { AppBarProvider, useAppBarContext } from "./context";
21
21
  import { getLayoutWidth, getMainLayoutStyle, useAppBar } from "./useAppBar";
22
+ import { mergeProps } from "../../utils/merge-props";
22
23
 
23
24
  type AppBarClassNames = ReturnType<typeof appBar>;
24
25
  type AppBarMainClassNames = ReturnType<typeof appBarMain>;
@@ -61,8 +62,7 @@ export const AppBarRoot = React.forwardRef<unknown, AppBarRootProps>((props, ref
61
62
  <AppBarProvider value={contextValue}>
62
63
  <AppBarClassNamesProvider value={classNames}>
63
64
  <view
64
- {...(ref ? { ref: ref as LynxViewRef } : {})}
65
- {...nativeProps}
65
+ {...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
66
66
  className={clsx(classNames.root, className)}
67
67
  style={
68
68
  {
@@ -106,9 +106,11 @@ export const AppBarLeft = React.forwardRef<unknown, AppBarLeftProps>((props, ref
106
106
 
107
107
  return (
108
108
  <view
109
- {...(ref ? { ref: ref as LynxViewRef } : {})}
110
- {...nativeProps}
111
- bindlayoutchange={handleLayoutChange}
109
+ {...mergeProps(
110
+ { bindlayoutchange: handleLayoutChange },
111
+ ref ? { ref: ref as LynxViewRef } : {},
112
+ nativeProps,
113
+ )}
112
114
  className={clsx(classNames.left, className)}
113
115
  >
114
116
  {children}
@@ -139,9 +141,11 @@ export const AppBarRight = React.forwardRef<unknown, AppBarRightProps>((props, r
139
141
 
140
142
  return (
141
143
  <view
142
- {...(ref ? { ref: ref as LynxViewRef } : {})}
143
- {...nativeProps}
144
- bindlayoutchange={handleLayoutChange}
144
+ {...mergeProps(
145
+ { bindlayoutchange: handleLayoutChange },
146
+ ref ? { ref: ref as LynxViewRef } : {},
147
+ nativeProps,
148
+ )}
145
149
  className={clsx(classNames.right, className)}
146
150
  >
147
151
  {children}
@@ -175,8 +179,7 @@ export const AppBarMain = React.forwardRef<unknown, AppBarMainProps>((props, ref
175
179
  return (
176
180
  <AppBarMainClassNamesProvider value={classNames}>
177
181
  <view
178
- {...(ref ? { ref: ref as LynxViewRef } : {})}
179
- {...nativeProps}
182
+ {...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
180
183
  className={clsx(classNames.root, className)}
181
184
  style={
182
185
  {
@@ -201,8 +204,7 @@ export const AppBarTitle = React.forwardRef<unknown, AppBarTitleProps>((props, r
201
204
 
202
205
  return (
203
206
  <text
204
- {...(ref ? { ref: ref as LynxTextRef } : {})}
205
- {...nativeProps}
207
+ {...mergeProps(ref ? { ref: ref as LynxTextRef } : {}, nativeProps)}
206
208
  className={clsx(classNames.title, className)}
207
209
  >
208
210
  {children}
@@ -219,8 +221,7 @@ export const AppBarSubtitle = React.forwardRef<unknown, AppBarSubtitleProps>((pr
219
221
 
220
222
  return (
221
223
  <text
222
- {...(ref ? { ref: ref as LynxTextRef } : {})}
223
- {...nativeProps}
224
+ {...mergeProps(ref ? { ref: ref as LynxTextRef } : {}, nativeProps)}
224
225
  className={clsx(classNames.subtitle, className)}
225
226
  >
226
227
  {children}
@@ -256,8 +257,7 @@ export const AppBarIconButton = React.forwardRef<unknown, AppBarIconButtonProps>
256
257
 
257
258
  return (
258
259
  <view
259
- {...(ref ? { ref: ref as LynxViewRef } : {})}
260
- {...nativeProps}
260
+ {...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
261
261
  accessibility-element={accessibilityElement}
262
262
  accessibility-label={accessibilityLabel}
263
263
  accessibility-traits={accessibilityTraits}
@@ -277,8 +277,7 @@ export const AppBarSlot = React.forwardRef<unknown, AppBarSlotProps>((props, ref
277
277
 
278
278
  return (
279
279
  <view
280
- {...(ref ? { ref: ref as LynxViewRef } : {})}
281
- {...nativeProps}
280
+ {...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
282
281
  className={clsx(classNames.custom, className)}
283
282
  >
284
283
  {children}
@@ -3,6 +3,7 @@ import clsx from "clsx";
3
3
  import * as React from "@lynx-js/react";
4
4
 
5
5
  import type { LynxStyledElementProps, LynxViewRef } from "../../types";
6
+ import { mergeProps } from "../../utils/merge-props";
6
7
 
7
8
  /**
8
9
  * @platform Lynx
@@ -20,8 +21,7 @@ export const Badge = React.forwardRef<unknown, BadgeProps>((props, ref) => {
20
21
 
21
22
  return (
22
23
  <view
23
- {...(ref ? { ref: ref as LynxViewRef } : {})}
24
- {...nativeProps}
24
+ {...mergeProps(ref ? { ref: ref as LynxViewRef } : {}, nativeProps)}
25
25
  className={clsx(classes.root, className)}
26
26
  >
27
27
  <text className={classes.label}>{children}</text>