@carto/ps-react-ui 4.3.3 → 4.3.5

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 (301) hide show
  1. package/dist/components.js +3 -3
  2. package/dist/components.js.map +1 -1
  3. package/dist/{lasso-tool-BwRzEW7k.js → lasso-tool-wFqOD6wk.js} +13 -13
  4. package/dist/lasso-tool-wFqOD6wk.js.map +1 -0
  5. package/dist/types/components/common-types.d.ts +41 -0
  6. package/dist/types/components/types.d.ts +1 -1
  7. package/dist/types/widgets/echart/echart-ui.d.ts +1 -1
  8. package/dist/types/widgets/echart/types.d.ts +4 -0
  9. package/dist/widgets/actions.js +1 -1
  10. package/dist/widgets/bar.js +1 -1
  11. package/dist/widgets/category.js +1 -1
  12. package/dist/widgets/echart.js +96 -85
  13. package/dist/widgets/echart.js.map +1 -1
  14. package/dist/widgets/formula.js +1 -1
  15. package/dist/widgets/histogram.js +1 -1
  16. package/dist/widgets/markdown.js +1 -1
  17. package/dist/widgets/pie.js +1 -1
  18. package/dist/widgets/scatterplot.js +1 -1
  19. package/dist/widgets/spread.js +1 -1
  20. package/dist/widgets/table.js +1 -1
  21. package/dist/widgets/timeseries.js +1 -1
  22. package/dist/widgets/toolbar-actions.js.map +1 -1
  23. package/dist/widgets/wrapper.js +1 -1
  24. package/package.json +8 -3
  25. package/src/components/basemaps/basemaps.test.tsx +196 -0
  26. package/src/components/basemaps/basemaps.tsx +128 -0
  27. package/src/components/basemaps/const.ts +13 -0
  28. package/src/components/basemaps/group-wrapper.test.tsx +38 -0
  29. package/src/components/basemaps/group-wrapper.tsx +28 -0
  30. package/src/components/basemaps/group.test.tsx +52 -0
  31. package/src/components/basemaps/group.tsx +42 -0
  32. package/src/components/basemaps/header.test.tsx +54 -0
  33. package/src/components/basemaps/header.tsx +36 -0
  34. package/src/components/basemaps/styles.ts +76 -0
  35. package/src/components/basemaps/types.ts +30 -0
  36. package/src/components/common-types.ts +1 -0
  37. package/src/components/geolocation-controls/const.ts +6 -0
  38. package/src/components/geolocation-controls/geolocation-controls.test.tsx +133 -0
  39. package/src/components/geolocation-controls/geolocation-controls.tsx +95 -0
  40. package/src/components/geolocation-controls/types.ts +17 -0
  41. package/src/components/index.ts +64 -0
  42. package/src/components/lasso-tool/chip.tsx +37 -0
  43. package/src/components/lasso-tool/const.tsx +70 -0
  44. package/src/components/lasso-tool/icons.tsx +91 -0
  45. package/src/components/lasso-tool/lasso-tool-inline.test.tsx +168 -0
  46. package/src/components/lasso-tool/lasso-tool-inline.tsx +245 -0
  47. package/src/components/lasso-tool/lasso-tool.test.tsx +212 -0
  48. package/src/components/lasso-tool/lasso-tool.tsx +479 -0
  49. package/src/components/lasso-tool/styles.ts +143 -0
  50. package/src/components/lasso-tool/types.ts +114 -0
  51. package/src/components/list-data/list-data-skeleton.test.tsx +10 -0
  52. package/src/components/list-data/list-data-skeleton.tsx +40 -0
  53. package/src/components/list-data/list-data.test.tsx +94 -0
  54. package/src/components/list-data/list-data.tsx +106 -0
  55. package/src/components/list-data/styles.ts +37 -0
  56. package/src/components/list-data/types.ts +25 -0
  57. package/src/components/measurement-tools/const.tsx +108 -0
  58. package/src/components/measurement-tools/icons.tsx +54 -0
  59. package/src/components/measurement-tools/measurement-tools.test.tsx +165 -0
  60. package/src/components/measurement-tools/measurement-tools.tsx +443 -0
  61. package/src/components/measurement-tools/styles.ts +91 -0
  62. package/src/components/measurement-tools/types.ts +77 -0
  63. package/src/components/no-data-alert/no-data-alert.test.tsx +31 -0
  64. package/src/components/no-data-alert/no-data-alert.tsx +59 -0
  65. package/src/components/responsive-drawer/responsive-drawer.test.tsx +91 -0
  66. package/src/components/responsive-drawer/responsive-drawer.tsx +53 -0
  67. package/src/components/smart-tooltip/smart-tooltip.test.tsx +168 -0
  68. package/src/components/smart-tooltip/smart-tooltip.tsx +40 -0
  69. package/src/components/tooltip/tooltip.test.tsx +86 -0
  70. package/src/components/tooltip/tooltip.tsx +30 -0
  71. package/src/components/types.ts +1 -0
  72. package/src/components/zoom-controls/styles.ts +27 -0
  73. package/src/components/zoom-controls/types.ts +19 -0
  74. package/src/components/zoom-controls/zoom-controls.test.tsx +101 -0
  75. package/src/components/zoom-controls/zoom-controls.tsx +114 -0
  76. package/src/hooks/index.ts +2 -0
  77. package/src/hooks/use-debounce.ts +55 -0
  78. package/src/hooks/use-skeleton.test.tsx +32 -0
  79. package/src/hooks/use-skeleton.ts +19 -0
  80. package/src/hooks/use-widget-ref.ts +33 -0
  81. package/src/widgets/README.md +277 -0
  82. package/src/widgets/_shared/chart-config/config-factory.ts +67 -0
  83. package/src/widgets/_shared/chart-config/csv-modifiers.ts +56 -0
  84. package/src/widgets/_shared/chart-config/index.ts +21 -0
  85. package/src/widgets/_shared/chart-config/option-builders.ts +203 -0
  86. package/src/widgets/_shared/skeleton/index.ts +5 -0
  87. package/src/widgets/_shared/skeleton/styles.ts +20 -0
  88. package/src/widgets/actions/change-column/change-column-icon.tsx +10 -0
  89. package/src/widgets/actions/change-column/change-column.test.tsx +163 -0
  90. package/src/widgets/actions/change-column/change-column.tsx +141 -0
  91. package/src/widgets/actions/change-column/sortable-column-item.tsx +49 -0
  92. package/src/widgets/actions/change-column/types.ts +20 -0
  93. package/src/widgets/actions/download/download.test.tsx +322 -0
  94. package/src/widgets/actions/download/download.tsx +118 -0
  95. package/src/widgets/actions/download/exports.test.tsx +275 -0
  96. package/src/widgets/actions/download/exports.tsx +103 -0
  97. package/src/widgets/actions/download/types.ts +21 -0
  98. package/src/widgets/actions/fullscreen/fullscreen.test.tsx +269 -0
  99. package/src/widgets/actions/fullscreen/fullscreen.tsx +82 -0
  100. package/src/widgets/actions/fullscreen/styles.ts +17 -0
  101. package/src/widgets/actions/fullscreen/types.ts +27 -0
  102. package/src/widgets/actions/index.ts +51 -0
  103. package/src/widgets/actions/lock-selection/lock-selection.test.tsx +186 -0
  104. package/src/widgets/actions/lock-selection/lock-selection.tsx +133 -0
  105. package/src/widgets/actions/lock-selection/types.ts +41 -0
  106. package/src/widgets/actions/relative-data/relative-data.test.tsx +267 -0
  107. package/src/widgets/actions/relative-data/relative-data.tsx +133 -0
  108. package/src/widgets/actions/relative-data/style.ts +9 -0
  109. package/src/widgets/actions/relative-data/types.ts +31 -0
  110. package/src/widgets/actions/relative-data/utils.test.ts +223 -0
  111. package/src/widgets/actions/relative-data/utils.ts +58 -0
  112. package/src/widgets/actions/searcher/searcher-toggle.test.tsx +354 -0
  113. package/src/widgets/actions/searcher/searcher-toggle.tsx +73 -0
  114. package/src/widgets/actions/searcher/searcher.tsx +205 -0
  115. package/src/widgets/actions/searcher/types.ts +72 -0
  116. package/src/widgets/actions/shared/styles.ts +12 -0
  117. package/src/widgets/actions/stack-toggle/grouped-bar-chart-icon.tsx +14 -0
  118. package/src/widgets/actions/stack-toggle/stack-toggle.test.tsx +270 -0
  119. package/src/widgets/actions/stack-toggle/stack-toggle.tsx +146 -0
  120. package/src/widgets/actions/stack-toggle/types.ts +29 -0
  121. package/src/widgets/actions/zoom-toggle/index.ts +2 -0
  122. package/src/widgets/actions/zoom-toggle/style.ts +14 -0
  123. package/src/widgets/actions/zoom-toggle/types.ts +44 -0
  124. package/src/widgets/actions/zoom-toggle/zoom-toggle.tsx +186 -0
  125. package/src/widgets/bar/config.ts +122 -0
  126. package/src/widgets/bar/index.ts +9 -0
  127. package/src/widgets/bar/skeleton.tsx +60 -0
  128. package/src/widgets/bar/style.ts +33 -0
  129. package/src/widgets/bar/types.ts +16 -0
  130. package/src/widgets/category/category-ui.test.tsx +399 -0
  131. package/src/widgets/category/category-ui.tsx +156 -0
  132. package/src/widgets/category/components/category-bar.tsx +28 -0
  133. package/src/widgets/category/components/category-legend.tsx +30 -0
  134. package/src/widgets/category/components/category-row-multi.tsx +50 -0
  135. package/src/widgets/category/components/category-row-other.tsx +23 -0
  136. package/src/widgets/category/components/category-row-single.tsx +47 -0
  137. package/src/widgets/category/components/index.ts +14 -0
  138. package/src/widgets/category/config.ts +85 -0
  139. package/src/widgets/category/index.ts +30 -0
  140. package/src/widgets/category/skeleton.tsx +24 -0
  141. package/src/widgets/category/style.ts +133 -0
  142. package/src/widgets/category/types.ts +40 -0
  143. package/src/widgets/echart/const.ts +1 -0
  144. package/src/widgets/echart/echart-ui.test.tsx +537 -0
  145. package/src/widgets/echart/echart-ui.tsx +92 -0
  146. package/src/widgets/echart/echart.test.tsx +562 -0
  147. package/src/widgets/echart/echart.tsx +68 -0
  148. package/src/widgets/echart/index.ts +16 -0
  149. package/src/widgets/echart/options.ts +53 -0
  150. package/src/widgets/echart/types.ts +45 -0
  151. package/src/widgets/echart/utils.ts +169 -0
  152. package/src/widgets/error/error.test.tsx +331 -0
  153. package/src/widgets/error/error.tsx +40 -0
  154. package/src/widgets/error/index.ts +2 -0
  155. package/src/widgets/error/types.ts +14 -0
  156. package/src/widgets/formula/components/item.test.tsx +249 -0
  157. package/src/widgets/formula/components/item.tsx +18 -0
  158. package/src/widgets/formula/components/prefix.test.tsx +341 -0
  159. package/src/widgets/formula/components/prefix.tsx +18 -0
  160. package/src/widgets/formula/components/row.test.tsx +364 -0
  161. package/src/widgets/formula/components/row.tsx +21 -0
  162. package/src/widgets/formula/components/series.tsx +34 -0
  163. package/src/widgets/formula/components/suffix.test.tsx +383 -0
  164. package/src/widgets/formula/components/suffix.tsx +28 -0
  165. package/src/widgets/formula/components/value.test.tsx +329 -0
  166. package/src/widgets/formula/components/value.tsx +29 -0
  167. package/src/widgets/formula/config.ts +27 -0
  168. package/src/widgets/formula/formula-ui.test.tsx +399 -0
  169. package/src/widgets/formula/formula-ui.tsx +27 -0
  170. package/src/widgets/formula/index.ts +24 -0
  171. package/src/widgets/formula/serializer.test.tsx +144 -0
  172. package/src/widgets/formula/serializer.ts +28 -0
  173. package/src/widgets/formula/skeleton.tsx +10 -0
  174. package/src/widgets/formula/style.ts +23 -0
  175. package/src/widgets/formula/types.ts +50 -0
  176. package/src/widgets/histogram/config.ts +143 -0
  177. package/src/widgets/histogram/index.ts +8 -0
  178. package/src/widgets/histogram/skeleton.tsx +52 -0
  179. package/src/widgets/histogram/style.ts +8 -0
  180. package/src/widgets/histogram/types.ts +17 -0
  181. package/src/widgets/index.ts +25 -0
  182. package/src/widgets/loader/index.ts +4 -0
  183. package/src/widgets/loader/loader.tsx +70 -0
  184. package/src/widgets/loader/types.ts +11 -0
  185. package/src/widgets/loader/utils.test.ts +112 -0
  186. package/src/widgets/loader/utils.ts +35 -0
  187. package/src/widgets/markdown/config.ts +18 -0
  188. package/src/widgets/markdown/index.ts +14 -0
  189. package/src/widgets/markdown/markdown-ui.test.tsx +341 -0
  190. package/src/widgets/markdown/markdown-ui.tsx +52 -0
  191. package/src/widgets/markdown/markdown.tsx +20 -0
  192. package/src/widgets/markdown/skeleton.tsx +12 -0
  193. package/src/widgets/markdown/style.ts +28 -0
  194. package/src/widgets/markdown/types.ts +28 -0
  195. package/src/widgets/no-data/index.ts +2 -0
  196. package/src/widgets/no-data/no-data.test.tsx +447 -0
  197. package/src/widgets/no-data/no-data.tsx +116 -0
  198. package/src/widgets/no-data/style.ts +18 -0
  199. package/src/widgets/no-data/types.ts +72 -0
  200. package/src/widgets/note/index.ts +2 -0
  201. package/src/widgets/note/note.test.tsx +391 -0
  202. package/src/widgets/note/note.tsx +114 -0
  203. package/src/widgets/note/style.ts +29 -0
  204. package/src/widgets/note/types.ts +9 -0
  205. package/src/widgets/pie/config.ts +177 -0
  206. package/src/widgets/pie/index.ts +8 -0
  207. package/src/widgets/pie/skeleton.tsx +70 -0
  208. package/src/widgets/pie/style.ts +8 -0
  209. package/src/widgets/pie/types.ts +16 -0
  210. package/src/widgets/range/components/range-item.tsx +213 -0
  211. package/src/widgets/range/config.ts +10 -0
  212. package/src/widgets/range/index.ts +16 -0
  213. package/src/widgets/range/range-ui.test.tsx +203 -0
  214. package/src/widgets/range/range-ui.tsx +11 -0
  215. package/src/widgets/range/serializer.test.ts +70 -0
  216. package/src/widgets/range/serializer.ts +27 -0
  217. package/src/widgets/range/skeleton.tsx +14 -0
  218. package/src/widgets/range/style.ts +37 -0
  219. package/src/widgets/range/types.ts +39 -0
  220. package/src/widgets/scatterplot/config.ts +138 -0
  221. package/src/widgets/scatterplot/index.ts +8 -0
  222. package/src/widgets/scatterplot/skeleton.tsx +59 -0
  223. package/src/widgets/scatterplot/style.ts +21 -0
  224. package/src/widgets/scatterplot/types.ts +17 -0
  225. package/src/widgets/selection-summary/index.ts +6 -0
  226. package/src/widgets/selection-summary/selection-summary.tsx +46 -0
  227. package/src/widgets/selection-summary/style.ts +10 -0
  228. package/src/widgets/selection-summary/types.ts +14 -0
  229. package/src/widgets/skeleton-loader/index.ts +2 -0
  230. package/src/widgets/skeleton-loader/skeleton-loader.test.tsx +139 -0
  231. package/src/widgets/skeleton-loader/skeleton-loader.tsx +28 -0
  232. package/src/widgets/skeleton-loader/types.ts +8 -0
  233. package/src/widgets/spread/components/max-value.tsx +29 -0
  234. package/src/widgets/spread/components/min-value.tsx +29 -0
  235. package/src/widgets/spread/components/separator.tsx +6 -0
  236. package/src/widgets/spread/config.ts +34 -0
  237. package/src/widgets/spread/index.ts +23 -0
  238. package/src/widgets/spread/skeleton.tsx +10 -0
  239. package/src/widgets/spread/spread-ui.test.tsx +368 -0
  240. package/src/widgets/spread/spread-ui.tsx +29 -0
  241. package/src/widgets/spread/style.ts +22 -0
  242. package/src/widgets/spread/types.ts +47 -0
  243. package/src/widgets/stores/index.ts +9 -0
  244. package/src/widgets/stores/types.ts +192 -0
  245. package/src/widgets/stores/widget-store.test.ts +601 -0
  246. package/src/widgets/stores/widget-store.ts +239 -0
  247. package/src/widgets/subheader/index.ts +3 -0
  248. package/src/widgets/subheader/style.ts +20 -0
  249. package/src/widgets/subheader/subheader.test.tsx +45 -0
  250. package/src/widgets/subheader/subheader.tsx +16 -0
  251. package/src/widgets/subheader/types.ts +11 -0
  252. package/src/widgets/table/components/cell-header.tsx +58 -0
  253. package/src/widgets/table/components/cell.tsx +80 -0
  254. package/src/widgets/table/components/index.ts +4 -0
  255. package/src/widgets/table/components/pagination-actions.tsx +67 -0
  256. package/src/widgets/table/components/pagination.tsx +41 -0
  257. package/src/widgets/table/components/row.tsx +60 -0
  258. package/src/widgets/table/config.ts +71 -0
  259. package/src/widgets/table/helpers.test.ts +244 -0
  260. package/src/widgets/table/helpers.ts +107 -0
  261. package/src/widgets/table/hooks/index.ts +7 -0
  262. package/src/widgets/table/hooks/use-pagination.test.ts +294 -0
  263. package/src/widgets/table/hooks/use-pagination.ts +155 -0
  264. package/src/widgets/table/hooks/use-selection.test.ts +504 -0
  265. package/src/widgets/table/hooks/use-selection.ts +189 -0
  266. package/src/widgets/table/hooks/use-sort.test.ts +296 -0
  267. package/src/widgets/table/hooks/use-sort.ts +138 -0
  268. package/src/widgets/table/index.ts +53 -0
  269. package/src/widgets/table/serializer.ts +54 -0
  270. package/src/widgets/table/skeleton.tsx +48 -0
  271. package/src/widgets/table/style.ts +34 -0
  272. package/src/widgets/table/table-ui.tsx +64 -0
  273. package/src/widgets/table/types.ts +223 -0
  274. package/src/widgets/timeseries/config.ts +135 -0
  275. package/src/widgets/timeseries/index.ts +8 -0
  276. package/src/widgets/timeseries/skeleton.tsx +55 -0
  277. package/src/widgets/timeseries/style.ts +36 -0
  278. package/src/widgets/timeseries/types.ts +17 -0
  279. package/src/widgets/toolbar-actions/index.ts +6 -0
  280. package/src/widgets/toolbar-actions/styles.ts +38 -0
  281. package/src/widgets/toolbar-actions/toolbar-actions.test.tsx +691 -0
  282. package/src/widgets/toolbar-actions/toolbar-actions.tsx +145 -0
  283. package/src/widgets/toolbar-actions/types.ts +60 -0
  284. package/src/widgets/wrapper/components/actions.test.tsx +101 -0
  285. package/src/widgets/wrapper/components/actions.tsx +30 -0
  286. package/src/widgets/wrapper/components/options.test.tsx +323 -0
  287. package/src/widgets/wrapper/components/options.tsx +73 -0
  288. package/src/widgets/wrapper/components/title.test.tsx +126 -0
  289. package/src/widgets/wrapper/components/title.tsx +32 -0
  290. package/src/widgets/wrapper/index.ts +16 -0
  291. package/src/widgets/wrapper/styles.ts +98 -0
  292. package/src/widgets/wrapper/types.ts +55 -0
  293. package/src/widgets/wrapper/wrapper-ui.test.tsx +232 -0
  294. package/src/widgets/wrapper/wrapper-ui.tsx +57 -0
  295. package/src/widgets/wrapper/wrapper.test.tsx +365 -0
  296. package/src/widgets/wrapper/wrapper.tsx +50 -0
  297. package/dist/lasso-tool-BwRzEW7k.js.map +0 -1
  298. package/dist/types/common/common.d.ts +0 -3
  299. package/dist/types/common/index.d.ts +0 -26
  300. package/dist/types/common/lasso-tools.d.ts +0 -36
  301. package/dist/types/common/measurement-tools.d.ts +0 -65
@@ -0,0 +1,691 @@
1
+ import { describe, test, expect } from 'vitest'
2
+ import { render, screen, fireEvent } from '@testing-library/react'
3
+ import { ToolbarActions } from './toolbar-actions'
4
+ import { IconButton, Divider } from '@mui/material'
5
+ import { Tooltip } from '../../components/tooltip/tooltip'
6
+ import {
7
+ FileDownloadOutlined,
8
+ ShareOutlined,
9
+ EditOutlined,
10
+ FilterListOutlined,
11
+ } from '@mui/icons-material'
12
+
13
+ describe('ToolbarActions', () => {
14
+ const createAction = (
15
+ key: string,
16
+ label: string,
17
+ Icon: React.ComponentType,
18
+ ) => (
19
+ <Tooltip key={key} title={label}>
20
+ <IconButton size='small' aria-label={label}>
21
+ <Icon />
22
+ </IconButton>
23
+ </Tooltip>
24
+ )
25
+
26
+ describe('data-toolbar-hidden filtering', () => {
27
+ test('filters children with data-toolbar-hidden from visible count', () => {
28
+ const children = [
29
+ createAction('download', 'Download', FileDownloadOutlined),
30
+ <Divider
31
+ key='divider-1'
32
+ orientation='vertical'
33
+ flexItem
34
+ data-toolbar-hidden
35
+ />,
36
+ createAction('share', 'Share', ShareOutlined),
37
+ <Divider
38
+ key='divider-2'
39
+ orientation='vertical'
40
+ flexItem
41
+ data-toolbar-hidden
42
+ />,
43
+ createAction('edit', 'Edit', EditOutlined),
44
+ ]
45
+
46
+ render(<ToolbarActions visibleCount={2}>{children}</ToolbarActions>)
47
+
48
+ // Should show trigger button because there are 3 visible actions (download, share, edit)
49
+ // even though total children count is 5
50
+ const triggerButton = screen.getByRole('button', {
51
+ name: /more actions/i,
52
+ })
53
+ expect(triggerButton).toBeTruthy()
54
+
55
+ // Preview should include first 2 visible actions plus divider between them
56
+ // (Download, Divider, Share - stops after counting 2 non-hidden actions)
57
+ const downloadButtons = screen.getAllByLabelText('Download')
58
+ const shareButtons = screen.getAllByLabelText('Share')
59
+ expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
60
+ expect(shareButtons.length).toBeGreaterThanOrEqual(1)
61
+
62
+ // Edit button should also be present (in the expanded section)
63
+ const editButtons = screen.getAllByLabelText('Edit')
64
+ expect(editButtons.length).toBeGreaterThanOrEqual(1)
65
+ })
66
+
67
+ test('includes data-toolbar-hidden children in preview between visible actions', () => {
68
+ const children = [
69
+ createAction('download', 'Download', FileDownloadOutlined),
70
+ <Divider
71
+ key='divider-1'
72
+ orientation='vertical'
73
+ flexItem
74
+ data-toolbar-hidden
75
+ data-testid='divider-1'
76
+ />,
77
+ createAction('share', 'Share', ShareOutlined),
78
+ <Divider
79
+ key='divider-2'
80
+ orientation='vertical'
81
+ flexItem
82
+ data-toolbar-hidden
83
+ data-testid='divider-2'
84
+ />,
85
+ createAction('edit', 'Edit', EditOutlined),
86
+ ]
87
+
88
+ const { container } = render(
89
+ <ToolbarActions visibleCount={2}>{children}</ToolbarActions>,
90
+ )
91
+
92
+ // With visibleCount={2}, preview should include:
93
+ // Download, Divider-1, Share (counting 2 visible actions, including divider between them)
94
+ // Hidden: Divider-2, Edit
95
+
96
+ // First divider should be visible (in both preview and expanded)
97
+ const allDividers = container.querySelectorAll(
98
+ '[data-toolbar-hidden="true"]',
99
+ )
100
+ expect(allDividers.length).toBeGreaterThanOrEqual(1)
101
+ })
102
+
103
+ test('includes hidden children in expanded view', () => {
104
+ const children = [
105
+ createAction('download', 'Download', FileDownloadOutlined),
106
+ <Divider
107
+ key='divider-1'
108
+ orientation='vertical'
109
+ flexItem
110
+ data-toolbar-hidden
111
+ />,
112
+ createAction('share', 'Share', ShareOutlined),
113
+ <Divider
114
+ key='divider-2'
115
+ orientation='vertical'
116
+ flexItem
117
+ data-toolbar-hidden
118
+ />,
119
+ createAction('edit', 'Edit', EditOutlined),
120
+ ]
121
+
122
+ const { container } = render(
123
+ <ToolbarActions visibleCount={2}>{children}</ToolbarActions>,
124
+ )
125
+
126
+ const triggerButton = screen.getByRole('button', {
127
+ name: /more actions/i,
128
+ })
129
+ fireEvent.click(triggerButton)
130
+
131
+ // After expanding, all children including dividers should be present
132
+ // Check for dividers with data-toolbar-hidden attribute
133
+ // Note: dividers appear in both preview and expanded sections
134
+ // Preview: Divider-1 (between Download and Share)
135
+ // Expanded: Divider-1 and Divider-2 (all dividers)
136
+ // Total: 3 dividers with data-toolbar-hidden attribute
137
+ const dividers = container.querySelectorAll(
138
+ '[data-toolbar-hidden="true"]',
139
+ )
140
+ expect(dividers.length).toBe(3) // Divider-1 (preview) + Divider-1 + Divider-2 (expanded)
141
+ })
142
+
143
+ test('does not show trigger when only hidden children exceed visibleCount', () => {
144
+ const children = [
145
+ createAction('download', 'Download', FileDownloadOutlined),
146
+ createAction('share', 'Share', ShareOutlined),
147
+ <Divider
148
+ key='divider-1'
149
+ orientation='vertical'
150
+ flexItem
151
+ data-toolbar-hidden
152
+ />,
153
+ <Divider
154
+ key='divider-2'
155
+ orientation='vertical'
156
+ flexItem
157
+ data-toolbar-hidden
158
+ />,
159
+ ]
160
+
161
+ render(<ToolbarActions visibleCount={2}>{children}</ToolbarActions>)
162
+
163
+ // Should not show trigger button because there are only 2 visible actions
164
+ const triggerButtons = screen.queryAllByRole('button', {
165
+ name: /more actions/i,
166
+ })
167
+ expect(triggerButtons.length).toBe(0)
168
+
169
+ // Both visible actions should be shown (appear in both preview and hidden expanded sections)
170
+ const downloadButtons = screen.getAllByLabelText('Download')
171
+ const shareButtons = screen.getAllByLabelText('Share')
172
+ expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
173
+ expect(shareButtons.length).toBeGreaterThanOrEqual(1)
174
+ })
175
+ })
176
+
177
+ describe('visibleCount behavior', () => {
178
+ test('shows all actions when visibleCount is undefined', () => {
179
+ const children = [
180
+ createAction('download', 'Download', FileDownloadOutlined),
181
+ createAction('share', 'Share', ShareOutlined),
182
+ createAction('edit', 'Edit', EditOutlined),
183
+ createAction('filter', 'Filter', FilterListOutlined),
184
+ ]
185
+
186
+ render(
187
+ <ToolbarActions visibleCount={undefined}>{children}</ToolbarActions>,
188
+ )
189
+
190
+ // Should not show trigger button
191
+ const triggerButtons = screen.queryAllByRole('button', {
192
+ name: /more actions/i,
193
+ })
194
+ expect(triggerButtons.length).toBe(0)
195
+
196
+ // All actions should be visible (appear in both preview and hidden expanded sections)
197
+ const downloadButtons = screen.getAllByLabelText('Download')
198
+ const shareButtons = screen.getAllByLabelText('Share')
199
+ const editButtons = screen.getAllByLabelText('Edit')
200
+ const filterButtons = screen.getAllByLabelText('Filter')
201
+ expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
202
+ expect(shareButtons.length).toBeGreaterThanOrEqual(1)
203
+ expect(editButtons.length).toBeGreaterThanOrEqual(1)
204
+ expect(filterButtons.length).toBeGreaterThanOrEqual(1)
205
+ })
206
+
207
+ test('shows trigger when visibleCount is 1 and there are 2+ actions', () => {
208
+ const children = [
209
+ createAction('download', 'Download', FileDownloadOutlined),
210
+ createAction('share', 'Share', ShareOutlined),
211
+ ]
212
+
213
+ render(<ToolbarActions visibleCount={1}>{children}</ToolbarActions>)
214
+
215
+ // Should show trigger button
216
+ const triggerButton = screen.getByRole('button', {
217
+ name: /more actions/i,
218
+ })
219
+ expect(triggerButton).toBeTruthy()
220
+
221
+ // Download action should be visible (appears in both preview and expanded)
222
+ const downloadButtons = screen.getAllByLabelText('Download')
223
+ expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
224
+
225
+ // Share button exists in the expanded section
226
+ const shareButtons = screen.getAllByLabelText('Share')
227
+ expect(shareButtons.length).toBeGreaterThanOrEqual(1)
228
+ })
229
+
230
+ test('shows trigger when visibleCount is 2 and there are 3+ actions', () => {
231
+ const children = [
232
+ createAction('download', 'Download', FileDownloadOutlined),
233
+ createAction('share', 'Share', ShareOutlined),
234
+ createAction('edit', 'Edit', EditOutlined),
235
+ ]
236
+
237
+ render(<ToolbarActions visibleCount={2}>{children}</ToolbarActions>)
238
+
239
+ // Should show trigger button
240
+ const triggerButton = screen.getByRole('button', {
241
+ name: /more actions/i,
242
+ })
243
+ expect(triggerButton).toBeTruthy()
244
+
245
+ // First two actions should be visible (appear in both preview and expanded)
246
+ const downloadButtons = screen.getAllByLabelText('Download')
247
+ const shareButtons = screen.getAllByLabelText('Share')
248
+ expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
249
+ expect(shareButtons.length).toBeGreaterThanOrEqual(1)
250
+ })
251
+
252
+ test('does not show trigger when actions equal visibleCount', () => {
253
+ const children = [
254
+ createAction('download', 'Download', FileDownloadOutlined),
255
+ createAction('share', 'Share', ShareOutlined),
256
+ ]
257
+
258
+ render(<ToolbarActions visibleCount={2}>{children}</ToolbarActions>)
259
+
260
+ // Should not show trigger button
261
+ const triggerButtons = screen.queryAllByRole('button', {
262
+ name: /more actions/i,
263
+ })
264
+ expect(triggerButtons.length).toBe(0)
265
+
266
+ // Both actions should be visible (appear in both preview and hidden expanded sections)
267
+ const downloadButtons = screen.getAllByLabelText('Download')
268
+ const shareButtons = screen.getAllByLabelText('Share')
269
+ expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
270
+ expect(shareButtons.length).toBeGreaterThanOrEqual(1)
271
+ })
272
+
273
+ test('does not show trigger when actions are less than visibleCount', () => {
274
+ const children = [
275
+ createAction('download', 'Download', FileDownloadOutlined),
276
+ ]
277
+
278
+ render(<ToolbarActions visibleCount={2}>{children}</ToolbarActions>)
279
+
280
+ // Should not show trigger button
281
+ const triggerButtons = screen.queryAllByRole('button', {
282
+ name: /more actions/i,
283
+ })
284
+ expect(triggerButtons.length).toBe(0)
285
+
286
+ // Single action should be visible (appears in both preview and hidden expanded sections)
287
+ const downloadButtons = screen.getAllByLabelText('Download')
288
+ expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
289
+ })
290
+ })
291
+
292
+ describe('trigger button behavior', () => {
293
+ test('trigger button appears when there are more visible actions than visibleCount', () => {
294
+ const children = [
295
+ createAction('download', 'Download', FileDownloadOutlined),
296
+ createAction('share', 'Share', ShareOutlined),
297
+ createAction('edit', 'Edit', EditOutlined),
298
+ ]
299
+
300
+ render(<ToolbarActions visibleCount={2}>{children}</ToolbarActions>)
301
+
302
+ const triggerButton = screen.getByRole('button', {
303
+ name: /more actions/i,
304
+ })
305
+ expect(triggerButton).toBeTruthy()
306
+ })
307
+
308
+ test('trigger button does not appear when visibleCount is undefined', () => {
309
+ const children = [
310
+ createAction('download', 'Download', FileDownloadOutlined),
311
+ createAction('share', 'Share', ShareOutlined),
312
+ createAction('edit', 'Edit', EditOutlined),
313
+ ]
314
+
315
+ render(
316
+ <ToolbarActions visibleCount={undefined}>{children}</ToolbarActions>,
317
+ )
318
+
319
+ const triggerButtons = screen.queryAllByRole('button', {
320
+ name: /more actions/i,
321
+ })
322
+ expect(triggerButtons.length).toBe(0)
323
+ })
324
+
325
+ test('clicking trigger button expands the actions panel', () => {
326
+ const children = [
327
+ createAction('download', 'Download', FileDownloadOutlined),
328
+ createAction('share', 'Share', ShareOutlined),
329
+ createAction('edit', 'Edit', EditOutlined),
330
+ ]
331
+
332
+ render(<ToolbarActions visibleCount={2}>{children}</ToolbarActions>)
333
+
334
+ const triggerButton = screen.getByRole('button', {
335
+ name: /more actions/i,
336
+ })
337
+
338
+ // Before clicking, trigger button should not have data-active
339
+ expect(triggerButton.getAttribute('data-active')).toBe('false')
340
+
341
+ fireEvent.click(triggerButton)
342
+
343
+ // After clicking, trigger button should have data-active
344
+ expect(triggerButton.getAttribute('data-active')).toBe('true')
345
+
346
+ // Button should now show close label
347
+ const closeButton = screen.getByRole('button', { name: /close/i })
348
+ expect(closeButton).toBeTruthy()
349
+ })
350
+
351
+ test('clicking trigger button again collapses the actions panel', () => {
352
+ const children = [
353
+ createAction('download', 'Download', FileDownloadOutlined),
354
+ createAction('share', 'Share', ShareOutlined),
355
+ createAction('edit', 'Edit', EditOutlined),
356
+ ]
357
+
358
+ render(<ToolbarActions visibleCount={2}>{children}</ToolbarActions>)
359
+
360
+ const triggerButton = screen.getByRole('button', {
361
+ name: /more actions/i,
362
+ })
363
+
364
+ // Expand
365
+ fireEvent.click(triggerButton)
366
+ expect(triggerButton.getAttribute('data-active')).toBe('true')
367
+
368
+ // Collapse
369
+ fireEvent.click(triggerButton)
370
+ expect(triggerButton.getAttribute('data-active')).toBe('false')
371
+
372
+ // Button should show trigger label again
373
+ const reopenButton = screen.getByRole('button', {
374
+ name: /more actions/i,
375
+ })
376
+ expect(reopenButton).toBeTruthy()
377
+ })
378
+
379
+ test('uses custom labels when provided', () => {
380
+ const children = [
381
+ createAction('download', 'Download', FileDownloadOutlined),
382
+ createAction('share', 'Share', ShareOutlined),
383
+ createAction('edit', 'Edit', EditOutlined),
384
+ ]
385
+
386
+ render(
387
+ <ToolbarActions
388
+ visibleCount={2}
389
+ labels={{ trigger: 'Show options', close: 'Hide options' }}
390
+ >
391
+ {children}
392
+ </ToolbarActions>,
393
+ )
394
+
395
+ const triggerButton = screen.getByRole('button', {
396
+ name: /show options/i,
397
+ })
398
+ expect(triggerButton).toBeTruthy()
399
+
400
+ fireEvent.click(triggerButton)
401
+
402
+ const closeButton = screen.getByRole('button', { name: /hide options/i })
403
+ expect(closeButton).toBeTruthy()
404
+ })
405
+ })
406
+
407
+ describe('childrenPreview behavior', () => {
408
+ test('childrenPreview shows only visible children up to visibleCount', () => {
409
+ const children = [
410
+ createAction('download', 'Download', FileDownloadOutlined),
411
+ createAction('share', 'Share', ShareOutlined),
412
+ createAction('edit', 'Edit', EditOutlined),
413
+ createAction('filter', 'Filter', FilterListOutlined),
414
+ ]
415
+
416
+ render(<ToolbarActions visibleCount={2}>{children}</ToolbarActions>)
417
+
418
+ // Only first 2 should be in preview
419
+ // Note: Download and Share appear in both preview and expanded sections
420
+ const downloadButtons = screen.getAllByLabelText('Download')
421
+ const shareButtons = screen.getAllByLabelText('Share')
422
+ expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
423
+ expect(shareButtons.length).toBeGreaterThanOrEqual(1)
424
+
425
+ // Edit and Filter should also be in expanded section
426
+ const triggerButton = screen.getByRole('button', {
427
+ name: /more actions/i,
428
+ })
429
+ fireEvent.click(triggerButton)
430
+
431
+ // Now all should be visible
432
+ const editButtons = screen.getAllByLabelText('Edit')
433
+ const filterButtons = screen.getAllByLabelText('Filter')
434
+ expect(editButtons.length).toBeGreaterThanOrEqual(1)
435
+ expect(filterButtons.length).toBeGreaterThanOrEqual(1)
436
+ })
437
+
438
+ test('childrenPreview includes hidden children but does not count them', () => {
439
+ const children = [
440
+ createAction('download', 'Download', FileDownloadOutlined),
441
+ <Divider
442
+ key='divider-1'
443
+ orientation='vertical'
444
+ flexItem
445
+ data-toolbar-hidden
446
+ />,
447
+ createAction('share', 'Share', ShareOutlined),
448
+ createAction('edit', 'Edit', EditOutlined),
449
+ ]
450
+
451
+ const { container } = render(
452
+ <ToolbarActions visibleCount={2}>{children}</ToolbarActions>,
453
+ )
454
+
455
+ // Preview should show: Download, Divider, Share (2 visible actions counted, divider included)
456
+ // Hidden: Edit action
457
+ const downloadButtons = screen.getAllByLabelText('Download')
458
+ const shareButtons = screen.getAllByLabelText('Share')
459
+ expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
460
+ expect(shareButtons.length).toBeGreaterThanOrEqual(1)
461
+
462
+ // Divider with data-toolbar-hidden should be in preview (appears in both preview and expanded)
463
+ const allDividers = container.querySelectorAll(
464
+ '[data-toolbar-hidden="true"]',
465
+ )
466
+ expect(allDividers.length).toBeGreaterThanOrEqual(1)
467
+
468
+ // Edit button should also be present in expanded section
469
+ const triggerButton = screen.getByRole('button', {
470
+ name: /more actions/i,
471
+ })
472
+ fireEvent.click(triggerButton)
473
+
474
+ const editButtons = screen.getAllByLabelText('Edit')
475
+ expect(editButtons.length).toBeGreaterThanOrEqual(1)
476
+ })
477
+
478
+ test('childrenPreview shows all visible children when visibleCount is undefined', () => {
479
+ const children = [
480
+ createAction('download', 'Download', FileDownloadOutlined),
481
+ createAction('share', 'Share', ShareOutlined),
482
+ createAction('edit', 'Edit', EditOutlined),
483
+ ]
484
+
485
+ render(
486
+ <ToolbarActions visibleCount={undefined}>{children}</ToolbarActions>,
487
+ )
488
+
489
+ // All actions should be in preview (no trigger button)
490
+ // Actions appear in both preview and hidden expanded sections
491
+ const downloadButtons = screen.getAllByLabelText('Download')
492
+ const shareButtons = screen.getAllByLabelText('Share')
493
+ const editButtons = screen.getAllByLabelText('Edit')
494
+ expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
495
+ expect(shareButtons.length).toBeGreaterThanOrEqual(1)
496
+ expect(editButtons.length).toBeGreaterThanOrEqual(1)
497
+
498
+ const triggerButtons = screen.queryAllByRole('button', {
499
+ name: /more actions/i,
500
+ })
501
+ expect(triggerButtons.length).toBe(0)
502
+ })
503
+ })
504
+
505
+ describe('edge cases', () => {
506
+ test('renders nothing when children array is empty', () => {
507
+ const { container } = render(<ToolbarActions>{[]}</ToolbarActions>)
508
+ expect(container.firstChild).toBeNull()
509
+ })
510
+
511
+ test('renders nothing when children is null', () => {
512
+ const { container } = render(<ToolbarActions>{null}</ToolbarActions>)
513
+ expect(container.firstChild).toBeNull()
514
+ })
515
+
516
+ test('handles single child (not array)', () => {
517
+ const child = createAction('download', 'Download', FileDownloadOutlined)
518
+
519
+ render(<ToolbarActions visibleCount={2}>{child}</ToolbarActions>)
520
+
521
+ // Should appear in both preview and expanded sections (even though expanded is hidden)
522
+ const downloadButtons = screen.getAllByLabelText('Download')
523
+ expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
524
+
525
+ const triggerButtons = screen.queryAllByRole('button', {
526
+ name: /more actions/i,
527
+ })
528
+ expect(triggerButtons.length).toBe(0)
529
+ })
530
+
531
+ test('handles all children being hidden', () => {
532
+ const children = [
533
+ <Divider
534
+ key='divider-1'
535
+ orientation='vertical'
536
+ flexItem
537
+ data-toolbar-hidden
538
+ />,
539
+ <Divider
540
+ key='divider-2'
541
+ orientation='vertical'
542
+ flexItem
543
+ data-toolbar-hidden
544
+ />,
545
+ ]
546
+
547
+ const { container } = render(
548
+ <ToolbarActions visibleCount={2}>{children}</ToolbarActions>,
549
+ )
550
+
551
+ // Component still renders container even when no visible children
552
+ // (it only checks children.length, not visibleChildren.length)
553
+ // This test documents the current behavior
554
+ expect(container.firstChild).toBeTruthy()
555
+
556
+ // But there should be no trigger button since visibleChildren.length is 0
557
+ const triggerButtons = screen.queryAllByRole('button', {
558
+ name: /more actions/i,
559
+ })
560
+ expect(triggerButtons.length).toBe(0)
561
+ })
562
+
563
+ test('correctly counts when mix of hidden and visible children', () => {
564
+ const children = [
565
+ createAction('download', 'Download', FileDownloadOutlined),
566
+ <Divider
567
+ key='d1'
568
+ orientation='vertical'
569
+ flexItem
570
+ data-toolbar-hidden
571
+ />,
572
+ createAction('share', 'Share', ShareOutlined),
573
+ <Divider
574
+ key='d2'
575
+ orientation='vertical'
576
+ flexItem
577
+ data-toolbar-hidden
578
+ />,
579
+ createAction('edit', 'Edit', EditOutlined),
580
+ <Divider
581
+ key='d3'
582
+ orientation='vertical'
583
+ flexItem
584
+ data-toolbar-hidden
585
+ />,
586
+ createAction('filter', 'Filter', FilterListOutlined),
587
+ ]
588
+
589
+ render(<ToolbarActions visibleCount={3}>{children}</ToolbarActions>)
590
+
591
+ // Should show trigger because there are 4 visible actions > 3
592
+ const triggerButton = screen.getByRole('button', {
593
+ name: /more actions/i,
594
+ })
595
+ expect(triggerButton).toBeTruthy()
596
+
597
+ // Preview should show first 3 visible actions + dividers between them
598
+ // (Download, Divider, Share, Divider, Edit - stops after counting 3 non-hidden)
599
+ const downloadButtons = screen.getAllByLabelText('Download')
600
+ const shareButtons = screen.getAllByLabelText('Share')
601
+ const editButtons = screen.getAllByLabelText('Edit')
602
+ expect(downloadButtons.length).toBeGreaterThanOrEqual(1)
603
+ expect(shareButtons.length).toBeGreaterThanOrEqual(1)
604
+ expect(editButtons.length).toBeGreaterThanOrEqual(1)
605
+ })
606
+
607
+ test('documentation example: visibleCount={2} with [Action1, Divider, Action2, Divider, Action3]', () => {
608
+ const children = [
609
+ createAction('action1', 'Action 1', FileDownloadOutlined),
610
+ <Divider
611
+ key='divider-1'
612
+ orientation='vertical'
613
+ flexItem
614
+ data-toolbar-hidden
615
+ />,
616
+ createAction('action2', 'Action 2', ShareOutlined),
617
+ <Divider
618
+ key='divider-2'
619
+ orientation='vertical'
620
+ flexItem
621
+ data-toolbar-hidden
622
+ />,
623
+ createAction('action3', 'Action 3', EditOutlined),
624
+ ]
625
+
626
+ const { container } = render(
627
+ <ToolbarActions visibleCount={2}>{children}</ToolbarActions>,
628
+ )
629
+
630
+ // Expected preview: Action1, Divider, Action2 (2 actions counted, divider included)
631
+ // Hidden: Divider, Action3
632
+
633
+ // Should show trigger button since we have 3 visible actions > 2
634
+ const triggerButton = screen.getByRole('button', {
635
+ name: /more actions/i,
636
+ })
637
+ expect(triggerButton).toBeTruthy()
638
+
639
+ // Action1 and Action2 should be visible
640
+ const action1Buttons = screen.getAllByLabelText('Action 1')
641
+ const action2Buttons = screen.getAllByLabelText('Action 2')
642
+ expect(action1Buttons.length).toBeGreaterThanOrEqual(1)
643
+ expect(action2Buttons.length).toBeGreaterThanOrEqual(1)
644
+
645
+ // At least one divider with data-toolbar-hidden should be rendered
646
+ const dividers = container.querySelectorAll(
647
+ '[data-toolbar-hidden="true"]',
648
+ )
649
+ expect(dividers.length).toBeGreaterThanOrEqual(1)
650
+
651
+ // Action3 should be in expanded section
652
+ const action3Buttons = screen.getAllByLabelText('Action 3')
653
+ expect(action3Buttons.length).toBeGreaterThanOrEqual(1)
654
+ })
655
+ })
656
+
657
+ describe('direction prop', () => {
658
+ test('applies correct flex direction for left expansion', () => {
659
+ const children = [
660
+ createAction('download', 'Download', FileDownloadOutlined),
661
+ createAction('share', 'Share', ShareOutlined),
662
+ ]
663
+
664
+ const { container } = render(
665
+ <ToolbarActions direction='left'>{children}</ToolbarActions>,
666
+ )
667
+
668
+ const root = container.firstChild as HTMLElement
669
+ expect(root).toBeTruthy()
670
+ // Check that the style contains row-reverse
671
+ const style = window.getComputedStyle(root)
672
+ expect(style.flexDirection).toBe('row-reverse')
673
+ })
674
+
675
+ test('applies correct flex direction for right expansion (default)', () => {
676
+ const children = [
677
+ createAction('download', 'Download', FileDownloadOutlined),
678
+ createAction('share', 'Share', ShareOutlined),
679
+ ]
680
+
681
+ const { container } = render(
682
+ <ToolbarActions direction='right'>{children}</ToolbarActions>,
683
+ )
684
+
685
+ const root = container.firstChild as HTMLElement
686
+ expect(root).toBeTruthy()
687
+ const style = window.getComputedStyle(root)
688
+ expect(style.flexDirection).toBe('row')
689
+ })
690
+ })
691
+ })