@seed-design/lynx-react 0.7.1 → 0.9.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 (265) 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 +42 -16
  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/context.d.ts +2 -1
  17. package/lib/components/AppBar/context.d.ts.map +1 -1
  18. package/lib/components/AppBar/index.d.ts +1 -1
  19. package/lib/components/AppBar/index.d.ts.map +1 -1
  20. package/lib/components/AppBar/useAppBar.d.ts +2 -1
  21. package/lib/components/AppBar/useAppBar.d.ts.map +1 -1
  22. package/lib/components/AppBar/useAppBar.js +17 -15
  23. package/lib/components/AttachmentDisplay/AttachmentDisplay.d.ts +182 -0
  24. package/lib/components/AttachmentDisplay/AttachmentDisplay.d.ts.map +1 -0
  25. package/lib/components/AttachmentDisplay/AttachmentDisplay.jsx +444 -0
  26. package/lib/components/AttachmentDisplay/index.d.ts +2 -0
  27. package/lib/components/AttachmentDisplay/index.d.ts.map +1 -0
  28. package/lib/components/AttachmentInput/AttachmentInput.d.ts +179 -0
  29. package/lib/components/AttachmentInput/AttachmentInput.d.ts.map +1 -0
  30. package/lib/components/AttachmentInput/AttachmentInput.jsx +520 -0
  31. package/lib/components/AttachmentInput/index.d.ts +2 -0
  32. package/lib/components/AttachmentInput/index.d.ts.map +1 -0
  33. package/lib/components/BottomSheet/BottomSheet.d.ts +1 -1
  34. package/lib/components/BottomSheet/BottomSheet.d.ts.map +1 -1
  35. package/lib/components/BottomSheet/BottomSheet.jsx +1 -7
  36. package/lib/components/Box/Box.d.ts +3 -3
  37. package/lib/components/Box/Box.d.ts.map +1 -1
  38. package/lib/components/Callout/Callout.jsx +2 -2
  39. package/lib/components/Checkbox/Checkbox.jsx +2 -2
  40. package/lib/components/Chip/Chip.jsx +2 -2
  41. package/lib/components/ChipTabs/ChipTabs.d.ts +41 -0
  42. package/lib/components/ChipTabs/ChipTabs.d.ts.map +1 -0
  43. package/lib/components/ChipTabs/ChipTabs.jsx +39 -0
  44. package/lib/components/ChipTabs/ChipTabs.namespace.d.ts +2 -0
  45. package/lib/components/ChipTabs/ChipTabs.namespace.d.ts.map +1 -0
  46. package/lib/components/ChipTabs/ChipTabs.namespace.js +13 -0
  47. package/lib/components/ChipTabs/index.d.ts +3 -0
  48. package/lib/components/ChipTabs/index.d.ts.map +1 -0
  49. package/lib/components/ContextualFloatingButton/ContextualFloatingButton.d.ts +18 -0
  50. package/lib/components/ContextualFloatingButton/ContextualFloatingButton.d.ts.map +1 -0
  51. package/lib/components/ContextualFloatingButton/ContextualFloatingButton.jsx +113 -0
  52. package/lib/components/ContextualFloatingButton/index.d.ts +2 -0
  53. package/lib/components/ContextualFloatingButton/index.d.ts.map +1 -0
  54. package/lib/components/Dialog/Dialog.d.ts +87 -0
  55. package/lib/components/Dialog/Dialog.d.ts.map +1 -0
  56. package/lib/components/Dialog/Dialog.jsx +147 -0
  57. package/lib/components/Dialog/Dialog.namespace.d.ts +2 -0
  58. package/lib/components/Dialog/Dialog.namespace.d.ts.map +1 -0
  59. package/lib/components/Dialog/Dialog.namespace.js +18 -0
  60. package/lib/components/Dialog/index.d.ts +3 -0
  61. package/lib/components/Dialog/index.d.ts.map +1 -0
  62. package/lib/components/FloatingActionButton/FloatingActionButton.d.ts +23 -0
  63. package/lib/components/FloatingActionButton/FloatingActionButton.d.ts.map +1 -0
  64. package/lib/components/FloatingActionButton/FloatingActionButton.jsx +76 -0
  65. package/lib/components/FloatingActionButton/FloatingActionButton.namespace.d.ts +2 -0
  66. package/lib/components/FloatingActionButton/FloatingActionButton.namespace.d.ts.map +1 -0
  67. package/lib/components/FloatingActionButton/FloatingActionButton.namespace.js +10 -0
  68. package/lib/components/FloatingActionButton/index.d.ts +3 -0
  69. package/lib/components/FloatingActionButton/index.d.ts.map +1 -0
  70. package/lib/components/HelpBubble/HelpBubble.d.ts +67 -0
  71. package/lib/components/HelpBubble/HelpBubble.d.ts.map +1 -0
  72. package/lib/components/HelpBubble/HelpBubble.jsx +600 -0
  73. package/lib/components/HelpBubble/HelpBubble.namespace.d.ts +2 -0
  74. package/lib/components/HelpBubble/HelpBubble.namespace.d.ts.map +1 -0
  75. package/lib/components/HelpBubble/HelpBubble.namespace.js +18 -0
  76. package/lib/components/HelpBubble/index.d.ts +3 -0
  77. package/lib/components/HelpBubble/index.d.ts.map +1 -0
  78. package/lib/components/Icon/Icon.d.ts +1 -0
  79. package/lib/components/Icon/Icon.d.ts.map +1 -1
  80. package/lib/components/Icon/Icon.jsx +2 -1
  81. package/lib/components/IdentityPlaceholder/IdentityPlaceholder.d.ts +28 -0
  82. package/lib/components/IdentityPlaceholder/IdentityPlaceholder.d.ts.map +1 -0
  83. package/lib/components/IdentityPlaceholder/IdentityPlaceholder.jsx +37 -0
  84. package/lib/components/IdentityPlaceholder/IdentityPlaceholder.namespace.d.ts +2 -0
  85. package/lib/components/IdentityPlaceholder/IdentityPlaceholder.namespace.d.ts.map +1 -0
  86. package/lib/components/IdentityPlaceholder/IdentityPlaceholder.namespace.js +9 -0
  87. package/lib/components/IdentityPlaceholder/identity-placeholder-business.js +4 -0
  88. package/lib/components/IdentityPlaceholder/identity-placeholder-person.js +4 -0
  89. package/lib/components/IdentityPlaceholder/index.d.ts +3 -0
  90. package/lib/components/IdentityPlaceholder/index.d.ts.map +1 -0
  91. package/lib/components/InputButton/InputButton.d.ts +2 -0
  92. package/lib/components/InputButton/InputButton.d.ts.map +1 -1
  93. package/lib/components/InputButton/InputButton.jsx +40 -8
  94. package/lib/components/List/List.d.ts +1 -1
  95. package/lib/components/List/List.d.ts.map +1 -1
  96. package/lib/components/List/List.jsx +26 -12
  97. package/lib/components/Menu/Menu.d.ts.map +1 -1
  98. package/lib/components/Menu/Menu.jsx +15 -5
  99. package/lib/components/PageBanner/PageBanner.d.ts +3 -0
  100. package/lib/components/PageBanner/PageBanner.d.ts.map +1 -1
  101. package/lib/components/PageBanner/PageBanner.jsx +49 -11
  102. package/lib/components/QuantityPicker/QuantityPicker.d.ts +53 -0
  103. package/lib/components/QuantityPicker/QuantityPicker.d.ts.map +1 -0
  104. package/lib/components/QuantityPicker/QuantityPicker.jsx +282 -0
  105. package/lib/components/QuantityPicker/QuantityPicker.namespace.d.ts +2 -0
  106. package/lib/components/QuantityPicker/QuantityPicker.namespace.d.ts.map +1 -0
  107. package/lib/components/QuantityPicker/QuantityPicker.namespace.js +11 -0
  108. package/lib/components/QuantityPicker/index.d.ts +3 -0
  109. package/lib/components/QuantityPicker/index.d.ts.map +1 -0
  110. package/lib/components/RadioGroup/RadioGroup.jsx +2 -2
  111. package/lib/components/ReactionButton/ReactionButton.d.ts +1 -1
  112. package/lib/components/ReactionButton/ReactionButton.d.ts.map +1 -1
  113. package/lib/components/ReactionButton/ReactionButton.jsx +22 -13
  114. package/lib/components/ScrollFog/ScrollFog.d.ts +41 -0
  115. package/lib/components/ScrollFog/ScrollFog.d.ts.map +1 -0
  116. package/lib/components/ScrollFog/ScrollFog.jsx +65 -0
  117. package/lib/components/ScrollFog/index.d.ts +2 -0
  118. package/lib/components/ScrollFog/index.d.ts.map +1 -0
  119. package/lib/components/SegmentedControl/SegmentedControl.jsx +2 -2
  120. package/lib/components/Select/Select.d.ts +112 -0
  121. package/lib/components/Select/Select.d.ts.map +1 -0
  122. package/lib/components/Select/Select.jsx +885 -0
  123. package/lib/components/Select/Select.namespace.d.ts +2 -0
  124. package/lib/components/Select/Select.namespace.d.ts.map +1 -0
  125. package/lib/components/Select/Select.namespace.js +23 -0
  126. package/lib/components/Select/index.d.ts +3 -0
  127. package/lib/components/Select/index.d.ts.map +1 -0
  128. package/lib/components/Skeleton/Skeleton.d.ts +15 -0
  129. package/lib/components/Skeleton/Skeleton.d.ts.map +1 -0
  130. package/lib/components/Skeleton/Skeleton.jsx +18 -0
  131. package/lib/components/Skeleton/index.d.ts +2 -0
  132. package/lib/components/Skeleton/index.d.ts.map +1 -0
  133. package/lib/components/Slider/Slider.d.ts +101 -0
  134. package/lib/components/Slider/Slider.d.ts.map +1 -0
  135. package/lib/components/Slider/Slider.jsx +573 -0
  136. package/lib/components/Slider/Slider.namespace.d.ts +2 -0
  137. package/lib/components/Slider/Slider.namespace.d.ts.map +1 -0
  138. package/lib/components/Slider/Slider.namespace.js +19 -0
  139. package/lib/components/Slider/Slider.utils.d.ts +19 -0
  140. package/lib/components/Slider/Slider.utils.d.ts.map +1 -0
  141. package/lib/components/Slider/Slider.utils.js +106 -0
  142. package/lib/components/Slider/index.d.ts +3 -0
  143. package/lib/components/Slider/index.d.ts.map +1 -0
  144. package/lib/components/Stack/Stack.d.ts +7 -9
  145. package/lib/components/Stack/Stack.d.ts.map +1 -1
  146. package/lib/components/SwipeableMenuSheet/SwipeableMenuSheet.d.ts.map +1 -1
  147. package/lib/components/SwipeableMenuSheet/SwipeableMenuSheet.jsx +22 -8
  148. package/lib/components/Switch/Switch.d.ts.map +1 -1
  149. package/lib/components/Switch/Switch.jsx +5 -3
  150. package/lib/components/Tabs/Tabs.d.ts +34 -2
  151. package/lib/components/Tabs/Tabs.d.ts.map +1 -1
  152. package/lib/components/Tabs/Tabs.jsx +186 -56
  153. package/lib/components/Tabs/Tabs.utils.d.ts +14 -1
  154. package/lib/components/Tabs/Tabs.utils.d.ts.map +1 -1
  155. package/lib/components/Tabs/Tabs.utils.js +24 -3
  156. package/lib/components/Tabs/index.d.ts +1 -1
  157. package/lib/components/Tabs/index.d.ts.map +1 -1
  158. package/lib/components/index.d.ts +14 -0
  159. package/lib/components/index.d.ts.map +1 -1
  160. package/lib/hooks/useControllableState.d.ts +1 -14
  161. package/lib/hooks/useControllableState.d.ts.map +1 -1
  162. package/lib/hooks/usePressTap.d.ts +1 -27
  163. package/lib/hooks/usePressTap.d.ts.map +1 -1
  164. package/lib/hooks/useSafeArea.d.ts +8 -4
  165. package/lib/hooks/useSafeArea.d.ts.map +1 -1
  166. package/lib/hooks/useSafeArea.js +22 -20
  167. package/lib/index.js +29 -6
  168. package/lib/{hooks/useControllableState.js → packages/lynx-react-headless/use-controllable-state/lib/index.js} +2 -3
  169. package/lib/{hooks/usePressTap.js → packages/lynx-react-headless/use-press-tap/lib/index.js} +13 -10
  170. package/lib/types.d.ts +1 -0
  171. package/lib/types.d.ts.map +1 -1
  172. package/lib/utils/styled.d.ts +46 -6
  173. package/lib/utils/styled.d.ts.map +1 -1
  174. package/lib/utils/styled.js +19 -4
  175. package/package.json +9 -5
  176. package/src/components/AlertDialog/AlertDialog.namespace.ts +22 -0
  177. package/src/components/AlertDialog/AlertDialog.test.tsx +226 -0
  178. package/src/components/AlertDialog/AlertDialog.tsx +374 -0
  179. package/src/components/AlertDialog/index.ts +24 -0
  180. package/src/components/AppBar/AppBar.namespace.ts +1 -0
  181. package/src/components/AppBar/AppBar.test.tsx +252 -3
  182. package/src/components/AppBar/AppBar.tsx +108 -25
  183. package/src/components/AppBar/context.ts +3 -1
  184. package/src/components/AppBar/index.ts +1 -0
  185. package/src/components/AppBar/useAppBar.ts +21 -15
  186. package/src/components/AttachmentDisplay/AttachmentDisplay.tsx +886 -0
  187. package/src/components/AttachmentDisplay/index.ts +48 -0
  188. package/src/components/AttachmentInput/AttachmentInput.tsx +1001 -0
  189. package/src/components/AttachmentInput/index.ts +49 -0
  190. package/src/components/BottomSheet/BottomSheet.test.tsx +22 -7
  191. package/src/components/BottomSheet/BottomSheet.tsx +1 -19
  192. package/src/components/Box/Box.test.tsx +104 -0
  193. package/src/components/Box/Box.tsx +9 -6
  194. package/src/components/ChipTabs/ChipTabs.namespace.ts +14 -0
  195. package/src/components/ChipTabs/ChipTabs.tsx +119 -0
  196. package/src/components/ChipTabs/index.ts +16 -0
  197. package/src/components/ContextualFloatingButton/ContextualFloatingButton.test.tsx +63 -0
  198. package/src/components/ContextualFloatingButton/ContextualFloatingButton.tsx +232 -0
  199. package/src/components/ContextualFloatingButton/index.ts +4 -0
  200. package/src/components/Dialog/Dialog.namespace.ts +24 -0
  201. package/src/components/Dialog/Dialog.test.tsx +172 -0
  202. package/src/components/Dialog/Dialog.tsx +373 -0
  203. package/src/components/Dialog/index.ts +26 -0
  204. package/src/components/FloatingActionButton/FloatingActionButton.namespace.ts +8 -0
  205. package/src/components/FloatingActionButton/FloatingActionButton.test.tsx +59 -0
  206. package/src/components/FloatingActionButton/FloatingActionButton.tsx +207 -0
  207. package/src/components/FloatingActionButton/index.ts +10 -0
  208. package/src/components/HelpBubble/HelpBubble.namespace.ts +24 -0
  209. package/src/components/HelpBubble/HelpBubble.tsx +998 -0
  210. package/src/components/HelpBubble/index.ts +26 -0
  211. package/src/components/Icon/Icon.test.tsx +0 -3
  212. package/src/components/Icon/Icon.tsx +11 -1
  213. package/src/components/IdentityPlaceholder/IdentityPlaceholder.namespace.ts +6 -0
  214. package/src/components/IdentityPlaceholder/IdentityPlaceholder.tsx +103 -0
  215. package/src/components/IdentityPlaceholder/assets.d.ts +4 -0
  216. package/src/components/IdentityPlaceholder/identity-placeholder-business.webp +0 -0
  217. package/src/components/IdentityPlaceholder/identity-placeholder-person.webp +0 -0
  218. package/src/components/IdentityPlaceholder/index.ts +8 -0
  219. package/src/components/InputButton/InputButton.test.tsx +128 -1
  220. package/src/components/InputButton/InputButton.tsx +60 -9
  221. package/src/components/List/List.test.tsx +54 -2
  222. package/src/components/List/List.tsx +43 -10
  223. package/src/components/Menu/Menu.tsx +14 -4
  224. package/src/components/Menu/__tests__/Menu.test.tsx +34 -0
  225. package/src/components/PageBanner/PageBanner.test.tsx +110 -3
  226. package/src/components/PageBanner/PageBanner.tsx +83 -19
  227. package/src/components/QuantityPicker/QuantityPicker.namespace.ts +10 -0
  228. package/src/components/QuantityPicker/QuantityPicker.test.tsx +235 -0
  229. package/src/components/QuantityPicker/QuantityPicker.tsx +605 -0
  230. package/src/components/QuantityPicker/index.ts +14 -0
  231. package/src/components/ReactionButton/ReactionButton.feedback.test.tsx +50 -0
  232. package/src/components/ReactionButton/ReactionButton.test.tsx +5 -3
  233. package/src/components/ReactionButton/ReactionButton.tsx +20 -12
  234. package/src/components/ScrollFog/ScrollFog.test.tsx +222 -0
  235. package/src/components/ScrollFog/ScrollFog.tsx +172 -0
  236. package/src/components/ScrollFog/index.ts +1 -0
  237. package/src/components/Select/Select.namespace.ts +34 -0
  238. package/src/components/Select/Select.test.tsx +297 -0
  239. package/src/components/Select/Select.tsx +1483 -0
  240. package/src/components/Select/index.ts +39 -0
  241. package/src/components/Skeleton/Skeleton.test.tsx +64 -0
  242. package/src/components/Skeleton/Skeleton.tsx +45 -0
  243. package/src/components/Skeleton/index.ts +1 -0
  244. package/src/components/Slider/Slider.namespace.ts +26 -0
  245. package/src/components/Slider/Slider.test.tsx +260 -0
  246. package/src/components/Slider/Slider.tsx +897 -0
  247. package/src/components/Slider/Slider.utils.ts +167 -0
  248. package/src/components/Slider/index.ts +30 -0
  249. package/src/components/Stack/Stack.test.tsx +7 -0
  250. package/src/components/Stack/Stack.tsx +11 -10
  251. package/src/components/SwipeableMenuSheet/SwipeableMenuSheet.test.tsx +21 -1
  252. package/src/components/SwipeableMenuSheet/SwipeableMenuSheet.tsx +30 -7
  253. package/src/components/Switch/Switch.tsx +14 -13
  254. package/src/components/Tabs/Tabs.test.tsx +218 -1
  255. package/src/components/Tabs/Tabs.tsx +346 -75
  256. package/src/components/Tabs/Tabs.utils.ts +51 -1
  257. package/src/components/Tabs/index.ts +17 -1
  258. package/src/components/index.ts +14 -0
  259. package/src/hooks/useControllableState.ts +1 -43
  260. package/src/hooks/usePressTap.test.ts +23 -11
  261. package/src/hooks/usePressTap.ts +1 -60
  262. package/src/hooks/useSafeArea.test.ts +13 -1
  263. package/src/hooks/useSafeArea.ts +25 -23
  264. package/src/types.ts +1 -0
  265. package/src/utils/styled.ts +127 -9
@@ -0,0 +1,235 @@
1
+ import "@testing-library/jest-dom";
2
+ import * as React from "@lynx-js/react";
3
+ import { fireEvent, render } from "@lynx-js/react/testing-library";
4
+ import type { MainThread } from "@lynx-js/types";
5
+ import { describe, expect, it, vi } from "vitest";
6
+
7
+ import type { LynxIconElementProps } from "../../types";
8
+ import { QuantityPicker } from "./index";
9
+
10
+ const TestIcon = React.forwardRef<MainThread.Element, LynxIconElementProps>((props, ref) => (
11
+ <image {...props} {...(ref ? { "main-thread:ref": ref } : {})} />
12
+ ));
13
+ TestIcon.displayName = "TestIcon";
14
+
15
+ function renderQuantityPicker(
16
+ props: Partial<QuantityPicker.RootProps> = {},
17
+ children?: React.ReactNode,
18
+ ) {
19
+ const rootProps = {
20
+ min: 0,
21
+ max: 5,
22
+ "accessibility-label": "수량",
23
+ ...props,
24
+ } as QuantityPicker.RootProps;
25
+
26
+ return render(
27
+ <QuantityPicker.Root {...rootProps}>
28
+ {children ?? (
29
+ <>
30
+ <QuantityPicker.DecrementButton accessibility-label="줄이기" />
31
+ <QuantityPicker.ValueDisplay />
32
+ <QuantityPicker.IncrementButton accessibility-label="늘리기" />
33
+ </>
34
+ )}
35
+ </QuantityPicker.Root>,
36
+ );
37
+ }
38
+
39
+ function getElement(container: HTMLElement, selector: string) {
40
+ const element = container.querySelector<HTMLElement>(selector);
41
+ if (!element) throw new Error(`Expected element matching ${selector} to exist.`);
42
+ return element;
43
+ }
44
+
45
+ function getAction(container: HTMLElement, label: string) {
46
+ return getElement(container, `[accessibility-label="${label}"]`);
47
+ }
48
+
49
+ function getRoot(container: HTMLElement) {
50
+ return getAction(container, "수량");
51
+ }
52
+
53
+ function getValueText(container: HTMLElement) {
54
+ return getElement(container, ".seed-quantity-picker__valueDisplayText");
55
+ }
56
+
57
+ function getText(container: HTMLElement, text: string) {
58
+ const element = Array.from(container.querySelectorAll<HTMLElement>("text")).find(
59
+ (candidate) => candidate.textContent === text,
60
+ );
61
+ if (!element) throw new Error(`Expected text node ${text} to exist.`);
62
+ return element;
63
+ }
64
+
65
+ describe("QuantityPicker", () => {
66
+ it("initializes from min and clamps uncontrolled changes", () => {
67
+ const { container } = renderQuantityPicker({ min: 1, max: 3, step: 2 });
68
+ const increment = getAction(container, "늘리기");
69
+
70
+ expect(getValueText(container)).toHaveTextContent("1");
71
+ fireEvent.tap(increment);
72
+ expect(getValueText(container)).toHaveTextContent("3");
73
+ fireEvent.tap(increment);
74
+ expect(getValueText(container)).toHaveTextContent("3");
75
+ });
76
+
77
+ it("calls back without changing a controlled value", () => {
78
+ const onValueChange = vi.fn();
79
+ const { container } = renderQuantityPicker({ value: 2, onValueChange });
80
+
81
+ fireEvent.tap(getAction(container, "늘리기"));
82
+ expect(onValueChange).toHaveBeenCalledWith(3);
83
+ expect(getValueText(container)).toHaveTextContent("2");
84
+ });
85
+ it("uses the decrement action as remove at min", () => {
86
+ const onRemove = vi.fn();
87
+ const onValueChange = vi.fn();
88
+ const { container } = renderQuantityPicker({
89
+ min: 1,
90
+ defaultValue: 1,
91
+ removable: true,
92
+ removeAccessibilityLabel: "상품 삭제",
93
+ onRemove,
94
+ onValueChange,
95
+ });
96
+
97
+ fireEvent.tap(getAction(container, "상품 삭제"));
98
+ expect(onRemove).toHaveBeenCalledTimes(1);
99
+ expect(onValueChange).not.toHaveBeenCalled();
100
+ expect(getValueText(container)).toHaveTextContent("1");
101
+ });
102
+
103
+ it("blocks per-action loading and readOnly taps", () => {
104
+ const onValueChange = vi.fn();
105
+ const { container } = renderQuantityPicker({
106
+ defaultValue: 2,
107
+ loading: { increment: true },
108
+ readOnly: true,
109
+ onValueChange,
110
+ });
111
+
112
+ const decrement = getAction(container, "줄이기");
113
+ const increment = getAction(container, "늘리기");
114
+ expect(decrement).toHaveAttribute("accessibility-traits", "disabled");
115
+ expect(increment).toHaveAttribute("accessibility-traits", "disabled");
116
+ fireEvent.tap(increment);
117
+ expect(onValueChange).not.toHaveBeenCalled();
118
+ });
119
+
120
+ it("applies disabled icon state at action boundaries", () => {
121
+ const { container } = renderQuantityPicker(
122
+ { defaultValue: 0 },
123
+ <>
124
+ <QuantityPicker.DecrementButton accessibility-label="줄이기" icon={<TestIcon />} />
125
+ <QuantityPicker.ValueDisplay />
126
+ <QuantityPicker.IncrementButton accessibility-label="늘리기" icon={<TestIcon />} />
127
+ </>,
128
+ );
129
+
130
+ const decrement = getAction(container, "줄이기");
131
+ const increment = getAction(container, "늘리기");
132
+ expect(decrement).toHaveAttribute("accessibility-traits", "disabled");
133
+ expect(increment).toHaveAttribute("accessibility-traits", "button");
134
+ expect(getElement(container, ".seed-quantity-picker__decrementIcon")).toHaveClass(
135
+ "seed-quantity-picker__decrementIcon--disabled_true",
136
+ );
137
+ expect(getElement(container, ".seed-quantity-picker__incrementIcon")).not.toHaveClass(
138
+ "seed-quantity-picker__incrementIcon--disabled_true",
139
+ );
140
+ fireEvent.tap(decrement);
141
+ expect(getValueText(container)).toHaveTextContent("0");
142
+ fireEvent.tap(increment);
143
+ expect(getValueText(container)).toHaveTextContent("1");
144
+ });
145
+
146
+ it("renders loading indicators as ordinary nodes and primitive content as text", () => {
147
+ const { container } = renderQuantityPicker(
148
+ { defaultValue: 1, loading: { increment: true } },
149
+ <>
150
+ <QuantityPicker.DecrementButton>−</QuantityPicker.DecrementButton>
151
+ <QuantityPicker.ValueDisplay />
152
+ <QuantityPicker.IncrementButton loadingIndicator={<view className="loading-node" />}>
153
+ +
154
+ </QuantityPicker.IncrementButton>
155
+ </>,
156
+ );
157
+
158
+ expect(getText(container, "−").tagName.toLowerCase()).toBe("text");
159
+ const loadingNode = getElement(container, ".loading-node");
160
+ expect(loadingNode).not.toHaveClass("seed-quantity-picker__incrementIcon");
161
+ expect(loadingNode.parentElement).toHaveClass("seed-quantity-picker__incrementIcon");
162
+ });
163
+
164
+ it("formats the value and reserves width for a negative minimum", () => {
165
+ const { container } = renderQuantityPicker({
166
+ min: -999,
167
+ max: 5,
168
+ defaultValue: -2,
169
+ getValueText: (valueText, value) => `${valueText}개(${value})`,
170
+ });
171
+
172
+ expect(getValueText(container)).toHaveTextContent("-2개(-2)");
173
+ expect(
174
+ getElement(container, ".seed-quantity-picker__valueDisplayPlaceholder"),
175
+ ).toHaveTextContent("-000개(-000)");
176
+ });
177
+
178
+ it("inserts dividers only between adjacent actions and value, and reverses RTL children", () => {
179
+ const { container } = renderQuantityPicker(
180
+ { dir: "rtl" },
181
+ <>
182
+ <QuantityPicker.DecrementButton accessibility-label="줄이기" />
183
+ <QuantityPicker.ValueDisplay />
184
+ <QuantityPicker.IncrementButton accessibility-label="늘리기" />
185
+ </>,
186
+ );
187
+
188
+ const root = getRoot(container);
189
+ expect(root.children[0]).toBe(getAction(container, "늘리기"));
190
+ expect(root.children[1]).toHaveClass("seed-quantity-picker__divider");
191
+ expect(root.children[2]).toHaveClass("seed-quantity-picker__valueDisplay");
192
+ expect(root.children[3]).toHaveClass("seed-quantity-picker__divider");
193
+ expect(root.children[4]).toBe(getAction(container, "줄이기"));
194
+ expect(container.querySelectorAll<HTMLElement>(".seed-quantity-picker__divider")).toHaveLength(
195
+ 2,
196
+ );
197
+ });
198
+
199
+ it("exposes native accessibility defaults without leaking recipe props", () => {
200
+ const { container } = renderQuantityPicker({
201
+ disabled: true,
202
+ invalid: true,
203
+ layout: "fill",
204
+ size: "large",
205
+ defaultValue: 2,
206
+ });
207
+ const root = getRoot(container);
208
+ const valueDisplay = getElement(container, ".seed-quantity-picker__valueDisplay");
209
+
210
+ expect(root).toHaveAttribute("accessibility-element", "true");
211
+ expect(root).toHaveAttribute("accessibility-role-description", "quantity picker");
212
+ expect(root).toHaveAttribute("accessibility-traits", "disabled");
213
+ expect(root).toHaveAttribute("accessibility-value", "2");
214
+ expect(root).not.toHaveAttribute("layout");
215
+ expect(root).not.toHaveAttribute("size");
216
+ expect(root).not.toHaveAttribute("data-invalid");
217
+ expect(valueDisplay).toHaveAttribute("accessibility-elements-hidden", "true");
218
+ });
219
+
220
+ it("allows ValueDisplay accessibility override", () => {
221
+ const { container } = renderQuantityPicker(
222
+ {},
223
+ <>
224
+ <QuantityPicker.DecrementButton />
225
+ <QuantityPicker.ValueDisplay accessibility-elements-hidden={false} />
226
+ <QuantityPicker.IncrementButton />
227
+ </>,
228
+ );
229
+
230
+ expect(getElement(container, ".seed-quantity-picker__valueDisplay")).toHaveAttribute(
231
+ "accessibility-elements-hidden",
232
+ "false",
233
+ );
234
+ });
235
+ });