taro-uno-ui 0.9.0 → 1.0.1

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 (312) hide show
  1. package/README.md +21 -0
  2. package/dist/js/{index-DffLRSro.js → index-CDFsvu80.js} +15369 -10741
  3. package/dist/js/index-CDFsvu80.js.map +1 -0
  4. package/dist/js/index-DFdcksbe.js.map +1 -1
  5. package/dist/js/index-DXRIkWX1.js.map +1 -1
  6. package/dist/js/{index-6NJ3A1Dn.js → index-JffnTUrv.js} +15430 -10801
  7. package/dist/js/index-JffnTUrv.js.map +1 -0
  8. package/dist/utils/http/request.d.ts +280 -0
  9. package/package.json +14 -10
  10. package/src/components/basic/Button/Button.tsx +53 -13
  11. package/src/components/basic/Button/Button.types.ts +45 -9
  12. package/src/components/basic/Divider/Divider.tsx +60 -29
  13. package/src/components/basic/Icon/Icon.data.ts +474 -0
  14. package/src/components/basic/Icon/Icon.test.tsx +2 -2
  15. package/src/components/basic/Icon/Icon.tsx +48 -35
  16. package/src/components/basic/Icon/IconManager.ts +229 -0
  17. package/src/components/basic/Text/Text.styles.ts +3 -3
  18. package/src/components/basic/Text/Text.types.ts +14 -4
  19. package/src/components/basic/Typography/Typography.styles.ts +10 -9
  20. package/src/components/basic/Typography/Typography.tsx +15 -13
  21. package/src/components/basic/Typography/Typography.types.ts +41 -41
  22. package/src/components/basic/Typography/index.tsx +1 -1
  23. package/src/components/basic/Video/Video.styles.ts +777 -0
  24. package/src/components/basic/Video/Video.test.tsx +490 -0
  25. package/src/components/basic/Video/Video.tsx +1468 -0
  26. package/src/components/basic/Video/Video.types.ts +500 -0
  27. package/src/components/basic/Video/index.tsx +26 -0
  28. package/src/components/basic/index.tsx +13 -15
  29. package/src/components/common/ErrorBoundary.tsx +1 -1
  30. package/src/components/common/LazyComponent.tsx +9 -8
  31. package/src/components/common/SecurityProvider.tsx +2 -14
  32. package/src/components/common/ThemeProvider.tsx +43 -56
  33. package/src/components/common/VirtualList.tsx +187 -205
  34. package/src/components/common/index.tsx +25 -0
  35. package/src/components/display/Avatar/Avatar.styles.ts +1 -1
  36. package/src/components/display/Avatar/Avatar.tsx +6 -19
  37. package/src/components/display/Avatar/Avatar.types.ts +1 -1
  38. package/src/components/display/Avatar/index.ts +1 -1
  39. package/src/components/display/Badge/Badge.tsx +3 -16
  40. package/src/components/display/Badge/Badge.types.ts +1 -1
  41. package/src/components/display/Badge/index.ts +1 -1
  42. package/src/components/display/Calendar/Calendar.styles.ts +36 -36
  43. package/src/components/display/Calendar/Calendar.test.tsx +27 -15
  44. package/src/components/display/Calendar/Calendar.tsx +56 -35
  45. package/src/components/display/Calendar/Calendar.types.ts +1 -1
  46. package/src/components/display/Calendar/index.ts +1 -1
  47. package/src/components/display/Card/Card.styles.ts +2 -2
  48. package/src/components/display/Card/Card.test.tsx +6 -4
  49. package/src/components/display/Card/Card.tsx +1 -1
  50. package/src/components/display/Card/Card.types.ts +4 -4
  51. package/src/components/display/Card/index.ts +1 -1
  52. package/src/components/display/Carousel/Carousel.styles.ts +31 -31
  53. package/src/components/display/Carousel/Carousel.tsx +34 -39
  54. package/src/components/display/Carousel/Carousel.types.ts +1 -1
  55. package/src/components/display/Carousel/index.ts +1 -1
  56. package/src/components/display/List/List.styles.ts +3 -3
  57. package/src/components/display/List/List.tsx +0 -1
  58. package/src/components/display/List/index.ts +1 -1
  59. package/src/components/display/Rate/Rate.styles.ts +5 -17
  60. package/src/components/display/Rate/Rate.tsx +6 -14
  61. package/src/components/display/Rate/Rate.types.ts +4 -3
  62. package/src/components/display/Rate/index.ts +3 -11
  63. package/src/components/display/Table/Table.test.tsx +2 -0
  64. package/src/components/display/Table/Table.tsx +3 -7
  65. package/src/components/display/Table/Table.types.ts +3 -2
  66. package/src/components/display/Tag/Tag.styles.ts +31 -31
  67. package/src/components/display/Tag/Tag.tsx +9 -26
  68. package/src/components/display/Tag/Tag.types.ts +1 -1
  69. package/src/components/display/Tag/index.ts +1 -1
  70. package/src/components/display/Timeline/Timeline.styles.ts +32 -32
  71. package/src/components/display/Timeline/Timeline.tsx +23 -42
  72. package/src/components/display/Timeline/Timeline.types.ts +1 -1
  73. package/src/components/display/Timeline/index.ts +1 -1
  74. package/src/components/display/index.tsx +33 -29
  75. package/src/components/feedback/Loading/Loading.tsx +6 -1
  76. package/src/components/feedback/Loading/index.ts +2 -5
  77. package/src/components/feedback/Message/Message.styles.ts +3 -3
  78. package/src/components/feedback/Message/index.ts +2 -5
  79. package/src/components/feedback/Modal/Modal.styles.ts +1 -1
  80. package/src/components/feedback/Modal/Modal.tsx +9 -31
  81. package/src/components/feedback/Modal/Modal.types.ts +12 -2
  82. package/src/components/feedback/Notification/Notification.styles.ts +49 -39
  83. package/src/components/feedback/Notification/Notification.test.tsx +1 -1
  84. package/src/components/feedback/Notification/Notification.tsx +97 -120
  85. package/src/components/feedback/Notification/Notification.types.ts +11 -8
  86. package/src/components/feedback/Notification/NotificationManager.tsx +135 -106
  87. package/src/components/feedback/Notification/index.ts +10 -3
  88. package/src/components/feedback/Notification/index.tsx +16 -26
  89. package/src/components/feedback/Progress/Progress.styles.ts +23 -14
  90. package/src/components/feedback/Progress/Progress.tsx +93 -113
  91. package/src/components/feedback/Progress/Progress.types.ts +1 -1
  92. package/src/components/feedback/Progress/index.ts +1 -1
  93. package/src/components/feedback/Progress/utils/animation.ts +12 -23
  94. package/src/components/feedback/Progress/utils/index.ts +2 -2
  95. package/src/components/feedback/Progress/utils/progress-calculator.ts +14 -32
  96. package/src/components/feedback/Result/Result.styles.ts +29 -29
  97. package/src/components/feedback/Result/Result.tsx +8 -20
  98. package/src/components/feedback/Result/Result.types.ts +7 -7
  99. package/src/components/feedback/Result/index.tsx +1 -1
  100. package/src/components/feedback/Toast/Toast.styles.ts +1 -1
  101. package/src/components/feedback/Toast/Toast.tsx +25 -13
  102. package/src/components/feedback/Tooltip/Tooltip.examples.tsx +21 -44
  103. package/src/components/feedback/Tooltip/Tooltip.styles.ts +16 -22
  104. package/src/components/feedback/Tooltip/Tooltip.test.tsx +1 -1
  105. package/src/components/feedback/Tooltip/Tooltip.tsx +65 -46
  106. package/src/components/feedback/Tooltip/Tooltip.types.ts +14 -20
  107. package/src/components/feedback/Tooltip/index.ts +1 -1
  108. package/src/components/feedback/Tooltip/index.tsx +12 -24
  109. package/src/components/feedback/index.tsx +54 -42
  110. package/src/components/form/Cascader/Cascader.styles.ts +2 -2
  111. package/src/components/form/Cascader/Cascader.tsx +84 -88
  112. package/src/components/form/Cascader/Cascader.types.ts +49 -50
  113. package/src/components/form/Cascader/hooks/useCascaderFieldNames.ts +11 -8
  114. package/src/components/form/Cascader/hooks/useCascaderOptions.ts +73 -55
  115. package/src/components/form/Cascader/hooks/useCascaderState.ts +31 -25
  116. package/src/components/form/Cascader/index.ts +1 -1
  117. package/src/components/form/Cascader/utils/formatDisplayValue.ts +4 -4
  118. package/src/components/form/Checkbox/Checkbox.styles.ts +83 -84
  119. package/src/components/form/Checkbox/Checkbox.tsx +2 -9
  120. package/src/components/form/Checkbox/CheckboxGroup.tsx +7 -7
  121. package/src/components/form/DatePicker/DatePicker.test.tsx +1 -1
  122. package/src/components/form/DatePicker/DatePicker.tsx +91 -75
  123. package/src/components/form/DatePicker/DatePicker.types.ts +4 -1
  124. package/src/components/form/Form/Form.tsx +66 -504
  125. package/src/components/form/Form/Form.types.ts +16 -1
  126. package/src/components/form/Form/useFormLogic.ts +497 -0
  127. package/src/components/form/Input/Input.styles.ts +8 -1
  128. package/src/components/form/Input/Input.tsx +55 -291
  129. package/src/components/form/Input/Input.types.ts +13 -1
  130. package/src/components/form/Input/useInputLogic.test.ts +82 -0
  131. package/src/components/form/Input/useInputLogic.ts +260 -0
  132. package/src/components/form/InputNumber/InputNumber.styles.ts +76 -25
  133. package/src/components/form/InputNumber/InputNumber.tsx +53 -21
  134. package/src/components/form/InputNumber/InputNumber.types.ts +21 -3
  135. package/src/components/form/InputNumber/components/InputNumberClearButton.tsx +3 -11
  136. package/src/components/form/InputNumber/components/InputNumberControls.tsx +3 -12
  137. package/src/components/form/InputNumber/hooks/index.ts +1 -1
  138. package/src/components/form/InputNumber/hooks/useInputNumberState.ts +7 -9
  139. package/src/components/form/InputNumber/hooks/useInputNumberValidation.ts +18 -17
  140. package/src/components/form/InputNumber/index.ts +7 -7
  141. package/src/components/form/Radio/Radio.styles.ts +1 -8
  142. package/src/components/form/Radio/Radio.tsx +3 -9
  143. package/src/components/form/Radio/Radio.types.ts +5 -1
  144. package/src/components/form/Select/Select.styles.ts +5 -1
  145. package/src/components/form/Select/Select.tsx +15 -15
  146. package/src/components/form/Select/Select.types.ts +2 -1
  147. package/src/components/form/Slider/Slider.styles.ts +13 -13
  148. package/src/components/form/Slider/Slider.tsx +19 -33
  149. package/src/components/form/Slider/Slider.types.ts +14 -12
  150. package/src/components/form/Slider/index.tsx +2 -9
  151. package/src/components/form/Switch/Switch.styles.ts +1 -7
  152. package/src/components/form/Switch/Switch.tsx +7 -13
  153. package/src/components/form/Textarea/Textarea.styles.ts +4 -4
  154. package/src/components/form/Textarea/Textarea.tsx +7 -1
  155. package/src/components/form/Textarea/Textarea.types.ts +4 -1
  156. package/src/components/form/TimePicker/TimePicker.styles.ts +8 -12
  157. package/src/components/form/TimePicker/TimePicker.tsx +122 -100
  158. package/src/components/form/TimePicker/TimePicker.types.ts +2 -2
  159. package/src/components/form/TimePicker/index.ts +1 -1
  160. package/src/components/form/Transfer/Transfer.styles.ts +3 -15
  161. package/src/components/form/Transfer/Transfer.tsx +146 -134
  162. package/src/components/form/Transfer/Transfer.types.ts +34 -26
  163. package/src/components/form/Transfer/components/TransferItem.tsx +55 -62
  164. package/src/components/form/Transfer/components/TransferList.tsx +212 -199
  165. package/src/components/form/Transfer/components/TransferOperations.tsx +52 -55
  166. package/src/components/form/Transfer/components/TransferPagination.tsx +115 -111
  167. package/src/components/form/Transfer/components/TransferSearch.tsx +52 -55
  168. package/src/components/form/Transfer/hooks/useTransferData.ts +91 -81
  169. package/src/components/form/Transfer/hooks/useTransferState.ts +22 -16
  170. package/src/components/form/Transfer/index.ts +2 -8
  171. package/src/components/form/Upload/Upload.styles.ts +21 -21
  172. package/src/components/form/Upload/Upload.tsx +189 -142
  173. package/src/components/form/Upload/Upload.types.ts +31 -31
  174. package/src/components/form/Upload/index.tsx +1 -1
  175. package/src/components/form/index.tsx +60 -29
  176. package/src/components/index.tsx +0 -1
  177. package/src/components/layout/Affix/Affix.styles.ts +16 -11
  178. package/src/components/layout/Affix/Affix.tsx +67 -75
  179. package/src/components/layout/Affix/Affix.types.ts +18 -18
  180. package/src/components/layout/Affix/index.tsx +1 -1
  181. package/src/components/layout/Col/Col.styles.ts +17 -17
  182. package/src/components/layout/Col/Col.test.tsx +7 -5
  183. package/src/components/layout/Col/Col.tsx +3 -21
  184. package/src/components/layout/Col/Col.types.ts +1 -1
  185. package/src/components/layout/Container/Container.styles.ts +3 -1
  186. package/src/components/layout/Container/Container.tsx +2 -11
  187. package/src/components/layout/Grid/Grid.tsx +3 -53
  188. package/src/components/layout/Layout/Content.tsx +24 -32
  189. package/src/components/layout/Layout/Footer.tsx +24 -32
  190. package/src/components/layout/Layout/Header.tsx +24 -32
  191. package/src/components/layout/Layout/Layout.styles.ts +17 -17
  192. package/src/components/layout/Layout/Layout.tsx +14 -25
  193. package/src/components/layout/Layout/Layout.types.ts +29 -29
  194. package/src/components/layout/Layout/Sider.tsx +44 -56
  195. package/src/components/layout/Layout/index.tsx +16 -2
  196. package/src/components/layout/Row/Row.tsx +15 -43
  197. package/src/components/layout/Space/Space.tsx +3 -11
  198. package/src/components/layout/Space/Space.types.ts +1 -1
  199. package/src/components/layout/index.tsx +29 -19
  200. package/src/components/navigation/Menu/Menu.constants.ts +69 -0
  201. package/src/components/navigation/Menu/Menu.stories.tsx +107 -0
  202. package/src/components/navigation/Menu/Menu.styles.ts +25 -37
  203. package/src/components/navigation/Menu/Menu.tsx +8 -11
  204. package/src/components/navigation/Menu/Menu.types.ts +2 -2
  205. package/src/components/navigation/Menu/Menu.utils.ts +17 -17
  206. package/src/components/navigation/Menu/MenuItem.tsx +9 -11
  207. package/src/components/navigation/Menu/SubMenu.tsx +8 -6
  208. package/src/components/navigation/Menu/index.tsx +4 -69
  209. package/src/components/navigation/NavBar/NavBar.styles.ts +1 -1
  210. package/src/components/navigation/NavBar/NavBar.tsx +7 -10
  211. package/src/components/navigation/NavBar/NavBar.types.ts +3 -3
  212. package/src/components/navigation/NavBar/index.tsx +1 -1
  213. package/src/components/navigation/Pagination/Pagination.test.tsx +2 -3
  214. package/src/components/navigation/Pagination/Pagination.tsx +3 -3
  215. package/src/components/navigation/Pagination/Pagination.types.ts +3 -2
  216. package/src/components/navigation/Pagination/index.ts +9 -3
  217. package/src/components/navigation/Steps/Step.tsx +24 -44
  218. package/src/components/navigation/Steps/Steps.styles.ts +28 -13
  219. package/src/components/navigation/Steps/Steps.test.tsx +2 -0
  220. package/src/components/navigation/Steps/Steps.tsx +88 -89
  221. package/src/components/navigation/Steps/Steps.types.ts +30 -30
  222. package/src/components/navigation/Steps/index.tsx +1 -1
  223. package/src/components/navigation/Tabs/Tabs.test.tsx +3 -2
  224. package/src/components/navigation/Tabs/Tabs.types.ts +4 -3
  225. package/src/components/navigation/index.tsx +21 -16
  226. package/src/constants/index.ts +1 -1
  227. package/src/hooks/index.ts +52 -102
  228. package/src/hooks/types.ts +4 -5
  229. package/src/hooks/useAsync.ts +46 -47
  230. package/src/hooks/useClickOutside.ts +52 -0
  231. package/src/hooks/useCounter.ts +87 -0
  232. package/src/hooks/useDebounce.ts +150 -0
  233. package/src/hooks/useDeepCompareEffect.ts +88 -0
  234. package/src/hooks/useEventListener.ts +77 -0
  235. package/src/hooks/useMediaQuery.ts +75 -0
  236. package/src/hooks/useMutation.ts +233 -0
  237. package/src/hooks/usePerformance.ts +1 -64
  238. package/src/hooks/usePlatform.ts +3 -1
  239. package/src/hooks/usePrevious.ts +25 -0
  240. package/src/hooks/useRequest.ts +12 -7
  241. package/src/hooks/useStateManagement.ts +1 -1
  242. package/src/hooks/useStorage.ts +169 -0
  243. package/src/hooks/useStyle.ts +8 -2
  244. package/src/hooks/useToggle.ts +54 -0
  245. package/src/index.ts +34 -9
  246. package/src/theme/ThemeProvider.tsx +3 -7
  247. package/src/theme/ThemeProvider.types.ts +1 -1
  248. package/src/theme/defaults.ts +1 -1
  249. package/src/theme/design-system.ts +2 -2
  250. package/src/theme/design-tokens.ts +85 -99
  251. package/src/theme/generated/dark-theme.scss +1 -1
  252. package/src/theme/generated/tokens.scss +82 -18
  253. package/src/theme/index.ts +8 -29
  254. package/src/theme/responsive.tsx +36 -34
  255. package/src/theme/styles.ts +1 -1
  256. package/src/theme/useThemeUtils.ts +43 -43
  257. package/src/theme/utils.ts +32 -32
  258. package/src/theme/variables.ts +70 -51
  259. package/src/types/accessibility.ts +36 -37
  260. package/src/types/button.ts +25 -27
  261. package/src/types/component-props.ts +6 -1
  262. package/src/types/glob.d.ts +4 -0
  263. package/src/types/index.ts +2 -2
  264. package/src/types/standardized-components.ts +9 -3
  265. package/src/types/utils.ts +13 -23
  266. package/src/utils/__tests__/responsiveUtils.test.ts +5 -4
  267. package/src/utils/abort-controller.ts +48 -0
  268. package/src/utils/cache.ts +2 -6
  269. package/src/utils/createNamespace.ts +4 -4
  270. package/src/utils/environment.ts +26 -6
  271. package/src/utils/error-handler.ts +2 -2
  272. package/src/utils/errorLogger.ts +16 -20
  273. package/src/utils/formatUtils.ts +38 -70
  274. package/src/utils/http/error-codes.ts +314 -0
  275. package/src/utils/http/http-client.test.ts +63 -0
  276. package/src/utils/{network → http}/http-client.ts +45 -35
  277. package/src/utils/http/request-cache.ts +127 -0
  278. package/src/utils/http/request.ts +954 -0
  279. package/src/utils/http/taro-adapter.test.ts +74 -0
  280. package/src/utils/http/taro-adapter.ts +24 -0
  281. package/src/utils/http/types.ts +414 -0
  282. package/src/utils/http/web-adapter.ts +33 -0
  283. package/src/utils/index.ts +5 -8
  284. package/src/utils/inputValidator.ts +17 -14
  285. package/src/utils/performance/performance.ts +60 -71
  286. package/src/utils/responsiveUtils.ts +7 -16
  287. package/src/utils/rtl-support.ts +29 -19
  288. package/src/utils/security/api-security.ts +47 -39
  289. package/src/utils/securityHeaders.ts +61 -67
  290. package/src/utils/typeHelpers.ts +10 -10
  291. package/src/utils/types/dataProcessing.ts +93 -92
  292. package/src/utils/types/typeHelpers.ts +31 -21
  293. package/src/utils/xssProtection.ts +96 -48
  294. package/dist/js/index-6NJ3A1Dn.js.map +0 -1
  295. package/dist/js/index-DffLRSro.js.map +0 -1
  296. package/src/components/form/Input/Input.enhanced.tsx +0 -732
  297. package/src/components/navigation/Menu/__tests__/Menu.test.tsx +0 -687
  298. package/src/components/navigation/Tree/Tree.styles.ts +0 -553
  299. package/src/components/navigation/Tree/Tree.test.basic.tsx +0 -7
  300. package/src/components/navigation/Tree/Tree.test.functional.tsx +0 -496
  301. package/src/components/navigation/Tree/Tree.test.import.check.tsx +0 -6
  302. package/src/components/navigation/Tree/Tree.test.import.tsx +0 -6
  303. package/src/components/navigation/Tree/Tree.test.minimal.tsx +0 -5
  304. package/src/components/navigation/Tree/Tree.test.simple.tsx +0 -30
  305. package/src/components/navigation/Tree/Tree.test.tsx +0 -908
  306. package/src/components/navigation/Tree/Tree.test.working.tsx +0 -673
  307. package/src/components/navigation/Tree/Tree.tsx +0 -600
  308. package/src/components/navigation/Tree/Tree.types.ts +0 -909
  309. package/src/components/navigation/Tree/Tree.utils.ts +0 -452
  310. package/src/components/navigation/Tree/index.ts +0 -33
  311. package/src/components/navigation/Tree/index.tsx +0 -23
  312. package/src/utils/network/http-client.test.ts +0 -18
@@ -1,908 +0,0 @@
1
- import React from 'react'
2
- import { render, screen, fireEvent, act } from '@testing-library/react'
3
- import { Tree } from '../Tree'
4
- import type { TreeProps, TreeRef, TreeNode } from '../Tree.types'
5
-
6
- // Mock Taro components
7
- vi.mock('@tarojs/components', () => ({
8
- View: ({ children, className, style, onClick, onLongPress, ...props }) => {
9
- return (
10
- <div
11
- className={className}
12
- style={style}
13
- onClick={onClick}
14
- onContextMenu={onLongPress}
15
- {...props}
16
- >
17
- {children}
18
- </div>
19
- )
20
- },
21
- Text: ({ children, className, style, ...props }) => {
22
- return (
23
- <span className={className} style={style} {...props}>
24
- {children}
25
- </span>
26
- )
27
- }
28
- }))
29
-
30
- // Mock the Tree styles
31
- vi.mock('../Tree.styles', () => ({
32
- getTreeStyles: (config: any) => ({
33
- tree: {
34
- backgroundColor: config.theme === 'dark' ? '#1f1f1f' : '#ffffff',
35
- borderRadius: '4px',
36
- padding: '8px',
37
- },
38
- getNodeIndent: (level: number) => ({
39
- paddingLeft: `${level * 20}px`,
40
- }),
41
- }),
42
- getTreeClassNames: (config: any) => ({
43
- tree: `taro-uno-tree taro-uno-tree--${config.size} taro-uno-tree--${config.theme} taro-uno-tree--${config.mode} ${config.disabled ? 'taro-uno-tree--disabled' : ''} ${config.className || ''}`,
44
- treeNode: 'taro-uno-tree-node',
45
- treeNodeContent: 'taro-uno-tree-node-content',
46
- treeNodeSwitcher: 'taro-uno-tree-node-switcher',
47
- treeNodeCheckbox: 'taro-uno-tree-node-checkbox',
48
- treeNodeIcon: 'taro-uno-tree-node-icon',
49
- treeNodeTitle: 'taro-uno-tree-node-title',
50
- expandIcon: 'taro-uno-tree-expand-icon',
51
- expandIconLeaf: 'taro-uno-tree-expand-icon-leaf',
52
- expandIconLoading: 'taro-uno-tree-expand-icon-loading',
53
- checkbox: 'taro-uno-tree-checkbox',
54
- checkboxChecked: 'taro-uno-tree-checkbox-checked',
55
- checkboxIndeterminate: 'taro-uno-tree-checkbox-indeterminate',
56
- icon: 'taro-uno-tree-icon',
57
- iconOpen: 'taro-uno-tree-icon-open',
58
- iconClose: 'taro-uno-tree-icon-close',
59
- loading: 'taro-uno-tree-loading',
60
- line: 'taro-uno-tree-line',
61
- checkboxInner: 'taro-uno-tree-checkbox-inner',
62
- }),
63
- }))
64
-
65
- // Mock the Tree utils
66
- vi.mock('../Tree.utils', () => ({
67
- TreeUtils: {
68
- flattenTreeNodes: (treeData: TreeNode[]) => {
69
- const result: TreeNode[] = []
70
- function traverse(nodes: TreeNode[]) {
71
- nodes.forEach(node => {
72
- result.push(node)
73
- if (node.children && node.children.length > 0) {
74
- traverse(node.children)
75
- }
76
- })
77
- }
78
- traverse(treeData)
79
- return result
80
- },
81
- getNodeByKey: (treeData: TreeNode[], key: string | number) => {
82
- function traverse(nodes: TreeNode[]): TreeNode | null {
83
- for (const node of nodes) {
84
- if (node.key === key) {
85
- return node
86
- }
87
- if (node.children && node.children.length > 0) {
88
- const found = traverse(node.children)
89
- if (found) return found
90
- }
91
- }
92
- return null
93
- }
94
- return traverse(treeData)
95
- },
96
- getNodesByKeys: (treeData: TreeNode[], keys: (string | number)[]) => {
97
- return keys
98
- .map(key => TreeUtils.getNodeByKey(treeData, key))
99
- .filter((node): node is TreeNode => node !== null)
100
- },
101
- getParentKeys: (treeData: TreeNode[], targetKeys: (string | number)[]) => {
102
- const parentKeys: Set<string | number> = new Set()
103
- function traverse(nodes: TreeNode[], parentKey?: string | number) {
104
- nodes.forEach(node => {
105
- if (targetKeys.includes(node.key) && parentKey !== undefined) {
106
- parentKeys.add(parentKey)
107
- }
108
- if (node.children && node.children.length > 0) {
109
- traverse(node.children, node.key)
110
- }
111
- })
112
- }
113
- traverse(treeData)
114
- return Array.from(parentKeys)
115
- },
116
- getCheckedKeys: (
117
- treeData: TreeNode[],
118
- key: string | number,
119
- checked: boolean,
120
- currentCheckedKeys: (string | number)[],
121
- currentHalfCheckedKeys: (string | number)[]
122
- ) => {
123
- const node = TreeUtils.getNodeByKey(treeData, key)
124
- if (!node) {
125
- return { checkedKeys: currentCheckedKeys, halfCheckedKeys: currentHalfCheckedKeys }
126
- }
127
-
128
- const checkedKeys = new Set(currentCheckedKeys)
129
- const halfCheckedKeys = new Set(currentHalfCheckedKeys)
130
-
131
- if (checked) {
132
- checkedKeys.add(key)
133
- // Add all children
134
- const addChildren = (node: TreeNode) => {
135
- if (node.children) {
136
- node.children.forEach(child => {
137
- checkedKeys.add(child.key)
138
- addChildren(child)
139
- })
140
- }
141
- }
142
- addChildren(node)
143
- } else {
144
- checkedKeys.delete(key)
145
- // Remove all children
146
- const removeChildren = (node: TreeNode) => {
147
- if (node.children) {
148
- node.children.forEach(child => {
149
- checkedKeys.delete(child.key)
150
- removeChildren(child)
151
- })
152
- }
153
- }
154
- removeChildren(node)
155
- }
156
-
157
- return {
158
- checkedKeys: Array.from(checkedKeys),
159
- halfCheckedKeys: Array.from(halfCheckedKeys),
160
- }
161
- },
162
- filterTreeNodes: (treeData: TreeNode[], filterFn: (node: TreeNode) => boolean) => {
163
- return treeData.filter(node => {
164
- if (filterFn(node)) return true
165
- if (node.children) {
166
- const filteredChildren = TreeUtils.filterTreeNodes(node.children, filterFn)
167
- if (filteredChildren.length > 0) {
168
- node.children = filteredChildren
169
- return true
170
- }
171
- }
172
- return false
173
- })
174
- },
175
- },
176
- }))
177
-
178
- // Sample tree data for testing
179
- const sampleTreeData: TreeNode[] = [
180
- {
181
- key: '1',
182
- title: 'Parent 1',
183
- children: [
184
- {
185
- key: '1-1',
186
- title: 'Child 1-1',
187
- },
188
- {
189
- key: '1-2',
190
- title: 'Child 1-2',
191
- children: [
192
- {
193
- key: '1-2-1',
194
- title: 'Grandchild 1-2-1',
195
- },
196
- ],
197
- },
198
- ],
199
- },
200
- {
201
- key: '2',
202
- title: 'Parent 2',
203
- children: [
204
- {
205
- key: '2-1',
206
- title: 'Child 2-1',
207
- },
208
- ],
209
- },
210
- ]
211
-
212
- describe('Tree Component', () => {
213
- const mockRef = React.createRef<TreeRef>()
214
-
215
- beforeEach(() => {
216
- vi.clearAllMocks()
217
- })
218
-
219
- describe('Rendering', () => {
220
- it('renders tree with default props', () => {
221
- render(<Tree treeData={sampleTreeData} data-testid="tree" />)
222
- const tree = screen.getByTestId('tree')
223
- expect(tree).toBeInTheDocument()
224
- expect(tree).toHaveClass('taro-uno-tree')
225
- })
226
-
227
- it('renders tree with custom size', () => {
228
- render(<Tree treeData={sampleTreeData} size="large" data-testid="tree" />)
229
- const tree = screen.getByTestId('tree')
230
- expect(tree).toBeInTheDocument()
231
- expect(tree).toHaveClass('taro-uno-tree--large')
232
- })
233
-
234
- it('renders tree with dark theme', () => {
235
- render(<Tree treeData={sampleTreeData} theme="dark" data-testid="tree" />)
236
- const tree = screen.getByTestId('tree')
237
- expect(tree).toBeInTheDocument()
238
- expect(tree).toHaveClass('taro-uno-tree--dark')
239
- })
240
-
241
- it('renders tree with directory mode', () => {
242
- render(<Tree treeData={sampleTreeData} mode="directory" data-testid="tree" />)
243
- const tree = screen.getByTestId('tree')
244
- expect(tree).toBeInTheDocument()
245
- expect(tree).toHaveClass('taro-uno-tree--directory')
246
- })
247
-
248
- it('renders tree with showLine', () => {
249
- render(<Tree treeData={sampleTreeData} showLine data-testid="tree" />)
250
- const tree = screen.getByTestId('tree')
251
- expect(tree).toBeInTheDocument()
252
- })
253
-
254
- it('renders tree without icons', () => {
255
- render(<Tree treeData={sampleTreeData} showIcon={false} data-testid="tree" />)
256
- const tree = screen.getByTestId('tree')
257
- expect(tree).toBeInTheDocument()
258
- })
259
-
260
- it('renders tree with block nodes', () => {
261
- render(<Tree treeData={sampleTreeData} blockNode data-testid="tree" />)
262
- const tree = screen.getByTestId('tree')
263
- expect(tree).toBeInTheDocument()
264
- })
265
-
266
- it('renders tree with checkable', () => {
267
- render(<Tree treeData={sampleTreeData} checkable data-testid="tree" />)
268
- const tree = screen.getByTestId('tree')
269
- expect(tree).toBeInTheDocument()
270
- })
271
-
272
- it('renders tree with checkStrictly', () => {
273
- render(<Tree treeData={sampleTreeData} checkable checkStrictly data-testid="tree" />)
274
- const tree = screen.getByTestId('tree')
275
- expect(tree).toBeInTheDocument()
276
- })
277
-
278
- it('renders tree without selection', () => {
279
- render(<Tree treeData={sampleTreeData} selectable={false} data-testid="tree" />)
280
- const tree = screen.getByTestId('tree')
281
- expect(tree).toBeInTheDocument()
282
- })
283
-
284
- it('renders tree with multiple selection', () => {
285
- render(<Tree treeData={sampleTreeData} multiple data-testid="tree" />)
286
- const tree = screen.getByTestId('tree')
287
- expect(tree).toBeInTheDocument()
288
- })
289
-
290
- it('renders tree with disabled state', () => {
291
- render(<Tree treeData={sampleTreeData} disabled data-testid="tree" />)
292
- const tree = screen.getByTestId('tree')
293
- expect(tree).toBeInTheDocument()
294
- expect(tree).toHaveClass('taro-uno-tree--disabled')
295
- })
296
-
297
- it('renders tree with custom className', () => {
298
- render(<Tree treeData={sampleTreeData} className="custom-tree" data-testid="tree" />)
299
- const tree = screen.getByTestId('tree')
300
- expect(tree).toBeInTheDocument()
301
- expect(tree).toHaveClass('custom-tree')
302
- })
303
-
304
- it('renders tree with custom style', () => {
305
- const customStyle = { backgroundColor: '#f0f0f0', padding: '16px' }
306
- render(<Tree treeData={sampleTreeData} style={customStyle} data-testid="tree" />)
307
- const tree = screen.getByTestId('tree')
308
- expect(tree).toBeInTheDocument()
309
- })
310
-
311
- it('renders empty tree gracefully', () => {
312
- render(<Tree treeData={[]} data-testid="tree" />)
313
- const tree = screen.getByTestId('tree')
314
- expect(tree).toBeInTheDocument()
315
- })
316
- })
317
-
318
- describe('Node Selection', () => {
319
- it('selects node on click', () => {
320
- const handleSelect = vi.fn()
321
- render(<Tree treeData={sampleTreeData} onSelect={handleSelect} data-testid="tree" />)
322
-
323
- const nodeTitle = screen.getByText('Parent 1')
324
- fireEvent.click(nodeTitle)
325
-
326
- expect(handleSelect).toHaveBeenCalled()
327
- })
328
-
329
- it('selects multiple nodes when multiple is true', () => {
330
- const handleSelect = vi.fn()
331
- render(<Tree treeData={sampleTreeData} multiple onSelect={handleSelect} data-testid="tree" />)
332
-
333
- const node1 = screen.getByText('Parent 1')
334
- const node2 = screen.getByText('Parent 2')
335
-
336
- fireEvent.click(node1)
337
- fireEvent.click(node2)
338
-
339
- expect(handleSelect).toHaveBeenCalledTimes(2)
340
- })
341
-
342
- it('does not select node when disabled', () => {
343
- const handleSelect = vi.fn()
344
- render(<Tree treeData={sampleTreeData} disabled onSelect={handleSelect} data-testid="tree" />)
345
-
346
- const nodeTitle = screen.getByText('Parent 1')
347
- fireEvent.click(nodeTitle)
348
-
349
- expect(handleSelect).not.toHaveBeenCalled()
350
- })
351
-
352
- it('does not select node when selectable is false', () => {
353
- const handleSelect = vi.fn()
354
- render(<Tree treeData={sampleTreeData} selectable={false} onSelect={handleSelect} data-testid="tree" />)
355
-
356
- const nodeTitle = screen.getByText('Parent 1')
357
- fireEvent.click(nodeTitle)
358
-
359
- expect(handleSelect).not.toHaveBeenCalled()
360
- })
361
- })
362
-
363
- describe('Node Expansion', () => {
364
- it('expands node on click', () => {
365
- const handleExpand = vi.fn()
366
- render(<Tree treeData={sampleTreeData} onExpand={handleExpand} data-testid="tree" />)
367
-
368
- const expandIcon = screen.getByText('▶')
369
- fireEvent.click(expandIcon)
370
-
371
- expect(handleExpand).toHaveBeenCalled()
372
- })
373
-
374
- it('expands all nodes when defaultExpandAll is true', () => {
375
- render(<Tree treeData={sampleTreeData} defaultExpandAll data-testid="tree" />)
376
- const tree = screen.getByTestId('tree')
377
- expect(tree).toBeInTheDocument()
378
- })
379
-
380
- it('expands parent nodes when defaultExpandParent is true', () => {
381
- render(<Tree treeData={sampleTreeData} defaultExpandedKeys={['1-2-1']} defaultExpandParent data-testid="tree" />)
382
- const tree = screen.getByTestId('tree')
383
- expect(tree).toBeInTheDocument()
384
- })
385
- })
386
-
387
- describe('Checkbox Behavior', () => {
388
- it('checks node when checkable is true', () => {
389
- const handleCheck = vi.fn()
390
- render(<Tree treeData={sampleTreeData} checkable onCheck={handleCheck} data-testid="tree" />)
391
-
392
- const checkbox = screen.getByRole('checkbox') || screen.getByText('✓').closest('div')
393
- if (checkbox) {
394
- fireEvent.click(checkbox)
395
- }
396
-
397
- expect(handleCheck).toHaveBeenCalled()
398
- })
399
-
400
- it('checks child nodes when parent is checked', () => {
401
- const handleCheck = vi.fn()
402
- render(<Tree treeData={sampleTreeData} checkable onCheck={handleCheck} data-testid="tree" />)
403
-
404
- const checkbox = screen.getByRole('checkbox') || screen.getByText('✓').closest('div')
405
- if (checkbox) {
406
- fireEvent.click(checkbox)
407
- }
408
-
409
- expect(handleCheck).toHaveBeenCalled()
410
- })
411
-
412
- it('handles checkStrictly mode', () => {
413
- const handleCheck = vi.fn()
414
- render(<Tree treeData={sampleTreeData} checkable checkStrictly onCheck={handleCheck} data-testid="tree" />)
415
-
416
- const checkbox = screen.getByRole('checkbox') || screen.getByText('✓').closest('div')
417
- if (checkbox) {
418
- fireEvent.click(checkbox)
419
- }
420
-
421
- expect(handleCheck).toHaveBeenCalled()
422
- })
423
- })
424
-
425
- describe('Controlled vs Uncontrolled', () => {
426
- it('works in controlled mode with selectedKeys', () => {
427
- const handleSelect = vi.fn()
428
- render(<Tree treeData={sampleTreeData} selectedKeys={['1']} onSelect={handleSelect} data-testid="tree" />)
429
-
430
- const nodeTitle = screen.getByText('Parent 1')
431
- fireEvent.click(nodeTitle)
432
-
433
- expect(handleSelect).toHaveBeenCalled()
434
- })
435
-
436
- it('works in uncontrolled mode with defaultSelectedKeys', () => {
437
- const handleSelect = vi.fn()
438
- render(<Tree treeData={sampleTreeData} defaultSelectedKeys={['1']} onSelect={handleSelect} data-testid="tree" />)
439
-
440
- const nodeTitle = screen.getByText('Parent 1')
441
- fireEvent.click(nodeTitle)
442
-
443
- expect(handleSelect).toHaveBeenCalled()
444
- })
445
-
446
- it('works in controlled mode with expandedKeys', () => {
447
- const handleExpand = vi.fn()
448
- render(<Tree treeData={sampleTreeData} expandedKeys={['1']} onExpand={handleExpand} data-testid="tree" />)
449
-
450
- const expandIcon = screen.getByText('▶')
451
- fireEvent.click(expandIcon)
452
-
453
- expect(handleExpand).toHaveBeenCalled()
454
- })
455
-
456
- it('works in uncontrolled mode with defaultExpandedKeys', () => {
457
- const handleExpand = vi.fn()
458
- render(<Tree treeData={sampleTreeData} defaultExpandedKeys={['1']} onExpand={handleExpand} data-testid="tree" />)
459
-
460
- const expandIcon = screen.getByText('▶')
461
- fireEvent.click(expandIcon)
462
-
463
- expect(handleExpand).toHaveBeenCalled()
464
- })
465
-
466
- it('works in controlled mode with checkedKeys', () => {
467
- const handleCheck = vi.fn()
468
- render(<Tree treeData={sampleTreeData} checkable checkedKeys={['1']} onCheck={handleCheck} data-testid="tree" />)
469
-
470
- const checkbox = screen.getByRole('checkbox') || screen.getByText('✓').closest('div')
471
- if (checkbox) {
472
- fireEvent.click(checkbox)
473
- }
474
-
475
- expect(handleCheck).toHaveBeenCalled()
476
- })
477
-
478
- it('works in uncontrolled mode with defaultCheckedKeys', () => {
479
- const handleCheck = vi.fn()
480
- render(<Tree treeData={sampleTreeData} checkable defaultCheckedKeys={['1']} onCheck={handleCheck} data-testid="tree" />)
481
-
482
- const checkbox = screen.getByRole('checkbox') || screen.getByText('✓').closest('div')
483
- if (checkbox) {
484
- fireEvent.click(checkbox)
485
- }
486
-
487
- expect(handleCheck).toHaveBeenCalled()
488
- })
489
- })
490
-
491
- describe('Ref API', () => {
492
- it('exposes ref methods correctly', () => {
493
- render(<Tree treeData={sampleTreeData} ref={mockRef} data-testid="tree" />)
494
-
495
- act(() => {
496
- expect(mockRef.current).toBeDefined()
497
- expect(mockRef.current?.getSelectedKeys()).toEqual([])
498
- expect(mockRef.current?.getExpandedKeys()).toEqual([])
499
- expect(mockRef.current?.getCheckedKeys()).toEqual([])
500
- expect(mockRef.current?.getTreeData()).toEqual(sampleTreeData)
501
- })
502
- })
503
-
504
- it('sets selected keys via ref method', () => {
505
- render(<Tree treeData={sampleTreeData} ref={mockRef} data-testid="tree" />)
506
-
507
- act(() => {
508
- if (mockRef.current) {
509
- mockRef.current.setSelectedKeys(['1'])
510
- expect(mockRef.current.getSelectedKeys()).toEqual(['1'])
511
- }
512
- })
513
- })
514
-
515
- it('sets expanded keys via ref method', () => {
516
- render(<Tree treeData={sampleTreeData} ref={mockRef} data-testid="tree" />)
517
-
518
- act(() => {
519
- if (mockRef.current) {
520
- mockRef.current.setExpandedKeys(['1'])
521
- expect(mockRef.current.getExpandedKeys()).toEqual(['1'])
522
- }
523
- })
524
- })
525
-
526
- it('sets checked keys via ref method', () => {
527
- render(<Tree treeData={sampleTreeData} checkable ref={mockRef} data-testid="tree" />)
528
-
529
- act(() => {
530
- if (mockRef.current) {
531
- mockRef.current.setCheckedKeys(['1'])
532
- expect(mockRef.current.getCheckedKeys()).toEqual(['1'])
533
- }
534
- })
535
- })
536
-
537
- it('expands node via ref method', () => {
538
- render(<Tree treeData={sampleTreeData} ref={mockRef} data-testid="tree" />)
539
-
540
- act(() => {
541
- if (mockRef.current) {
542
- mockRef.current.expandNode('1')
543
- expect(mockRef.current.getExpandedKeys()).toContain('1')
544
- }
545
- })
546
- })
547
-
548
- it('selects node via ref method', () => {
549
- render(<Tree treeData={sampleTreeData} ref={mockRef} data-testid="tree" />)
550
-
551
- act(() => {
552
- if (mockRef.current) {
553
- mockRef.current.selectNode('1')
554
- expect(mockRef.current.getSelectedKeys()).toContain('1')
555
- }
556
- })
557
- })
558
-
559
- it('checks node via ref method', () => {
560
- render(<Tree treeData={sampleTreeData} checkable ref={mockRef} data-testid="tree" />)
561
-
562
- act(() => {
563
- if (mockRef.current) {
564
- mockRef.current.checkNode('1')
565
- expect(mockRef.current.getCheckedKeys()).toContain('1')
566
- }
567
- })
568
- })
569
-
570
- it('expands all nodes via ref method', () => {
571
- render(<Tree treeData={sampleTreeData} ref={mockRef} data-testid="tree" />)
572
-
573
- act(() => {
574
- if (mockRef.current) {
575
- mockRef.current.expandAll()
576
- expect(mockRef.current.getExpandedKeys().length).toBeGreaterThan(0)
577
- }
578
- })
579
- })
580
-
581
- it('collapses all nodes via ref method', () => {
582
- render(<Tree treeData={sampleTreeData} ref={mockRef} data-testid="tree" />)
583
-
584
- act(() => {
585
- if (mockRef.current) {
586
- mockRef.current.collapseAll()
587
- expect(mockRef.current.getExpandedKeys()).toEqual([])
588
- }
589
- })
590
- })
591
-
592
- it('selects all nodes via ref method', () => {
593
- render(<Tree treeData={sampleTreeData} multiple ref={mockRef} data-testid="tree" />)
594
-
595
- act(() => {
596
- if (mockRef.current) {
597
- mockRef.current.selectAll()
598
- expect(mockRef.current.getSelectedKeys().length).toBeGreaterThan(0)
599
- }
600
- })
601
- })
602
-
603
- it('clears selection via ref method', () => {
604
- render(<Tree treeData={sampleTreeData} ref={mockRef} data-testid="tree" />)
605
-
606
- act(() => {
607
- if (mockRef.current) {
608
- mockRef.current.clearSelect()
609
- expect(mockRef.current.getSelectedKeys()).toEqual([])
610
- }
611
- })
612
- })
613
-
614
- it('checks all nodes via ref method', () => {
615
- render(<Tree treeData={sampleTreeData} checkable ref={mockRef} data-testid="tree" />)
616
-
617
- act(() => {
618
- if (mockRef.current) {
619
- mockRef.current.checkAll()
620
- expect(mockRef.current.getCheckedKeys().length).toBeGreaterThan(0)
621
- }
622
- })
623
- })
624
-
625
- it('clears checks via ref method', () => {
626
- render(<Tree treeData={sampleTreeData} checkable ref={mockRef} data-testid="tree" />)
627
-
628
- act(() => {
629
- if (mockRef.current) {
630
- mockRef.current.clearCheck()
631
- expect(mockRef.current.getCheckedKeys()).toEqual([])
632
- }
633
- })
634
- })
635
-
636
- it('finds node by key via ref method', () => {
637
- render(<Tree treeData={sampleTreeData} ref={mockRef} data-testid="tree" />)
638
-
639
- act(() => {
640
- if (mockRef.current) {
641
- const node = mockRef.current.findNode('1')
642
- expect(node).toBeDefined()
643
- expect(node?.key).toBe('1')
644
- }
645
- })
646
- })
647
-
648
- it('gets nodes by keys via ref method', () => {
649
- render(<Tree treeData={sampleTreeData} ref={mockRef} data-testid="tree" />)
650
-
651
- act(() => {
652
- if (mockRef.current) {
653
- const nodes = mockRef.current.getNodesByKeys(['1', '2'])
654
- expect(nodes).toHaveLength(2)
655
- }
656
- })
657
- })
658
-
659
- it('provides element access via ref', () => {
660
- render(<Tree treeData={sampleTreeData} ref={mockRef} data-testid="tree" />)
661
-
662
- act(() => {
663
- expect(mockRef.current?.element).toBeDefined()
664
- })
665
- })
666
- })
667
-
668
- describe('Accessibility', () => {
669
- it('has proper role attribute', () => {
670
- render(<Tree treeData={sampleTreeData} accessibilityRole="tree" data-testid="tree" />)
671
- const tree = screen.getByTestId('tree')
672
- expect(tree).toHaveAttribute('accessibilityRole', 'tree')
673
- })
674
-
675
- it('supports accessibilityLabel', () => {
676
- render(<Tree treeData={sampleTreeData} accessibilityLabel="Tree navigation" data-testid="tree" />)
677
- const tree = screen.getByTestId('tree')
678
- expect(tree).toHaveAttribute('accessibilityLabel', 'Tree navigation')
679
- })
680
-
681
- it('supports accessibilityState', () => {
682
- render(<Tree treeData={sampleTreeData} accessibilityState={{ disabled: true }} data-testid="tree" />)
683
- const tree = screen.getByTestId('tree')
684
- expect(tree).toHaveAttribute('accessibilityState', '{"disabled":true}')
685
- })
686
-
687
- it('supports data attributes', () => {
688
- render(<Tree treeData={sampleTreeData} data-testid="tree" data-custom="value" />)
689
- const tree = screen.getByTestId('tree')
690
- expect(tree).toHaveAttribute('data-custom', 'value')
691
- })
692
-
693
- it('supports accessible prop', () => {
694
- render(<Tree treeData={sampleTreeData} accessible={false} data-testid="tree" />)
695
- const tree = screen.getByTestId('tree')
696
- expect(tree).toHaveAttribute('accessible', 'false')
697
- })
698
- })
699
-
700
- describe('Custom Rendering', () => {
701
- it('renders custom icon', () => {
702
- const customIcon = () => <span data-testid="custom-icon">📁</span>
703
- render(<Tree treeData={sampleTreeData} icon={customIcon} data-testid="tree" />)
704
- const customIconElement = screen.getByTestId('custom-icon')
705
- expect(customIconElement).toBeInTheDocument()
706
- })
707
-
708
- it('renders custom switcher icon', () => {
709
- const customSwitcherIcon = () => <span data-testid="custom-switcher">+</span>
710
- render(<Tree treeData={sampleTreeData} switcherIcon={customSwitcherIcon} data-testid="tree" />)
711
- const customSwitcherElement = screen.getByTestId('custom-switcher')
712
- expect(customSwitcherElement).toBeInTheDocument()
713
- })
714
-
715
- it('renders custom title', () => {
716
- const titleRender = (node: TreeNode) => <span data-testid="custom-title">{node.title} - Custom</span>
717
- render(<Tree treeData={sampleTreeData} titleRender={titleRender} data-testid="tree" />)
718
- const customTitle = screen.getByTestId('custom-title')
719
- expect(customTitle).toBeInTheDocument()
720
- })
721
- })
722
-
723
- describe('Filter Functionality', () => {
724
- it('filters nodes based on filter function', () => {
725
- const filterTreeNode = (node: TreeNode) => node.key === '1'
726
- render(<Tree treeData={sampleTreeData} filterTreeNode={filterTreeNode} data-testid="tree" />)
727
- const tree = screen.getByTestId('tree')
728
- expect(tree).toBeInTheDocument()
729
- })
730
- })
731
-
732
- describe('Async Data Loading', () => {
733
- it('loads data asynchronously', async () => {
734
- const loadData = vi.fn().mockResolvedValue([])
735
- const onLoad = vi.fn()
736
- render(<Tree treeData={sampleTreeData} loadData={loadData} onLoad={onLoad} data-testid="tree" />)
737
-
738
- const expandIcon = screen.getByText('▶')
739
- fireEvent.click(expandIcon)
740
-
741
- await act(async () => {
742
- await vi.waitFor(() => {
743
- expect(loadData).toHaveBeenCalled()
744
- })
745
- })
746
- })
747
- })
748
-
749
- describe('Right Click', () => {
750
- it('handles right click events', () => {
751
- const handleRightClick = vi.fn()
752
- render(<Tree treeData={sampleTreeData} onRightClick={handleRightClick} data-testid="tree" />)
753
-
754
- const nodeTitle = screen.getByText('Parent 1')
755
- fireEvent.contextMenu(nodeTitle)
756
-
757
- expect(handleRightClick).toHaveBeenCalled()
758
- })
759
- })
760
-
761
- describe('Edge Cases', () => {
762
- it('handles undefined treeData gracefully', () => {
763
- render(<Tree treeData={undefined as any} data-testid="tree" />)
764
- const tree = screen.getByTestId('tree')
765
- expect(tree).toBeInTheDocument()
766
- })
767
-
768
- it('handles null treeData gracefully', () => {
769
- render(<Tree treeData={null as any} data-testid="tree" />)
770
- const tree = screen.getByTestId('tree')
771
- expect(tree).toBeInTheDocument()
772
- })
773
-
774
- it('handles treeData with invalid nodes gracefully', () => {
775
- const invalidTreeData = [
776
- { key: '1', title: 'Valid Node' },
777
- { key: null, title: 'Invalid Node' },
778
- { title: 'Node without key' },
779
- ] as any
780
- render(<Tree treeData={invalidTreeData} data-testid="tree" />)
781
- const tree = screen.getByTestId('tree')
782
- expect(tree).toBeInTheDocument()
783
- })
784
-
785
- it('handles very large tree data', () => {
786
- const largeTreeData = Array.from({ length: 1000 }, (_, i) => ({
787
- key: i,
788
- title: `Node ${i}`,
789
- }))
790
- render(<Tree treeData={largeTreeData} data-testid="tree" />)
791
- const tree = screen.getByTestId('tree')
792
- expect(tree).toBeInTheDocument()
793
- })
794
-
795
- it('handles deeply nested tree structure', () => {
796
- const deepTreeData = {
797
- key: '1',
798
- title: 'Root',
799
- children: Array.from({ length: 10 }, (_, i) => ({
800
- key: `1-${i}`,
801
- title: `Level 1-${i}`,
802
- children: Array.from({ length: 10 }, (_, j) => ({
803
- key: `1-${i}-${j}`,
804
- title: `Level 2-${i}-${j}`,
805
- })),
806
- })),
807
- }
808
- render(<Tree treeData={[deepTreeData]} data-testid="tree" />)
809
- const tree = screen.getByTestId('tree')
810
- expect(tree).toBeInTheDocument()
811
- })
812
- })
813
-
814
- describe('Performance', () => {
815
- it('renders efficiently with many nodes', () => {
816
- const largeTreeData = Array.from({ length: 100 }, (_, i) => ({
817
- key: i,
818
- title: `Node ${i}`,
819
- children: Array.from({ length: 5 }, (_, j) => ({
820
- key: `${i}-${j}`,
821
- title: `Child ${i}-${j}`,
822
- })),
823
- }))
824
- render(<Tree treeData={largeTreeData} data-testid="tree" />)
825
- const tree = screen.getByTestId('tree')
826
- expect(tree).toBeInTheDocument()
827
- })
828
-
829
- it('handles frequent prop updates efficiently', () => {
830
- const { rerender } = render(<Tree treeData={sampleTreeData} selectedKeys={['1']} data-testid="tree" />)
831
-
832
- for (let i = 0; i < 10; i++) {
833
- rerender(<Tree treeData={sampleTreeData} selectedKeys={[i.toString()]} data-testid="tree" />)
834
- }
835
-
836
- expect(screen.getByTestId('tree')).toBeInTheDocument()
837
- })
838
- })
839
-
840
- describe('Style Application', () => {
841
- it('applies custom styles correctly', () => {
842
- const customStyle = { backgroundColor: '#ff0000', color: '#ffffff' }
843
- render(<Tree treeData={sampleTreeData} style={customStyle} data-testid="tree" />)
844
- const tree = screen.getByTestId('tree')
845
- expect(tree).toHaveStyle('background-color: #ff0000')
846
- expect(tree).toHaveStyle('color: #ffffff')
847
- })
848
-
849
- it('applies theme-specific styles', () => {
850
- render(<Tree treeData={sampleTreeData} theme="dark" data-testid="tree" />)
851
- const tree = screen.getByTestId('tree')
852
- expect(tree).toHaveClass('taro-uno-tree--dark')
853
- })
854
-
855
- it('applies size-specific styles', () => {
856
- render(<Tree treeData={sampleTreeData} size="large" data-testid="tree" />)
857
- const tree = screen.getByTestId('tree')
858
- expect(tree).toHaveClass('taro-uno-tree--large')
859
- })
860
- })
861
-
862
- describe('Event Handling', () => {
863
- it('handles all tree events correctly', () => {
864
- const handleExpand = vi.fn()
865
- const handleSelect = vi.fn()
866
- const handleCheck = vi.fn()
867
- const handleRightClick = vi.fn()
868
-
869
- render(
870
- <Tree
871
- treeData={sampleTreeData}
872
- checkable
873
- onExpand={handleExpand}
874
- onSelect={handleSelect}
875
- onCheck={handleCheck}
876
- onRightClick={handleRightClick}
877
- data-testid="tree"
878
- />
879
- )
880
-
881
- const nodeTitle = screen.getByText('Parent 1')
882
- fireEvent.click(nodeTitle)
883
- fireEvent.contextMenu(nodeTitle)
884
-
885
- expect(handleSelect).toHaveBeenCalled()
886
- expect(handleRightClick).toHaveBeenCalled()
887
- })
888
-
889
- it('stops event propagation correctly', () => {
890
- const handleExpand = vi.fn()
891
- const handleSelect = vi.fn()
892
-
893
- render(
894
- <Tree
895
- treeData={sampleTreeData}
896
- onExpand={handleExpand}
897
- onSelect={handleSelect}
898
- data-testid="tree"
899
- />
900
- )
901
-
902
- const expandIcon = screen.getByText('▶')
903
- fireEvent.click(expandIcon)
904
-
905
- expect(handleExpand).toHaveBeenCalled()
906
- })
907
- })
908
- })