@seed-design/lynx-react 0.7.1 → 0.8.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 (241) hide show
  1. package/lib/components/Accordion/Accordion.jsx +2 -2
  2. package/lib/components/ActionButton/ActionButton.jsx +1 -1
  3. package/lib/components/AlertDialog/AlertDialog.d.ts +64 -0
  4. package/lib/components/AlertDialog/AlertDialog.d.ts.map +1 -0
  5. package/lib/components/AlertDialog/AlertDialog.jsx +138 -0
  6. package/lib/components/AlertDialog/AlertDialog.namespace.d.ts +2 -0
  7. package/lib/components/AlertDialog/AlertDialog.namespace.d.ts.map +1 -0
  8. package/lib/components/AlertDialog/AlertDialog.namespace.js +17 -0
  9. package/lib/components/AlertDialog/index.d.ts +3 -0
  10. package/lib/components/AlertDialog/index.d.ts.map +1 -0
  11. package/lib/components/AppBar/AppBar.d.ts +14 -1
  12. package/lib/components/AppBar/AppBar.d.ts.map +1 -1
  13. package/lib/components/AppBar/AppBar.jsx +39 -8
  14. package/lib/components/AppBar/AppBar.namespace.d.ts +1 -1
  15. package/lib/components/AppBar/AppBar.namespace.d.ts.map +1 -1
  16. package/lib/components/AppBar/index.d.ts +1 -1
  17. package/lib/components/AppBar/index.d.ts.map +1 -1
  18. package/lib/components/AttachmentDisplay/AttachmentDisplay.d.ts +182 -0
  19. package/lib/components/AttachmentDisplay/AttachmentDisplay.d.ts.map +1 -0
  20. package/lib/components/AttachmentDisplay/AttachmentDisplay.jsx +444 -0
  21. package/lib/components/AttachmentDisplay/index.d.ts +2 -0
  22. package/lib/components/AttachmentDisplay/index.d.ts.map +1 -0
  23. package/lib/components/AttachmentInput/AttachmentInput.d.ts +179 -0
  24. package/lib/components/AttachmentInput/AttachmentInput.d.ts.map +1 -0
  25. package/lib/components/AttachmentInput/AttachmentInput.jsx +520 -0
  26. package/lib/components/AttachmentInput/index.d.ts +2 -0
  27. package/lib/components/AttachmentInput/index.d.ts.map +1 -0
  28. package/lib/components/BottomSheet/BottomSheet.d.ts +1 -1
  29. package/lib/components/BottomSheet/BottomSheet.d.ts.map +1 -1
  30. package/lib/components/BottomSheet/BottomSheet.jsx +1 -7
  31. package/lib/components/Callout/Callout.jsx +2 -2
  32. package/lib/components/Checkbox/Checkbox.jsx +2 -2
  33. package/lib/components/Chip/Chip.jsx +2 -2
  34. package/lib/components/ChipTabs/ChipTabs.d.ts +41 -0
  35. package/lib/components/ChipTabs/ChipTabs.d.ts.map +1 -0
  36. package/lib/components/ChipTabs/ChipTabs.jsx +39 -0
  37. package/lib/components/ChipTabs/ChipTabs.namespace.d.ts +2 -0
  38. package/lib/components/ChipTabs/ChipTabs.namespace.d.ts.map +1 -0
  39. package/lib/components/ChipTabs/ChipTabs.namespace.js +13 -0
  40. package/lib/components/ChipTabs/index.d.ts +3 -0
  41. package/lib/components/ChipTabs/index.d.ts.map +1 -0
  42. package/lib/components/ContextualFloatingButton/ContextualFloatingButton.d.ts +18 -0
  43. package/lib/components/ContextualFloatingButton/ContextualFloatingButton.d.ts.map +1 -0
  44. package/lib/components/ContextualFloatingButton/ContextualFloatingButton.jsx +113 -0
  45. package/lib/components/ContextualFloatingButton/index.d.ts +2 -0
  46. package/lib/components/ContextualFloatingButton/index.d.ts.map +1 -0
  47. package/lib/components/Dialog/Dialog.d.ts +87 -0
  48. package/lib/components/Dialog/Dialog.d.ts.map +1 -0
  49. package/lib/components/Dialog/Dialog.jsx +147 -0
  50. package/lib/components/Dialog/Dialog.namespace.d.ts +2 -0
  51. package/lib/components/Dialog/Dialog.namespace.d.ts.map +1 -0
  52. package/lib/components/Dialog/Dialog.namespace.js +18 -0
  53. package/lib/components/Dialog/index.d.ts +3 -0
  54. package/lib/components/Dialog/index.d.ts.map +1 -0
  55. package/lib/components/FloatingActionButton/FloatingActionButton.d.ts +23 -0
  56. package/lib/components/FloatingActionButton/FloatingActionButton.d.ts.map +1 -0
  57. package/lib/components/FloatingActionButton/FloatingActionButton.jsx +76 -0
  58. package/lib/components/FloatingActionButton/FloatingActionButton.namespace.d.ts +2 -0
  59. package/lib/components/FloatingActionButton/FloatingActionButton.namespace.d.ts.map +1 -0
  60. package/lib/components/FloatingActionButton/FloatingActionButton.namespace.js +10 -0
  61. package/lib/components/FloatingActionButton/index.d.ts +3 -0
  62. package/lib/components/FloatingActionButton/index.d.ts.map +1 -0
  63. package/lib/components/HelpBubble/HelpBubble.d.ts +67 -0
  64. package/lib/components/HelpBubble/HelpBubble.d.ts.map +1 -0
  65. package/lib/components/HelpBubble/HelpBubble.jsx +600 -0
  66. package/lib/components/HelpBubble/HelpBubble.namespace.d.ts +2 -0
  67. package/lib/components/HelpBubble/HelpBubble.namespace.d.ts.map +1 -0
  68. package/lib/components/HelpBubble/HelpBubble.namespace.js +18 -0
  69. package/lib/components/HelpBubble/index.d.ts +3 -0
  70. package/lib/components/HelpBubble/index.d.ts.map +1 -0
  71. package/lib/components/Icon/Icon.d.ts +1 -0
  72. package/lib/components/Icon/Icon.d.ts.map +1 -1
  73. package/lib/components/Icon/Icon.jsx +2 -1
  74. package/lib/components/IdentityPlaceholder/IdentityPlaceholder.d.ts +28 -0
  75. package/lib/components/IdentityPlaceholder/IdentityPlaceholder.d.ts.map +1 -0
  76. package/lib/components/IdentityPlaceholder/IdentityPlaceholder.jsx +37 -0
  77. package/lib/components/IdentityPlaceholder/IdentityPlaceholder.namespace.d.ts +2 -0
  78. package/lib/components/IdentityPlaceholder/IdentityPlaceholder.namespace.d.ts.map +1 -0
  79. package/lib/components/IdentityPlaceholder/IdentityPlaceholder.namespace.js +9 -0
  80. package/lib/components/IdentityPlaceholder/identity-placeholder-business.js +4 -0
  81. package/lib/components/IdentityPlaceholder/identity-placeholder-person.js +4 -0
  82. package/lib/components/IdentityPlaceholder/index.d.ts +3 -0
  83. package/lib/components/IdentityPlaceholder/index.d.ts.map +1 -0
  84. package/lib/components/InputButton/InputButton.d.ts +2 -0
  85. package/lib/components/InputButton/InputButton.d.ts.map +1 -1
  86. package/lib/components/InputButton/InputButton.jsx +40 -8
  87. package/lib/components/List/List.d.ts +1 -1
  88. package/lib/components/List/List.d.ts.map +1 -1
  89. package/lib/components/List/List.jsx +26 -12
  90. package/lib/components/Menu/Menu.d.ts.map +1 -1
  91. package/lib/components/Menu/Menu.jsx +15 -5
  92. package/lib/components/PageBanner/PageBanner.d.ts +3 -0
  93. package/lib/components/PageBanner/PageBanner.d.ts.map +1 -1
  94. package/lib/components/PageBanner/PageBanner.jsx +49 -11
  95. package/lib/components/QuantityPicker/QuantityPicker.d.ts +53 -0
  96. package/lib/components/QuantityPicker/QuantityPicker.d.ts.map +1 -0
  97. package/lib/components/QuantityPicker/QuantityPicker.jsx +282 -0
  98. package/lib/components/QuantityPicker/QuantityPicker.namespace.d.ts +2 -0
  99. package/lib/components/QuantityPicker/QuantityPicker.namespace.d.ts.map +1 -0
  100. package/lib/components/QuantityPicker/QuantityPicker.namespace.js +11 -0
  101. package/lib/components/QuantityPicker/index.d.ts +3 -0
  102. package/lib/components/QuantityPicker/index.d.ts.map +1 -0
  103. package/lib/components/RadioGroup/RadioGroup.jsx +2 -2
  104. package/lib/components/ReactionButton/ReactionButton.d.ts +1 -1
  105. package/lib/components/ReactionButton/ReactionButton.d.ts.map +1 -1
  106. package/lib/components/ReactionButton/ReactionButton.jsx +22 -13
  107. package/lib/components/ScrollFog/ScrollFog.d.ts +41 -0
  108. package/lib/components/ScrollFog/ScrollFog.d.ts.map +1 -0
  109. package/lib/components/ScrollFog/ScrollFog.jsx +65 -0
  110. package/lib/components/ScrollFog/index.d.ts +2 -0
  111. package/lib/components/ScrollFog/index.d.ts.map +1 -0
  112. package/lib/components/SegmentedControl/SegmentedControl.jsx +2 -2
  113. package/lib/components/Select/Select.d.ts +112 -0
  114. package/lib/components/Select/Select.d.ts.map +1 -0
  115. package/lib/components/Select/Select.jsx +885 -0
  116. package/lib/components/Select/Select.namespace.d.ts +2 -0
  117. package/lib/components/Select/Select.namespace.d.ts.map +1 -0
  118. package/lib/components/Select/Select.namespace.js +23 -0
  119. package/lib/components/Select/index.d.ts +3 -0
  120. package/lib/components/Select/index.d.ts.map +1 -0
  121. package/lib/components/Skeleton/Skeleton.d.ts +15 -0
  122. package/lib/components/Skeleton/Skeleton.d.ts.map +1 -0
  123. package/lib/components/Skeleton/Skeleton.jsx +18 -0
  124. package/lib/components/Skeleton/index.d.ts +2 -0
  125. package/lib/components/Skeleton/index.d.ts.map +1 -0
  126. package/lib/components/Slider/Slider.d.ts +101 -0
  127. package/lib/components/Slider/Slider.d.ts.map +1 -0
  128. package/lib/components/Slider/Slider.jsx +573 -0
  129. package/lib/components/Slider/Slider.namespace.d.ts +2 -0
  130. package/lib/components/Slider/Slider.namespace.d.ts.map +1 -0
  131. package/lib/components/Slider/Slider.namespace.js +19 -0
  132. package/lib/components/Slider/Slider.utils.d.ts +19 -0
  133. package/lib/components/Slider/Slider.utils.d.ts.map +1 -0
  134. package/lib/components/Slider/Slider.utils.js +106 -0
  135. package/lib/components/Slider/index.d.ts +3 -0
  136. package/lib/components/Slider/index.d.ts.map +1 -0
  137. package/lib/components/SwipeableMenuSheet/SwipeableMenuSheet.d.ts.map +1 -1
  138. package/lib/components/SwipeableMenuSheet/SwipeableMenuSheet.jsx +22 -8
  139. package/lib/components/Switch/Switch.d.ts.map +1 -1
  140. package/lib/components/Switch/Switch.jsx +5 -3
  141. package/lib/components/Tabs/Tabs.d.ts +34 -2
  142. package/lib/components/Tabs/Tabs.d.ts.map +1 -1
  143. package/lib/components/Tabs/Tabs.jsx +186 -56
  144. package/lib/components/Tabs/Tabs.utils.d.ts +14 -1
  145. package/lib/components/Tabs/Tabs.utils.d.ts.map +1 -1
  146. package/lib/components/Tabs/Tabs.utils.js +24 -3
  147. package/lib/components/Tabs/index.d.ts +1 -1
  148. package/lib/components/Tabs/index.d.ts.map +1 -1
  149. package/lib/components/index.d.ts +14 -0
  150. package/lib/components/index.d.ts.map +1 -1
  151. package/lib/hooks/useControllableState.d.ts +1 -14
  152. package/lib/hooks/useControllableState.d.ts.map +1 -1
  153. package/lib/hooks/usePressTap.d.ts +1 -27
  154. package/lib/hooks/usePressTap.d.ts.map +1 -1
  155. package/lib/index.js +29 -6
  156. package/lib/{hooks/useControllableState.js → packages/lynx-react-headless/use-controllable-state/lib/index.js} +2 -3
  157. package/lib/{hooks/usePressTap.js → packages/lynx-react-headless/use-press-tap/lib/index.js} +13 -10
  158. package/lib/types.d.ts +1 -0
  159. package/lib/types.d.ts.map +1 -1
  160. package/package.json +9 -5
  161. package/src/components/AlertDialog/AlertDialog.namespace.ts +22 -0
  162. package/src/components/AlertDialog/AlertDialog.test.tsx +226 -0
  163. package/src/components/AlertDialog/AlertDialog.tsx +374 -0
  164. package/src/components/AlertDialog/index.ts +24 -0
  165. package/src/components/AppBar/AppBar.namespace.ts +1 -0
  166. package/src/components/AppBar/AppBar.test.tsx +231 -0
  167. package/src/components/AppBar/AppBar.tsx +105 -13
  168. package/src/components/AppBar/index.ts +1 -0
  169. package/src/components/AttachmentDisplay/AttachmentDisplay.tsx +886 -0
  170. package/src/components/AttachmentDisplay/index.ts +48 -0
  171. package/src/components/AttachmentInput/AttachmentInput.tsx +1001 -0
  172. package/src/components/AttachmentInput/index.ts +49 -0
  173. package/src/components/BottomSheet/BottomSheet.test.tsx +22 -7
  174. package/src/components/BottomSheet/BottomSheet.tsx +1 -19
  175. package/src/components/ChipTabs/ChipTabs.namespace.ts +14 -0
  176. package/src/components/ChipTabs/ChipTabs.tsx +119 -0
  177. package/src/components/ChipTabs/index.ts +16 -0
  178. package/src/components/ContextualFloatingButton/ContextualFloatingButton.test.tsx +63 -0
  179. package/src/components/ContextualFloatingButton/ContextualFloatingButton.tsx +232 -0
  180. package/src/components/ContextualFloatingButton/index.ts +4 -0
  181. package/src/components/Dialog/Dialog.namespace.ts +24 -0
  182. package/src/components/Dialog/Dialog.test.tsx +172 -0
  183. package/src/components/Dialog/Dialog.tsx +373 -0
  184. package/src/components/Dialog/index.ts +26 -0
  185. package/src/components/FloatingActionButton/FloatingActionButton.namespace.ts +8 -0
  186. package/src/components/FloatingActionButton/FloatingActionButton.test.tsx +59 -0
  187. package/src/components/FloatingActionButton/FloatingActionButton.tsx +207 -0
  188. package/src/components/FloatingActionButton/index.ts +10 -0
  189. package/src/components/HelpBubble/HelpBubble.namespace.ts +24 -0
  190. package/src/components/HelpBubble/HelpBubble.tsx +998 -0
  191. package/src/components/HelpBubble/index.ts +26 -0
  192. package/src/components/Icon/Icon.test.tsx +0 -3
  193. package/src/components/Icon/Icon.tsx +11 -1
  194. package/src/components/IdentityPlaceholder/IdentityPlaceholder.namespace.ts +6 -0
  195. package/src/components/IdentityPlaceholder/IdentityPlaceholder.tsx +103 -0
  196. package/src/components/IdentityPlaceholder/assets.d.ts +4 -0
  197. package/src/components/IdentityPlaceholder/identity-placeholder-business.webp +0 -0
  198. package/src/components/IdentityPlaceholder/identity-placeholder-person.webp +0 -0
  199. package/src/components/IdentityPlaceholder/index.ts +8 -0
  200. package/src/components/InputButton/InputButton.test.tsx +128 -1
  201. package/src/components/InputButton/InputButton.tsx +60 -9
  202. package/src/components/List/List.test.tsx +54 -2
  203. package/src/components/List/List.tsx +43 -10
  204. package/src/components/Menu/Menu.tsx +14 -4
  205. package/src/components/Menu/__tests__/Menu.test.tsx +34 -0
  206. package/src/components/PageBanner/PageBanner.test.tsx +110 -3
  207. package/src/components/PageBanner/PageBanner.tsx +83 -19
  208. package/src/components/QuantityPicker/QuantityPicker.namespace.ts +10 -0
  209. package/src/components/QuantityPicker/QuantityPicker.test.tsx +235 -0
  210. package/src/components/QuantityPicker/QuantityPicker.tsx +605 -0
  211. package/src/components/QuantityPicker/index.ts +14 -0
  212. package/src/components/ReactionButton/ReactionButton.feedback.test.tsx +50 -0
  213. package/src/components/ReactionButton/ReactionButton.test.tsx +5 -3
  214. package/src/components/ReactionButton/ReactionButton.tsx +20 -12
  215. package/src/components/ScrollFog/ScrollFog.test.tsx +222 -0
  216. package/src/components/ScrollFog/ScrollFog.tsx +172 -0
  217. package/src/components/ScrollFog/index.ts +1 -0
  218. package/src/components/Select/Select.namespace.ts +34 -0
  219. package/src/components/Select/Select.test.tsx +297 -0
  220. package/src/components/Select/Select.tsx +1483 -0
  221. package/src/components/Select/index.ts +39 -0
  222. package/src/components/Skeleton/Skeleton.test.tsx +64 -0
  223. package/src/components/Skeleton/Skeleton.tsx +45 -0
  224. package/src/components/Skeleton/index.ts +1 -0
  225. package/src/components/Slider/Slider.namespace.ts +26 -0
  226. package/src/components/Slider/Slider.test.tsx +260 -0
  227. package/src/components/Slider/Slider.tsx +897 -0
  228. package/src/components/Slider/Slider.utils.ts +167 -0
  229. package/src/components/Slider/index.ts +30 -0
  230. package/src/components/SwipeableMenuSheet/SwipeableMenuSheet.test.tsx +21 -1
  231. package/src/components/SwipeableMenuSheet/SwipeableMenuSheet.tsx +30 -7
  232. package/src/components/Switch/Switch.tsx +14 -13
  233. package/src/components/Tabs/Tabs.test.tsx +218 -1
  234. package/src/components/Tabs/Tabs.tsx +346 -75
  235. package/src/components/Tabs/Tabs.utils.ts +51 -1
  236. package/src/components/Tabs/index.ts +17 -1
  237. package/src/components/index.ts +14 -0
  238. package/src/hooks/useControllableState.ts +1 -43
  239. package/src/hooks/usePressTap.test.ts +23 -11
  240. package/src/hooks/usePressTap.ts +1 -60
  241. package/src/types.ts +1 -0
@@ -36,6 +36,7 @@ export function getTabsOrderedItems<T extends { value: string }>(
36
36
  export function getTabsTriggerRects(
37
37
  values: string[],
38
38
  widths: Record<string, number>,
39
+ triggerGap = 0,
39
40
  ): Record<string, TabsLayoutRect> {
40
41
  const rects = Object.create(null) as Record<string, TabsLayoutRect>;
41
42
  let left = 0;
@@ -49,12 +50,61 @@ export function getTabsTriggerRects(
49
50
  continue;
50
51
  }
51
52
  if (hasCompletePrefix) rects[value] = { left, width };
52
- left += width;
53
+ left += width + triggerGap;
53
54
  }
54
55
 
55
56
  return rects;
56
57
  }
57
58
 
59
+ /**
60
+ * Trigger rectangles begin at the first trigger, so they exclude list-content
61
+ * padding. Scroll offsets are measured from the scroll content edge.
62
+ */
63
+ export function getTabsScrollOffset({
64
+ scrollAlign,
65
+ currentOffset,
66
+ viewportWidth,
67
+ contentWidth,
68
+ contentInsetStart,
69
+ contentInsetEnd,
70
+ triggerRect,
71
+ }: {
72
+ scrollAlign: "nearest" | "start" | "center" | "end";
73
+ currentOffset: number;
74
+ viewportWidth: number;
75
+ contentWidth: number;
76
+ contentInsetStart: number;
77
+ contentInsetEnd: number;
78
+ triggerRect: TabsLayoutRect;
79
+ }): number {
80
+ const maxOffset = Math.max(0, contentWidth - viewportWidth);
81
+ const clampOffset = (offset: number) => Math.min(maxOffset, Math.max(0, offset));
82
+ const clampedCurrentOffset = clampOffset(currentOffset);
83
+ if (maxOffset === 0) return clampedCurrentOffset;
84
+
85
+ const triggerStart = contentInsetStart + triggerRect.left;
86
+ const triggerEnd = triggerStart + triggerRect.width;
87
+ if (scrollAlign === "nearest") {
88
+ // Visibility is the scroll-view's actual viewport. Insets provide the
89
+ // additional room only after a clipped trigger needs to move.
90
+ const visibleStart = clampedCurrentOffset;
91
+ const visibleEnd = clampedCurrentOffset + viewportWidth;
92
+
93
+ if (triggerStart >= visibleStart && triggerEnd <= visibleEnd) return clampedCurrentOffset;
94
+ return clampOffset(
95
+ triggerStart < visibleStart
96
+ ? triggerStart - contentInsetStart
97
+ : triggerEnd + contentInsetEnd - viewportWidth,
98
+ );
99
+ }
100
+
101
+ if (scrollAlign === "start") return clampOffset(triggerStart - contentInsetStart);
102
+ if (scrollAlign === "center") {
103
+ return clampOffset(triggerStart + triggerRect.width / 2 - viewportWidth / 2);
104
+ }
105
+ return clampOffset(triggerEnd + contentInsetEnd - viewportWidth);
106
+ }
107
+
58
108
  export function areTabsTransitionsEnabled(
59
109
  values: string[],
60
110
  rects: Record<string, TabsLayoutRect>,
@@ -1,2 +1,18 @@
1
- export * from "./Tabs";
1
+ export {
2
+ TabsCarousel,
3
+ TabsCarouselCamera,
4
+ TabsContent,
5
+ TabsIndicator,
6
+ TabsList,
7
+ TabsRoot,
8
+ TabsTrigger,
9
+ type TabsCarouselCameraProps,
10
+ type TabsCarouselProps,
11
+ type TabsContentProps,
12
+ type TabsIndicatorProps,
13
+ type TabsListProps,
14
+ type TabsRootProps,
15
+ type TabsTriggerProps,
16
+ } from "./Tabs";
17
+
2
18
  export * as Tabs from "./Tabs.namespace";
@@ -7,10 +7,17 @@ export * from "./BottomSheet";
7
7
  export * from "./Callout";
8
8
  export * from "./Checkbox";
9
9
  export * from "./Chip";
10
+ export * from "./ChipTabs";
10
11
  export * from "./Count";
12
+ export * from "./ContextualFloatingButton";
11
13
  export * from "./Divider";
12
14
  export * from "./Field";
15
+ export * from "./FloatingActionButton";
13
16
  export * from "./Icon";
17
+ export * from "./Dialog";
18
+ export * from "./AlertDialog";
19
+ export * from "./HelpBubble";
20
+ export * from "./IdentityPlaceholder";
14
21
  export * from "./InputButton";
15
22
  export * from "./KeyboardAvoidingScrollView";
16
23
  export * from "./MannerTemp";
@@ -20,15 +27,22 @@ export * from "./NotificationBadge";
20
27
  export * from "./PageBanner";
21
28
  export * from "./List";
22
29
  export * from "./ProgressCircle";
30
+ export * from "./QuantityPicker";
23
31
  export * from "./RadioGroup";
24
32
  export * from "./ReactionButton";
25
33
  export * from "./ScaleFeedback";
26
34
  export * from "./SegmentedControl";
35
+ export * from "./Select";
27
36
  export * from "./SelectBox";
37
+ export * from "./Skeleton";
38
+ export * from "./Slider";
28
39
  export * from "./Stack";
29
40
  export * from "./Switch";
41
+ export * from "./ScrollFog";
30
42
  export * from "./SwipeableMenuSheet";
31
43
  export * from "./Tabs";
32
44
  export * from "./TagGroup";
33
45
  export * from "./Text";
34
46
  export * from "./TextField";
47
+ export * from "./AttachmentInput";
48
+ export * from "./AttachmentDisplay";
@@ -1,43 +1 @@
1
- import { useRef, useState } from "@lynx-js/react";
2
- import { useMemoizedFn } from "@lynx-js/lynx-ui-common";
3
-
4
- export interface UseControllableStateProps<T> {
5
- value?: T;
6
- defaultValue: T;
7
- onChange?: (value: T) => void;
8
- }
9
-
10
- /**
11
- * Controlled/uncontrolled state pattern for Lynx components.
12
- *
13
- * - When `value` is provided, the component is controlled.
14
- * - When `value` is `undefined`, the component manages its own state
15
- * starting from `defaultValue`.
16
- * - `onChange` fires in both modes.
17
- */
18
- export function useControllableState<T>(
19
- props: UseControllableStateProps<T>,
20
- ): [T, (value: T) => void] {
21
- const { value, defaultValue, onChange } = props;
22
- const isControlled = value !== undefined;
23
- const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
24
- const currentValue = isControlled ? value : uncontrolledValue;
25
- const prevValueRef = useRef(currentValue);
26
-
27
- const setValue = useMemoizedFn((nextValue: T) => {
28
- if (isControlled) {
29
- if (nextValue !== value) {
30
- onChange?.(nextValue);
31
- }
32
- return;
33
- }
34
-
35
- setUncontrolledValue(nextValue);
36
- if (nextValue !== prevValueRef.current) {
37
- onChange?.(nextValue);
38
- prevValueRef.current = nextValue;
39
- }
40
- });
41
-
42
- return [currentValue, setValue];
43
- }
1
+ export * from "@seed-design/lynx-react-use-controllable-state";
@@ -60,8 +60,8 @@ describe("usePressTap", () => {
60
60
  expect(onTap).toHaveBeenCalledTimes(1);
61
61
  });
62
62
 
63
- it("clears pressed when bindtap fires before touchend", () => {
64
- const { result } = renderHook(() => usePressTap({ onTap: vi.fn() }));
63
+ it("clears pressed on tap without requiring a callback", () => {
64
+ const { result } = renderHook(() => usePressTap());
65
65
 
66
66
  act(() => {
67
67
  result.current.bindtouchstart(fakeEvent);
@@ -72,19 +72,31 @@ describe("usePressTap", () => {
72
72
 
73
73
  expect(result.current.pressed).toBe(false);
74
74
  });
75
+ });
75
76
 
76
- it("can be omitted without error", () => {
77
- const { result } = renderHook(() => usePressTap());
77
+ describe("disabled", () => {
78
+ it("clears an active press without restoring it when re-enabled", () => {
79
+ const { result, rerender } = renderHook(({ disabled }) => usePressTap({ disabled }), {
80
+ initialProps: { disabled: false },
81
+ });
82
+
83
+ act(() => {
84
+ result.current.bindtouchstart(fakeEvent);
85
+ });
86
+ expect(result.current.pressed).toBe(true);
78
87
 
79
- expect(() => {
80
- act(() => {
81
- result.current.bindtap(fakeEvent);
82
- });
83
- }).not.toThrow();
88
+ rerender({ disabled: true });
89
+ expect(result.current.pressed).toBe(false);
90
+
91
+ rerender({ disabled: false });
92
+ expect(result.current.pressed).toBe(false);
93
+
94
+ act(() => {
95
+ result.current.bindtouchstart(fakeEvent);
96
+ });
97
+ expect(result.current.pressed).toBe(true);
84
98
  });
85
- });
86
99
 
87
- describe("disabled", () => {
88
100
  it("does not update pressed on bindtouchstart", () => {
89
101
  const { result } = renderHook(() => usePressTap({ disabled: true }));
90
102
 
@@ -1,60 +1 @@
1
- import { useState } from "@lynx-js/react";
2
- import { useMemoizedFn } from "@lynx-js/lynx-ui-common";
3
- import type { BaseTouchEvent, EventHandler, Target } from "@lynx-js/types";
4
-
5
- import type { LynxTouchProps } from "../types";
6
-
7
- type TouchHandler = EventHandler<BaseTouchEvent<Target>>;
8
- type PressStateHandler = TouchHandler & (() => void);
9
-
10
- export interface UsePressTapOptions {
11
- disabled?: boolean;
12
- onTap?: TouchHandler;
13
- mainThreadOnTap?: LynxTouchProps["main-thread:bindtap"];
14
- }
15
-
16
- export interface UsePressTapReturn {
17
- pressed: boolean;
18
- bindtap: TouchHandler;
19
- bindtouchstart: PressStateHandler;
20
- bindtouchend: PressStateHandler;
21
- bindtouchcancel: PressStateHandler;
22
- "main-thread:bindtap"?: LynxTouchProps["main-thread:bindtap"];
23
- }
24
-
25
- /**
26
- * Hook that provides press/tap interaction state for Lynx elements.
27
- *
28
- * - Tracks `pressed` state via touch events.
29
- * - When `disabled` is true, the element cannot become active and no tap fires.
30
- * - If the element becomes disabled during a press, the active state is cleared.
31
- * - `main-thread:bindtap` is conditionally included (only when enabled and provided).
32
- */
33
- export function usePressTap(options: UsePressTapOptions = {}): UsePressTapReturn {
34
- const { disabled = false, onTap, mainThreadOnTap } = options;
35
- const [pressed, setPressed] = useState(false);
36
-
37
- const press = useMemoizedFn(() => {
38
- if (disabled) return;
39
- setPressed(true);
40
- });
41
-
42
- const reset = useMemoizedFn(() => {
43
- setPressed(false);
44
- });
45
-
46
- const handleTap = useMemoizedFn((...args: Parameters<TouchHandler>) => {
47
- if (disabled) return;
48
- setPressed(false);
49
- onTap?.(...args);
50
- });
51
-
52
- return {
53
- pressed,
54
- bindtap: handleTap,
55
- bindtouchstart: press,
56
- bindtouchend: reset,
57
- bindtouchcancel: reset,
58
- ...(!disabled && mainThreadOnTap ? { "main-thread:bindtap": mainThreadOnTap } : {}),
59
- };
60
- }
1
+ export * from "@seed-design/lynx-react-use-press-tap";
package/src/types.ts CHANGED
@@ -41,6 +41,7 @@ export interface LynxIconElementProps {
41
41
  className?: IntrinsicElements["image"]["className"];
42
42
  style?: LynxStyle;
43
43
  ref?: LynxMainThreadRef;
44
+ "disable-default-resize"?: boolean;
44
45
  "main-thread:binduiappear"?: IntrinsicElements["image"]["main-thread:binduiappear"];
45
46
  }
46
47