@coreui/react-pro 5.24.1 → 5.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (416) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/components/card/CCardImage.js.map +1 -1
  3. package/dist/cjs/components/carousel/CCarousel.js +44 -33
  4. package/dist/cjs/components/carousel/CCarousel.js.map +1 -1
  5. package/dist/cjs/components/carousel/CCarouselItem.js +19 -28
  6. package/dist/cjs/components/carousel/CCarouselItem.js.map +1 -1
  7. package/dist/cjs/components/chip/CChip.d.ts +12 -0
  8. package/dist/cjs/components/chip/CChip.js +16 -63
  9. package/dist/cjs/components/chip/CChip.js.map +1 -1
  10. package/dist/cjs/components/chip/const.d.ts +1 -0
  11. package/dist/cjs/components/chip/const.js +8 -0
  12. package/dist/cjs/components/chip/const.js.map +1 -0
  13. package/dist/cjs/components/chip-set/CChipSet.d.ts +73 -0
  14. package/dist/cjs/components/chip-set/CChipSet.js +66 -0
  15. package/dist/cjs/components/chip-set/CChipSet.js.map +1 -0
  16. package/dist/cjs/components/chip-set/index.d.ts +2 -0
  17. package/dist/cjs/components/chip-set/useChipSet.d.ts +48 -0
  18. package/dist/cjs/components/chip-set/useChipSet.js +163 -0
  19. package/dist/cjs/components/chip-set/useChipSet.js.map +1 -0
  20. package/dist/cjs/components/chip-set/utils.d.ts +7 -0
  21. package/dist/cjs/components/chip-set/utils.js +18 -0
  22. package/dist/cjs/components/chip-set/utils.js.map +1 -0
  23. package/dist/cjs/components/collapse/CCollapse.js +14 -6
  24. package/dist/cjs/components/collapse/CCollapse.js.map +1 -1
  25. package/dist/cjs/components/conditional-portal/CConditionalPortal.js +3 -1
  26. package/dist/cjs/components/conditional-portal/CConditionalPortal.js.map +1 -1
  27. package/dist/cjs/components/date-picker/CDatePicker.d.ts +1 -1
  28. package/dist/cjs/components/date-picker/CDatePicker.js.map +1 -1
  29. package/dist/cjs/components/date-range-picker/CDateRangePicker.js +2 -0
  30. package/dist/cjs/components/date-range-picker/CDateRangePicker.js.map +1 -1
  31. package/dist/cjs/components/dropdown/CDropdown.js +23 -30
  32. package/dist/cjs/components/dropdown/CDropdown.js.map +1 -1
  33. package/dist/cjs/components/dropdown/CDropdownToggle.js.map +1 -1
  34. package/dist/cjs/components/form/CChipInput.d.ts +14 -2
  35. package/dist/cjs/components/form/CChipInput.js +77 -49
  36. package/dist/cjs/components/form/CChipInput.js.map +1 -1
  37. package/dist/cjs/components/form/CFormCheck.js.map +1 -1
  38. package/dist/cjs/components/form/CFormInput.js.map +1 -1
  39. package/dist/cjs/components/form/CFormSelect.js.map +1 -1
  40. package/dist/cjs/components/form/CFormTextarea.js.map +1 -1
  41. package/dist/cjs/components/form/CInputGroupText.js.map +1 -1
  42. package/dist/cjs/components/grid/CContainer.js +3 -1
  43. package/dist/cjs/components/grid/CContainer.js.map +1 -1
  44. package/dist/cjs/components/header/CHeaderBrand.js.map +1 -1
  45. package/dist/cjs/components/index.d.ts +2 -0
  46. package/dist/cjs/components/link/CLink.js +4 -2
  47. package/dist/cjs/components/link/CLink.js.map +1 -1
  48. package/dist/cjs/components/list-group/CListGroupItem.js.map +1 -1
  49. package/dist/cjs/components/modal/CModal.js +14 -2
  50. package/dist/cjs/components/modal/CModal.js.map +1 -1
  51. package/dist/cjs/components/multi-select/CMultiSelect.d.ts +73 -1
  52. package/dist/cjs/components/multi-select/CMultiSelect.js +157 -18
  53. package/dist/cjs/components/multi-select/CMultiSelect.js.map +1 -1
  54. package/dist/cjs/components/multi-select/CMultiSelectNativeSelect.js +1 -1
  55. package/dist/cjs/components/multi-select/CMultiSelectNativeSelect.js.map +1 -1
  56. package/dist/cjs/components/multi-select/CMultiSelectOptions.d.ts +3 -0
  57. package/dist/cjs/components/multi-select/CMultiSelectOptions.js +45 -2
  58. package/dist/cjs/components/multi-select/CMultiSelectOptions.js.map +1 -1
  59. package/dist/cjs/components/multi-select/CMultiSelectSelection.d.ts +1 -0
  60. package/dist/cjs/components/multi-select/CMultiSelectSelection.js +4 -3
  61. package/dist/cjs/components/multi-select/CMultiSelectSelection.js.map +1 -1
  62. package/dist/cjs/components/multi-select/types.d.ts +12 -0
  63. package/dist/cjs/components/multi-select/utils.js +1 -4
  64. package/dist/cjs/components/multi-select/utils.js.map +1 -1
  65. package/dist/cjs/components/nav/CNav.js.map +1 -1
  66. package/dist/cjs/components/nav/CNavGroup.d.ts +13 -6
  67. package/dist/cjs/components/nav/CNavGroup.js +86 -23
  68. package/dist/cjs/components/nav/CNavGroup.js.map +1 -1
  69. package/dist/cjs/components/nav/CNavGroupContext.d.ts +25 -0
  70. package/dist/cjs/components/nav/CNavGroupContext.js +13 -0
  71. package/dist/cjs/components/nav/CNavGroupContext.js.map +1 -0
  72. package/dist/cjs/components/nav/CNavLink.d.ts +1 -5
  73. package/dist/cjs/components/nav/CNavLink.js +21 -8
  74. package/dist/cjs/components/nav/CNavLink.js.map +1 -1
  75. package/dist/cjs/components/one-time-password-input/COneTimePassword.js +3 -3
  76. package/dist/cjs/components/one-time-password-input/COneTimePassword.js.map +1 -1
  77. package/dist/cjs/components/popover/CPopover.js +69 -24
  78. package/dist/cjs/components/popover/CPopover.js.map +1 -1
  79. package/dist/cjs/components/progress/CProgress.js.map +1 -1
  80. package/dist/cjs/components/rating/CRating.d.ts +1 -1
  81. package/dist/cjs/components/rating/CRating.js.map +1 -1
  82. package/dist/cjs/components/search-button/CSearchButton.d.ts +32 -0
  83. package/dist/cjs/components/search-button/CSearchButton.js +77 -0
  84. package/dist/cjs/components/search-button/CSearchButton.js.map +1 -0
  85. package/dist/cjs/components/search-button/index.d.ts +2 -0
  86. package/dist/cjs/components/search-button/types.d.ts +10 -0
  87. package/dist/cjs/components/search-button/utils.d.ts +11 -0
  88. package/dist/cjs/components/search-button/utils.js +115 -0
  89. package/dist/cjs/components/search-button/utils.js.map +1 -0
  90. package/dist/cjs/components/sidebar/CSidebar.js +40 -23
  91. package/dist/cjs/components/sidebar/CSidebar.js.map +1 -1
  92. package/dist/cjs/components/sidebar/CSidebarNav.d.ts +12 -0
  93. package/dist/cjs/components/sidebar/CSidebarNav.js +12 -36
  94. package/dist/cjs/components/sidebar/CSidebarNav.js.map +1 -1
  95. package/dist/cjs/components/smart-table/CSmartTable.js +2 -2
  96. package/dist/cjs/components/smart-table/CSmartTable.js.map +1 -1
  97. package/dist/cjs/components/smart-table/CSmartTableInterface.d.ts +2 -2
  98. package/dist/cjs/components/table/CTableDataCell.js.map +1 -1
  99. package/dist/cjs/components/table/types.d.ts +2 -1
  100. package/dist/cjs/components/table/utils.js +4 -4
  101. package/dist/cjs/components/table/utils.js.map +1 -1
  102. package/dist/cjs/components/tabs/CTabPanel.js +3 -1
  103. package/dist/cjs/components/tabs/CTabPanel.js.map +1 -1
  104. package/dist/cjs/components/time-picker/CTimePicker.d.ts +1 -1
  105. package/dist/cjs/components/time-picker/CTimePicker.js +1 -1
  106. package/dist/cjs/components/time-picker/CTimePicker.js.map +1 -1
  107. package/dist/cjs/components/tooltip/CTooltip.js +69 -24
  108. package/dist/cjs/components/tooltip/CTooltip.js.map +1 -1
  109. package/dist/cjs/components/virtual-scroller/CVirtualScroller.js +11 -8
  110. package/dist/cjs/components/virtual-scroller/CVirtualScroller.js.map +1 -1
  111. package/dist/cjs/helpers/polymorphicComponent.d.ts +1 -2
  112. package/dist/cjs/hooks/useDebouncedCallback.d.ts +1 -1
  113. package/dist/cjs/hooks/useDebouncedCallback.js +1 -1
  114. package/dist/cjs/hooks/useDebouncedCallback.js.map +1 -1
  115. package/dist/cjs/hooks/useForkedRef.d.ts +1 -1
  116. package/dist/cjs/hooks/useForkedRef.js +6 -3
  117. package/dist/cjs/hooks/useForkedRef.js.map +1 -1
  118. package/dist/cjs/hooks/usePopper.js +8 -6
  119. package/dist/cjs/hooks/usePopper.js.map +1 -1
  120. package/dist/cjs/index.js +4 -0
  121. package/dist/cjs/index.js.map +1 -1
  122. package/dist/cjs/node_modules/@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js +1 -1
  123. package/dist/cjs/node_modules/@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js.map +1 -1
  124. package/dist/cjs/node_modules/@coreui/icons/dist/esm/free/cil-arrow-bottom.js +1 -1
  125. package/dist/cjs/node_modules/@coreui/icons/dist/esm/free/cil-arrow-bottom.js.map +1 -1
  126. package/dist/cjs/node_modules/@coreui/icons/dist/esm/free/cil-arrow-top.js +1 -1
  127. package/dist/cjs/node_modules/@coreui/icons/dist/esm/free/cil-arrow-top.js.map +1 -1
  128. package/dist/cjs/node_modules/@coreui/icons/dist/esm/free/cil-filter-x.js +1 -1
  129. package/dist/cjs/node_modules/@coreui/icons/dist/esm/free/cil-filter-x.js.map +1 -1
  130. package/dist/cjs/node_modules/@coreui/icons/dist/esm/free/cil-swap-vertical.js +1 -1
  131. package/dist/cjs/node_modules/@coreui/icons/dist/esm/free/cil-swap-vertical.js.map +1 -1
  132. package/dist/cjs/node_modules/ua-parser-js/dist/ua-parser.min.js +4 -4
  133. package/dist/cjs/node_modules/ua-parser-js/dist/ua-parser.min.js.map +1 -1
  134. package/dist/cjs/utils/executeAfterTransition.js.map +1 -1
  135. package/dist/cjs/utils/index.d.ts +2 -1
  136. package/dist/cjs/utils/swipe.d.ts +26 -0
  137. package/dist/cjs/utils/swipe.js +94 -0
  138. package/dist/cjs/utils/swipe.js.map +1 -0
  139. package/dist/esm/components/card/CCardImage.js.map +1 -1
  140. package/dist/esm/components/carousel/CCarousel.js +44 -33
  141. package/dist/esm/components/carousel/CCarousel.js.map +1 -1
  142. package/dist/esm/components/carousel/CCarouselItem.js +19 -28
  143. package/dist/esm/components/carousel/CCarouselItem.js.map +1 -1
  144. package/dist/esm/components/chip/CChip.d.ts +12 -0
  145. package/dist/esm/components/chip/CChip.js +16 -63
  146. package/dist/esm/components/chip/CChip.js.map +1 -1
  147. package/dist/esm/components/chip/const.d.ts +1 -0
  148. package/dist/esm/components/chip/const.js +6 -0
  149. package/dist/esm/components/chip/const.js.map +1 -0
  150. package/dist/esm/components/chip-set/CChipSet.d.ts +73 -0
  151. package/dist/esm/components/chip-set/CChipSet.js +64 -0
  152. package/dist/esm/components/chip-set/CChipSet.js.map +1 -0
  153. package/dist/esm/components/chip-set/index.d.ts +2 -0
  154. package/dist/esm/components/chip-set/useChipSet.d.ts +48 -0
  155. package/dist/esm/components/chip-set/useChipSet.js +161 -0
  156. package/dist/esm/components/chip-set/useChipSet.js.map +1 -0
  157. package/dist/esm/components/chip-set/utils.d.ts +7 -0
  158. package/dist/esm/components/chip-set/utils.js +16 -0
  159. package/dist/esm/components/chip-set/utils.js.map +1 -0
  160. package/dist/esm/components/collapse/CCollapse.js +14 -6
  161. package/dist/esm/components/collapse/CCollapse.js.map +1 -1
  162. package/dist/esm/components/conditional-portal/CConditionalPortal.js +3 -1
  163. package/dist/esm/components/conditional-portal/CConditionalPortal.js.map +1 -1
  164. package/dist/esm/components/date-picker/CDatePicker.d.ts +1 -1
  165. package/dist/esm/components/date-picker/CDatePicker.js.map +1 -1
  166. package/dist/esm/components/date-range-picker/CDateRangePicker.js +2 -0
  167. package/dist/esm/components/date-range-picker/CDateRangePicker.js.map +1 -1
  168. package/dist/esm/components/dropdown/CDropdown.js +23 -30
  169. package/dist/esm/components/dropdown/CDropdown.js.map +1 -1
  170. package/dist/esm/components/dropdown/CDropdownToggle.js.map +1 -1
  171. package/dist/esm/components/form/CChipInput.d.ts +14 -2
  172. package/dist/esm/components/form/CChipInput.js +78 -50
  173. package/dist/esm/components/form/CChipInput.js.map +1 -1
  174. package/dist/esm/components/form/CFormCheck.js.map +1 -1
  175. package/dist/esm/components/form/CFormInput.js.map +1 -1
  176. package/dist/esm/components/form/CFormSelect.js.map +1 -1
  177. package/dist/esm/components/form/CFormTextarea.js.map +1 -1
  178. package/dist/esm/components/form/CInputGroupText.js.map +1 -1
  179. package/dist/esm/components/grid/CContainer.js +3 -1
  180. package/dist/esm/components/grid/CContainer.js.map +1 -1
  181. package/dist/esm/components/header/CHeaderBrand.js.map +1 -1
  182. package/dist/esm/components/index.d.ts +2 -0
  183. package/dist/esm/components/link/CLink.js +4 -2
  184. package/dist/esm/components/link/CLink.js.map +1 -1
  185. package/dist/esm/components/list-group/CListGroupItem.js.map +1 -1
  186. package/dist/esm/components/modal/CModal.js +14 -2
  187. package/dist/esm/components/modal/CModal.js.map +1 -1
  188. package/dist/esm/components/multi-select/CMultiSelect.d.ts +73 -1
  189. package/dist/esm/components/multi-select/CMultiSelect.js +158 -19
  190. package/dist/esm/components/multi-select/CMultiSelect.js.map +1 -1
  191. package/dist/esm/components/multi-select/CMultiSelectNativeSelect.js +1 -1
  192. package/dist/esm/components/multi-select/CMultiSelectNativeSelect.js.map +1 -1
  193. package/dist/esm/components/multi-select/CMultiSelectOptions.d.ts +3 -0
  194. package/dist/esm/components/multi-select/CMultiSelectOptions.js +45 -2
  195. package/dist/esm/components/multi-select/CMultiSelectOptions.js.map +1 -1
  196. package/dist/esm/components/multi-select/CMultiSelectSelection.d.ts +1 -0
  197. package/dist/esm/components/multi-select/CMultiSelectSelection.js +4 -3
  198. package/dist/esm/components/multi-select/CMultiSelectSelection.js.map +1 -1
  199. package/dist/esm/components/multi-select/types.d.ts +12 -0
  200. package/dist/esm/components/multi-select/utils.js +1 -4
  201. package/dist/esm/components/multi-select/utils.js.map +1 -1
  202. package/dist/esm/components/nav/CNav.js.map +1 -1
  203. package/dist/esm/components/nav/CNavGroup.d.ts +13 -6
  204. package/dist/esm/components/nav/CNavGroup.js +87 -24
  205. package/dist/esm/components/nav/CNavGroup.js.map +1 -1
  206. package/dist/esm/components/nav/CNavGroupContext.d.ts +25 -0
  207. package/dist/esm/components/nav/CNavGroupContext.js +11 -0
  208. package/dist/esm/components/nav/CNavGroupContext.js.map +1 -0
  209. package/dist/esm/components/nav/CNavLink.d.ts +1 -5
  210. package/dist/esm/components/nav/CNavLink.js +21 -8
  211. package/dist/esm/components/nav/CNavLink.js.map +1 -1
  212. package/dist/esm/components/one-time-password-input/COneTimePassword.js +3 -3
  213. package/dist/esm/components/one-time-password-input/COneTimePassword.js.map +1 -1
  214. package/dist/esm/components/popover/CPopover.js +69 -24
  215. package/dist/esm/components/popover/CPopover.js.map +1 -1
  216. package/dist/esm/components/progress/CProgress.js.map +1 -1
  217. package/dist/esm/components/rating/CRating.d.ts +1 -1
  218. package/dist/esm/components/rating/CRating.js.map +1 -1
  219. package/dist/esm/components/search-button/CSearchButton.d.ts +32 -0
  220. package/dist/esm/components/search-button/CSearchButton.js +75 -0
  221. package/dist/esm/components/search-button/CSearchButton.js.map +1 -0
  222. package/dist/esm/components/search-button/index.d.ts +2 -0
  223. package/dist/esm/components/search-button/types.d.ts +10 -0
  224. package/dist/esm/components/search-button/utils.d.ts +11 -0
  225. package/dist/esm/components/search-button/utils.js +104 -0
  226. package/dist/esm/components/search-button/utils.js.map +1 -0
  227. package/dist/esm/components/sidebar/CSidebar.js +40 -23
  228. package/dist/esm/components/sidebar/CSidebar.js.map +1 -1
  229. package/dist/esm/components/sidebar/CSidebarNav.d.ts +12 -0
  230. package/dist/esm/components/sidebar/CSidebarNav.js +13 -37
  231. package/dist/esm/components/sidebar/CSidebarNav.js.map +1 -1
  232. package/dist/esm/components/smart-table/CSmartTable.js +2 -2
  233. package/dist/esm/components/smart-table/CSmartTable.js.map +1 -1
  234. package/dist/esm/components/smart-table/CSmartTableInterface.d.ts +2 -2
  235. package/dist/esm/components/table/CTableDataCell.js.map +1 -1
  236. package/dist/esm/components/table/types.d.ts +2 -1
  237. package/dist/esm/components/table/utils.js +4 -4
  238. package/dist/esm/components/table/utils.js.map +1 -1
  239. package/dist/esm/components/tabs/CTabPanel.js +3 -1
  240. package/dist/esm/components/tabs/CTabPanel.js.map +1 -1
  241. package/dist/esm/components/time-picker/CTimePicker.d.ts +1 -1
  242. package/dist/esm/components/time-picker/CTimePicker.js +1 -1
  243. package/dist/esm/components/time-picker/CTimePicker.js.map +1 -1
  244. package/dist/esm/components/tooltip/CTooltip.js +69 -24
  245. package/dist/esm/components/tooltip/CTooltip.js.map +1 -1
  246. package/dist/esm/components/virtual-scroller/CVirtualScroller.js +11 -8
  247. package/dist/esm/components/virtual-scroller/CVirtualScroller.js.map +1 -1
  248. package/dist/esm/helpers/polymorphicComponent.d.ts +1 -2
  249. package/dist/esm/hooks/useDebouncedCallback.d.ts +1 -1
  250. package/dist/esm/hooks/useDebouncedCallback.js +1 -1
  251. package/dist/esm/hooks/useDebouncedCallback.js.map +1 -1
  252. package/dist/esm/hooks/useForkedRef.d.ts +1 -1
  253. package/dist/esm/hooks/useForkedRef.js +6 -3
  254. package/dist/esm/hooks/useForkedRef.js.map +1 -1
  255. package/dist/esm/hooks/usePopper.js +9 -7
  256. package/dist/esm/hooks/usePopper.js.map +1 -1
  257. package/dist/esm/index.js +2 -0
  258. package/dist/esm/index.js.map +1 -1
  259. package/dist/esm/node_modules/@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js +1 -1
  260. package/dist/esm/node_modules/@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js.map +1 -1
  261. package/dist/esm/node_modules/@coreui/icons/dist/esm/free/cil-arrow-bottom.js +1 -1
  262. package/dist/esm/node_modules/@coreui/icons/dist/esm/free/cil-arrow-bottom.js.map +1 -1
  263. package/dist/esm/node_modules/@coreui/icons/dist/esm/free/cil-arrow-top.js +1 -1
  264. package/dist/esm/node_modules/@coreui/icons/dist/esm/free/cil-arrow-top.js.map +1 -1
  265. package/dist/esm/node_modules/@coreui/icons/dist/esm/free/cil-filter-x.js +1 -1
  266. package/dist/esm/node_modules/@coreui/icons/dist/esm/free/cil-filter-x.js.map +1 -1
  267. package/dist/esm/node_modules/@coreui/icons/dist/esm/free/cil-swap-vertical.js +1 -1
  268. package/dist/esm/node_modules/@coreui/icons/dist/esm/free/cil-swap-vertical.js.map +1 -1
  269. package/dist/esm/node_modules/ua-parser-js/dist/ua-parser.min.js +4 -4
  270. package/dist/esm/node_modules/ua-parser-js/dist/ua-parser.min.js.map +1 -1
  271. package/dist/esm/utils/executeAfterTransition.js.map +1 -1
  272. package/dist/esm/utils/index.d.ts +2 -1
  273. package/dist/esm/utils/swipe.d.ts +26 -0
  274. package/dist/esm/utils/swipe.js +90 -0
  275. package/dist/esm/utils/swipe.js.map +1 -0
  276. package/package.json +8 -6
  277. package/src/components/autocomplete/CAutocompleteOptions.tsx +1 -1
  278. package/src/components/autocomplete/__tests__/CAutocomplete.spec.tsx +18 -16
  279. package/src/components/autocomplete/__tests__/CAutocompleteOptions.spec.tsx +37 -28
  280. package/src/components/autocomplete/__tests__/__snapshots__/CAutocomplete.spec.tsx.snap +129 -0
  281. package/src/components/autocomplete/__tests__/__snapshots__/CAutocompleteOptions.spec.tsx.snap +36 -0
  282. package/src/components/calendar/__tests__/CCalendar.spec.tsx +40 -45
  283. package/src/components/calendar/__tests__/__snapshots__/CCalendar.spec.tsx.snap +99 -75
  284. package/src/components/calendar/__tests__/utils.spec.tsx +8 -18
  285. package/src/components/card/CCardImage.tsx +3 -2
  286. package/src/components/carousel/CCarousel.tsx +48 -51
  287. package/src/components/carousel/CCarouselContext.ts +1 -1
  288. package/src/components/carousel/CCarouselItem.tsx +25 -26
  289. package/src/components/carousel/__tests__/CCarousel.spec.tsx +47 -4
  290. package/src/components/carousel/__tests__/CCarouselItem.spec.tsx +37 -0
  291. package/src/components/chip/CChip.tsx +45 -78
  292. package/src/components/chip/__tests__/CChip.spec.tsx +26 -19
  293. package/src/components/chip/const.ts +3 -0
  294. package/src/components/chip-set/CChipSet.tsx +183 -0
  295. package/src/components/chip-set/__tests__/CChipSet.spec.tsx +215 -0
  296. package/src/components/chip-set/__tests__/__snapshots__/CChipSet.spec.tsx.snap +22 -0
  297. package/src/components/chip-set/index.ts +3 -0
  298. package/src/components/chip-set/useChipSet.ts +243 -0
  299. package/src/components/chip-set/utils.ts +19 -0
  300. package/src/components/collapse/CCollapse.tsx +18 -6
  301. package/src/components/conditional-portal/CConditionalPortal.tsx +4 -2
  302. package/src/components/date-picker/CDatePicker.tsx +12 -13
  303. package/src/components/date-picker/__tests__/CDatePicker.spec.tsx +1 -1
  304. package/src/components/date-picker/__tests__/__snapshots__/CDatePicker.spec.tsx.snap +12 -640
  305. package/src/components/date-range-picker/CDateRangePicker.tsx +2 -0
  306. package/src/components/date-range-picker/__tests__/CDateRangePicker.spec.tsx +1 -1
  307. package/src/components/date-range-picker/__tests__/__snapshots__/CDateRangePicker.spec.tsx.snap +21 -1259
  308. package/src/components/dropdown/CDropdown.tsx +29 -34
  309. package/src/components/dropdown/CDropdownToggle.tsx +1 -1
  310. package/src/components/dropdown/__tests__/CDropdown.spec.tsx +56 -1
  311. package/src/components/dropdown/__tests__/__snapshots__/CDropdown.spec.tsx.snap +2 -2
  312. package/src/components/dropdown/__tests__/__snapshots__/CDropdownMenu.spec.tsx.snap +1 -1
  313. package/src/components/focus-trap/__tests__/CFocusTrap.spec.tsx +1 -1
  314. package/src/components/form/CChipInput.tsx +105 -67
  315. package/src/components/form/CFormCheck.tsx +1 -2
  316. package/src/components/form/CFormInput.tsx +1 -2
  317. package/src/components/form/CFormSelect.tsx +1 -2
  318. package/src/components/form/CFormTextarea.tsx +1 -2
  319. package/src/components/form/CInputGroupText.tsx +3 -2
  320. package/src/components/form/__tests__/CChipInput.spec.tsx +67 -1
  321. package/src/components/form/__tests__/CFormInput.spec.tsx +17 -20
  322. package/src/components/form/__tests__/__snapshots__/CChipInput.spec.tsx.snap +7 -0
  323. package/src/components/form/__tests__/__snapshots__/CFormInput.spec.tsx.snap +12 -3
  324. package/src/components/grid/CContainer.tsx +3 -1
  325. package/src/components/header/CHeaderBrand.tsx +3 -2
  326. package/src/components/index.ts +2 -0
  327. package/src/components/link/CLink.tsx +7 -4
  328. package/src/components/list-group/CListGroupItem.tsx +3 -2
  329. package/src/components/loading-button/__tests__/CLoadingButton.spec.tsx +1 -1
  330. package/src/components/loading-button/__tests__/__snapshots__/CLoadingButton.spec.tsx.snap +4 -4
  331. package/src/components/modal/CModal.tsx +19 -2
  332. package/src/components/modal/__tests__/CModal.spec.tsx +43 -0
  333. package/src/components/multi-select/CMultiSelect.tsx +341 -46
  334. package/src/components/multi-select/CMultiSelectNativeSelect.tsx +1 -1
  335. package/src/components/multi-select/CMultiSelectOptions.tsx +74 -3
  336. package/src/components/multi-select/CMultiSelectSelection.tsx +5 -1
  337. package/src/components/multi-select/__tests__/CMultiSelect.spec.tsx +27 -69
  338. package/src/components/multi-select/__tests__/CMultiSelectNativeSelect.spec.tsx +4 -5
  339. package/src/components/multi-select/__tests__/CMultiSelectOptions.spec.tsx +4 -4
  340. package/src/components/multi-select/__tests__/CMultiSelectSelection.spec.tsx +7 -24
  341. package/src/components/multi-select/__tests__/__snapshots__/CMultiSelect.spec.tsx.snap +108 -61
  342. package/src/components/multi-select/__tests__/__snapshots__/CMultiSelectNativeSelect.spec.tsx.snap +2 -4
  343. package/src/components/multi-select/__tests__/__snapshots__/CMultiSelectOptions.spec.tsx.snap +7 -0
  344. package/src/components/multi-select/__tests__/__snapshots__/CMultiSelectSelection.spec.tsx.snap +16 -9
  345. package/src/components/multi-select/types.ts +14 -0
  346. package/src/components/nav/CNav.tsx +3 -2
  347. package/src/components/nav/CNavGroup.tsx +196 -105
  348. package/src/components/nav/CNavGroupContext.ts +27 -0
  349. package/src/components/nav/CNavLink.tsx +26 -12
  350. package/src/components/nav/__tests__/CNavGroup.spec.tsx +207 -4
  351. package/src/components/nav/__tests__/__snapshots__/CNavGroup.spec.tsx.snap +3 -1
  352. package/src/components/offcanvas/__tests__/COffcanvas.spec.tsx +1 -0
  353. package/src/components/one-time-password-input/COneTimePassword.tsx +10 -11
  354. package/src/components/picker/__tests__/CPicker.spec.tsx +1 -1
  355. package/src/components/picker/__tests__/__snapshots__/CPicker.spec.tsx.snap +2 -16
  356. package/src/components/popover/CPopover.tsx +71 -26
  357. package/src/components/popover/__tests__/CPopover.spec.tsx +85 -4
  358. package/src/components/progress/CProgress.tsx +1 -2
  359. package/src/components/rating/CRating.tsx +1 -0
  360. package/src/components/search-button/CSearchButton.tsx +195 -0
  361. package/src/components/search-button/__tests__/CSearchButton.spec.tsx +95 -0
  362. package/src/components/search-button/__tests__/__snapshots__/CSearchButton.spec.tsx.snap +87 -0
  363. package/src/components/search-button/index.ts +3 -0
  364. package/src/components/search-button/types.ts +10 -0
  365. package/src/components/search-button/utils.ts +140 -0
  366. package/src/components/sidebar/CSidebar.tsx +51 -26
  367. package/src/components/sidebar/CSidebarNav.tsx +39 -53
  368. package/src/components/sidebar/__tests__/CSidebar.spec.tsx +26 -0
  369. package/src/components/smart-table/CSmartTable.tsx +5 -4
  370. package/src/components/smart-table/CSmartTableInterface.tsx +2 -2
  371. package/src/components/smart-table/__tests__/CSmartTable.spec.tsx +3 -2
  372. package/src/components/smart-table/__tests__/__snapshots__/CSmartTable.spec.tsx.snap +7 -15
  373. package/src/components/stepper/__tests__/CStepper.spec.tsx +24 -21
  374. package/src/components/stepper/__tests__/__snapshots__/CStepper.spec.tsx.snap +295 -0
  375. package/src/components/table/CTableDataCell.tsx +2 -1
  376. package/src/components/table/types.ts +3 -1
  377. package/src/components/table/utils.ts +4 -4
  378. package/src/components/tabs/CTabPanel.tsx +3 -1
  379. package/src/components/tabs/CTabsContext.ts +1 -1
  380. package/src/components/tabs/__tests__/CTabContent.spec.tsx +1 -0
  381. package/src/components/tabs/__tests__/CTabPane.spec.tsx +1 -0
  382. package/src/components/time-picker/CTimePicker.tsx +6 -7
  383. package/src/components/time-picker/__tests__/CTimePicker.spec.tsx +10 -1
  384. package/src/components/time-picker/__tests__/__snapshots__/CTimePicker.spec.tsx.snap +599 -315
  385. package/src/components/tooltip/CTooltip.tsx +72 -27
  386. package/src/components/tooltip/__tests__/CTooltip.spec.tsx +102 -1
  387. package/src/components/virtual-scroller/CVirtualScroller.tsx +13 -14
  388. package/src/helpers/polymorphicComponent.ts +1 -1
  389. package/src/hooks/useColorModes.ts +2 -2
  390. package/src/hooks/useDebouncedCallback.ts +7 -4
  391. package/src/hooks/useForkedRef.ts +20 -15
  392. package/src/hooks/usePopper.ts +13 -9
  393. package/src/utils/__tests__/swipe.spec.ts +82 -0
  394. package/src/utils/executeAfterTransition.ts +1 -1
  395. package/src/utils/index.ts +2 -0
  396. package/src/utils/mergeClassNames.ts +1 -1
  397. package/src/utils/swipe.ts +114 -0
  398. package/dist/cjs/components/accordion/CAccordionCollapse.d.ts +0 -3
  399. package/dist/cjs/components/sidebar/CSidebarNavContext.d.ts +0 -5
  400. package/dist/cjs/components/sidebar/CSidebarNavContext.js +0 -8
  401. package/dist/cjs/components/sidebar/CSidebarNavContext.js.map +0 -1
  402. package/dist/esm/components/accordion/CAccordionCollapse.d.ts +0 -3
  403. package/dist/esm/components/sidebar/CSidebarNavContext.d.ts +0 -5
  404. package/dist/esm/components/sidebar/CSidebarNavContext.js +0 -6
  405. package/dist/esm/components/sidebar/CSidebarNavContext.js.map +0 -1
  406. package/src/components/accordion/CAccordionCollapse.tsx +0 -20
  407. package/src/components/accordion/__tests__/CAccordionCollapse.spec.tsx +0 -10
  408. package/src/components/accordion/__tests__/__snapshots__/CAccordionCollapse.spec.tsx.snap +0 -11
  409. package/src/components/button/__tests__/__snapshots__/CButtonClose.spec.tsx.snap +0 -26
  410. package/src/components/calendar/__tests__/CCalendar.accessibility.spec.tsx +0 -595
  411. package/src/components/calendar/__tests__/CCalendar.comprehensive.spec.tsx +0 -402
  412. package/src/components/calendar/__tests__/CCalendar.edge-cases.spec.tsx +0 -416
  413. package/src/components/calendar/__tests__/CCalendar.interactions.spec.tsx +0 -593
  414. package/src/components/header/CHeaderBrand.tsx~HEAD +0 -36
  415. package/src/components/sidebar/CSidebarNavContext.ts +0 -8
  416. /package/src/components/calendar/__tests__/{test-setup.ts → setup.ts} +0 -0
@@ -4,8 +4,11 @@ import React, {
4
4
  forwardRef,
5
5
  HTMLAttributes,
6
6
  ReactNode,
7
+ useCallback,
7
8
  useContext,
8
9
  useEffect,
10
+ useId,
11
+ useMemo,
9
12
  useRef,
10
13
  useState,
11
14
  } from 'react'
@@ -16,8 +19,7 @@ import type { TransitionStatus } from 'react-transition-group'
16
19
 
17
20
  import { PolymorphicRefForwardingComponent } from '../../helpers'
18
21
 
19
- import { CSidebarNavContext } from '../sidebar/CSidebarNavContext'
20
-
22
+ import { CNavGroupContext, CNavGroupContextValue } from './CNavGroupContext'
21
23
  export interface CNavGroupProps extends HTMLAttributes<HTMLDivElement | HTMLLIElement> {
22
24
  /**
23
25
  * Component used for the root node. Either a string to use a HTML element or a component.
@@ -34,140 +36,229 @@ export interface CNavGroupProps extends HTMLAttributes<HTMLDivElement | HTMLLIEl
34
36
  */
35
37
  compact?: boolean
36
38
  /**
37
- * Set group toggler label.
39
+ * Callback fired when the user toggles the group. Receives the requested visibility. Provide
40
+ * it together with `visible` for controlled mode—update `visible` from here, or ignore the
41
+ * change to keep the group as is.
42
+ *
43
+ * @since 5.12.0
38
44
  */
39
- toggler?: string | ReactNode
45
+ onVisibleChange?: (visible: boolean) => void
40
46
  /**
41
- * Show nav group items.
47
+ * Set group toggler label.
42
48
  */
43
- visible?: boolean
49
+ toggler?: string | ReactNode | (({ visible }: { visible: boolean }) => ReactNode)
44
50
  /**
45
- * @ignore
51
+ * Show nav group items. Acts as the initial state when used on its own, or as the controlled
52
+ * value when paired with `onVisibleChange`.
46
53
  */
47
- idx?: string
48
- }
49
-
50
- const isInVisibleGroup = (el1: string, el2: string) => {
51
- const array1 = el1.toString().split('.')
52
- const array2 = el2.toString().split('.')
53
-
54
- return array2.every((item, index) => item === array1[index])
54
+ visible?: boolean
55
55
  }
56
56
 
57
57
  export const CNavGroup: PolymorphicRefForwardingComponent<'li', CNavGroupProps> = forwardRef<
58
58
  HTMLDivElement | HTMLLIElement,
59
59
  CNavGroupProps
60
- >(({ children, as: Component = 'li', className, compact, idx, toggler, visible, ...rest }, ref) => {
61
- const [height, setHeight] = useState<number | string>(0)
62
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
63
- const navItemsRef = useRef<any>(null)
60
+ >(
61
+ (
62
+ {
63
+ children,
64
+ as: Component = 'li',
65
+ className,
66
+ compact,
67
+ onVisibleChange,
68
+ toggler,
69
+ visible,
70
+ ...rest
71
+ },
72
+ ref
73
+ ) => {
74
+ const id = useId()
75
+
76
+ // Accordion of the parent level: lets this group read whether it is the open one and request
77
+ // its own open/close. `null` when rendered outside a `CSidebarNav`.
78
+ const parentContext = useContext(CNavGroupContext)
79
+ const parentContextRef = useRef(parentContext)
80
+ parentContextRef.current = parentContext
81
+
82
+ const [height, setHeight] = useState<number | string>(0)
83
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
84
+ const navItemsRef = useRef<any>(null)
85
+
86
+ const [uncontrolledVisible, setUncontrolledVisible] = useState(Boolean(visible))
87
+ // This group's own accordion state for its children. It survives the group being collapsed,
88
+ // so reopening the group restores whichever child was previously open.
89
+ const [activeChildId, setActiveChildId] = useState<string | undefined>()
90
+
91
+ const controlled = visible !== undefined && onVisibleChange !== undefined
92
+
93
+ const _visible = controlled
94
+ ? Boolean(visible)
95
+ : parentContext
96
+ ? parentContext.activeId === id
97
+ : uncontrolledVisible
98
+
99
+ // Sync the accordion with the `visible` prop: seeds default-open groups and follows later
100
+ // changes (and keeps controlled groups in sync). Watching only `visible` keeps this from
101
+ // re-running on unrelated accordion updates—so a default-open group can be collapsed manually.
102
+ useEffect(() => {
103
+ if (visible === undefined) {
104
+ return
105
+ }
106
+
107
+ const parentSetActiveId = parentContextRef.current?.setActiveId
108
+ if (parentSetActiveId) {
109
+ if (visible) {
110
+ parentSetActiveId(id)
111
+ } else {
112
+ parentSetActiveId((prev) => (prev === id ? undefined : prev))
113
+ }
114
+ } else {
115
+ setUncontrolledVisible(visible)
116
+ }
117
+ }, [visible, id])
64
118
 
65
- const { visibleGroup, setVisibleGroup } = useContext(CSidebarNavContext)
119
+ // Accordion: when another branch opens, a controlled group must close too. As its visibility
120
+ // is owned by the parent, request the change through `onVisibleChange`.
121
+ useEffect(() => {
122
+ if (!controlled || !visible) {
123
+ return
124
+ }
66
125
 
67
- const [_visible, setVisible] = useState(
68
- Boolean(visible || (idx && visibleGroup && isInVisibleGroup(visibleGroup, idx)))
69
- )
126
+ const activeId = parentContext?.activeId
127
+ if (activeId !== undefined && activeId !== id) {
128
+ onVisibleChange?.(false)
129
+ }
130
+ }, [controlled, visible, parentContext?.activeId, id, onVisibleChange])
70
131
 
71
- useEffect(() => {
72
- setVisible(Boolean(idx && visibleGroup && isInVisibleGroup(visibleGroup, idx)))
73
- }, [visibleGroup])
132
+ // Open this group within its parent level and cascade up to the root, revealing the whole
133
+ // branch. Used by an active nav link and by nested groups to bubble the request upwards.
134
+ const openBranch = useCallback(() => {
135
+ const parent = parentContextRef.current
136
+ if (!parent) {
137
+ return
138
+ }
74
139
 
75
- const handleTogglerOnCLick = (event: React.MouseEvent<HTMLElement>) => {
76
- event.preventDefault()
77
- setVisibleGroup(
78
- _visible ? (idx?.toString().includes('.') ? idx.slice(0, idx.lastIndexOf('.')) : '') : idx
140
+ parent.setActiveId(id)
141
+ parent.openBranch()
142
+ }, [id])
143
+
144
+ const childContextValue = useMemo<CNavGroupContextValue>(
145
+ () => ({ activeId: activeChildId, setActiveId: setActiveChildId, openBranch }),
146
+ [activeChildId, openBranch]
79
147
  )
80
- setVisible(!_visible)
81
- }
82
148
 
83
- const style: CSSProperties = {
84
- height: 0,
85
- }
149
+ const handleTogglerOnClick = (event: React.MouseEvent<HTMLElement>) => {
150
+ event.preventDefault()
151
+ const next = !_visible
86
152
 
87
- const onEntering = () => {
88
- navItemsRef.current && setHeight(navItemsRef.current.scrollHeight)
89
- }
153
+ if (!controlled) {
154
+ if (parentContext) {
155
+ parentContext.setActiveId(next ? id : undefined)
156
+ } else {
157
+ setUncontrolledVisible(next)
158
+ }
159
+ }
90
160
 
91
- const onEntered = () => {
92
- setHeight('auto')
93
- }
161
+ onVisibleChange?.(next)
162
+ }
94
163
 
95
- const onExit = () => {
96
- navItemsRef.current && setHeight(navItemsRef.current.scrollHeight)
97
- }
164
+ const style: CSSProperties = {
165
+ height: 0,
166
+ }
98
167
 
99
- const onExiting = () => {
100
- // @ts-expect-error reflow is necessary to get correct height of the element
101
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
102
- const reflow = navItemsRef.current?.offsetHeight
103
- setHeight(0)
104
- }
168
+ const onEntering = () => {
169
+ if (navItemsRef.current) {
170
+ setHeight(navItemsRef.current.scrollHeight)
171
+ }
172
+ }
105
173
 
106
- const onExited = () => {
107
- setHeight(0)
108
- }
174
+ const onEntered = () => {
175
+ setHeight('auto')
176
+ }
109
177
 
110
- const transitionStyles = {
111
- entering: { display: 'block', height: height },
112
- entered: { display: 'block', height: height },
113
- exiting: { display: 'block', height: height },
114
- exited: { height: height },
115
- unmounted: {},
116
- }
178
+ const onExit = () => {
179
+ if (navItemsRef.current) {
180
+ setHeight(navItemsRef.current.scrollHeight)
181
+ }
182
+ }
183
+
184
+ const onExiting = () => {
185
+ // @ts-expect-error reflow is necessary to get correct height of the element
186
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
187
+ const reflow = navItemsRef.current?.offsetHeight
188
+ setHeight(0)
189
+ }
190
+
191
+ const onExited = () => {
192
+ setHeight(0)
193
+ }
194
+
195
+ const transitionStyles = {
196
+ entering: { display: 'block', height: height },
197
+ entered: { display: 'block', height: height },
198
+ exiting: { display: 'block', height: height },
199
+ exited: { height: height },
200
+ unmounted: {},
201
+ }
117
202
 
118
- const NavGroupItemsComponent = Component === 'li' ? 'ul' : 'div'
119
-
120
- return (
121
- <Component
122
- className={classNames('nav-group', { show: _visible }, className)}
123
- {...rest}
124
- ref={ref}
125
- >
126
- {toggler && (
127
- <a
128
- className="nav-link nav-group-toggle"
129
- href="#"
130
- onClick={(event) => handleTogglerOnCLick(event)}
203
+ const NavGroupItemsComponent = Component === 'li' ? 'ul' : 'div'
204
+ const togglerContent = typeof toggler === 'function' ? toggler({ visible: _visible }) : toggler
205
+
206
+ return (
207
+ <CNavGroupContext.Provider value={childContextValue}>
208
+ <Component
209
+ className={classNames('nav-group', { show: _visible }, className)}
210
+ {...rest}
211
+ ref={ref}
131
212
  >
132
- {toggler}
133
- </a>
134
- )}
135
- <Transition
136
- in={_visible}
137
- nodeRef={navItemsRef}
138
- onEntering={onEntering}
139
- onEntered={onEntered}
140
- onExit={onExit}
141
- onExiting={onExiting}
142
- onExited={onExited}
143
- timeout={300}
144
- >
145
- {(state) => (
146
- <NavGroupItemsComponent
147
- className={classNames('nav-group-items', {
148
- compact: compact,
149
- })}
150
- style={{
151
- ...style,
152
- ...transitionStyles[state as TransitionStatus],
153
- }}
154
- ref={navItemsRef}
213
+ {toggler && (
214
+ <a
215
+ aria-expanded={_visible}
216
+ className="nav-link nav-group-toggle"
217
+ href="#"
218
+ onClick={handleTogglerOnClick}
219
+ >
220
+ {togglerContent}
221
+ </a>
222
+ )}
223
+ <Transition
224
+ appear
225
+ in={_visible}
226
+ nodeRef={navItemsRef}
227
+ onEntering={onEntering}
228
+ onEntered={onEntered}
229
+ onExit={onExit}
230
+ onExiting={onExiting}
231
+ onExited={onExited}
232
+ timeout={300}
155
233
  >
156
- {children}
157
- </NavGroupItemsComponent>
158
- )}
159
- </Transition>
160
- </Component>
161
- )
162
- })
234
+ {(state) => (
235
+ <NavGroupItemsComponent
236
+ className={classNames('nav-group-items', {
237
+ compact: compact,
238
+ })}
239
+ style={{
240
+ ...style,
241
+ ...transitionStyles[state as TransitionStatus],
242
+ }}
243
+ ref={navItemsRef}
244
+ >
245
+ {children}
246
+ </NavGroupItemsComponent>
247
+ )}
248
+ </Transition>
249
+ </Component>
250
+ </CNavGroupContext.Provider>
251
+ )
252
+ }
253
+ )
163
254
 
164
255
  CNavGroup.propTypes = {
165
256
  as: PropTypes.elementType,
166
257
  children: PropTypes.node,
167
258
  className: PropTypes.string,
168
259
  compact: PropTypes.bool,
169
- idx: PropTypes.string,
170
- toggler: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
260
+ onVisibleChange: PropTypes.func,
261
+ toggler: PropTypes.oneOfType([PropTypes.string, PropTypes.node, PropTypes.func]),
171
262
  visible: PropTypes.bool,
172
263
  }
173
264
 
@@ -0,0 +1,27 @@
1
+ import { createContext, Dispatch, SetStateAction } from 'react'
2
+
3
+ export interface CNavGroupContextValue {
4
+ /**
5
+ * The id of the currently open child group at this level, or `undefined` when none is open.
6
+ * Each `CNavGroup` keeps its own accordion state, so collapsing an ancestor never discards the
7
+ * open/closed state of its descendants—reopening the ancestor restores them.
8
+ */
9
+ activeId: string | undefined
10
+ /**
11
+ * Open (or, with `undefined`, close) a child group at this level. Opening a group collapses its
12
+ * siblings, mirroring the vanilla `groupsAutoCollapse` behavior.
13
+ */
14
+ setActiveId: Dispatch<SetStateAction<string | undefined>>
15
+ /**
16
+ * Open the whole branch from the parent group up to the root. Used by an active nav link to
17
+ * reveal every ancestor group.
18
+ */
19
+ openBranch: () => void
20
+ }
21
+
22
+ /**
23
+ * Provides the per-level accordion state to the direct children (`CNavGroup`, `CNavLink`) of a
24
+ * `CSidebarNav` or a parent `CNavGroup`. `null` means the consumer is rendered outside a sidebar
25
+ * navigation, in which case groups fall back to their own local state.
26
+ */
27
+ export const CNavGroupContext = createContext<CNavGroupContextValue | null>(null)
@@ -3,16 +3,12 @@ import PropTypes from 'prop-types'
3
3
  import classNames from 'classnames'
4
4
 
5
5
  import { CLinkProps, CLink } from '../link/CLink'
6
- import { CSidebarNavContext } from '../sidebar/CSidebarNavContext'
6
+ import { CNavGroupContext } from './CNavGroupContext'
7
7
 
8
8
  import { PolymorphicRefForwardingComponent } from '../../helpers'
9
9
  import { useForkedRef } from '../../hooks'
10
10
 
11
- export interface CNavLinkProps extends Omit<CLinkProps, 'idx'> {
12
- /**
13
- * @ignore
14
- */
15
- idx?: string
11
+ export interface CNavLinkProps extends CLinkProps {
16
12
  /**
17
13
  * @ignore
18
14
  */
@@ -22,16 +18,35 @@ export interface CNavLinkProps extends Omit<CLinkProps, 'idx'> {
22
18
  export const CNavLink: PolymorphicRefForwardingComponent<'a', CNavLinkProps> = forwardRef<
23
19
  HTMLButtonElement | HTMLAnchorElement,
24
20
  CNavLinkProps
25
- >(({ children, className, idx, ...rest }, ref) => {
21
+ >(({ children, className, ...rest }, ref) => {
26
22
  const navLinkRef = useRef<HTMLAnchorElement>(null)
27
23
  const forkedRef = useForkedRef(ref, navLinkRef)
28
24
 
29
- const { setVisibleGroup } = useContext(CSidebarNavContext)
25
+ const openBranch = useContext(CNavGroupContext)?.openBranch
30
26
 
31
27
  useEffect(() => {
32
- rest.active = navLinkRef.current?.classList.contains('active')
33
- idx && rest.active && setVisibleGroup(idx)
34
- }, [rest.active, className])
28
+ const element = navLinkRef.current
29
+
30
+ if (!element || !openBranch) {
31
+ return
32
+ }
33
+
34
+ let wasActive = false
35
+ const sync = () => {
36
+ const active = element.classList.contains('active')
37
+ if (active && !wasActive) {
38
+ openBranch()
39
+ }
40
+
41
+ wasActive = active
42
+ }
43
+
44
+ sync()
45
+ const observer = new MutationObserver(sync)
46
+ observer.observe(element, { attributes: true, attributeFilter: ['class'] })
47
+
48
+ return () => observer.disconnect()
49
+ }, [openBranch])
35
50
 
36
51
  return (
37
52
  <CLink className={classNames('nav-link', className)} {...rest} ref={forkedRef}>
@@ -46,7 +61,6 @@ CNavLink.propTypes = {
46
61
  children: PropTypes.node,
47
62
  className: PropTypes.string,
48
63
  disabled: PropTypes.bool,
49
- idx: PropTypes.string,
50
64
  }
51
65
 
52
66
  CNavLink.displayName = 'CNavLink'
@@ -1,7 +1,8 @@
1
1
  import * as React from 'react'
2
- import { render } from '@testing-library/react'
2
+ import { fireEvent, render, screen } from '@testing-library/react'
3
3
  import '@testing-library/jest-dom'
4
- import { CNavGroup } from '../index'
4
+ import { CNavGroup, CNavItem } from '../index'
5
+ import { CSidebarNav } from '../../sidebar/CSidebarNav'
5
6
 
6
7
  test('loads and displays CNavGroup component', async () => {
7
8
  const { container } = render(<CNavGroup toggler="anchorText" />)
@@ -10,16 +11,218 @@ test('loads and displays CNavGroup component', async () => {
10
11
 
11
12
  test('CNavGroup customize', async () => {
12
13
  const { container } = render(
13
- <CNavGroup className="bazinga" toggler="anchorText" visible={true} idx="1" />
14
+ <CNavGroup className="bazinga" toggler="anchorText" visible={true} />
14
15
  )
15
16
  expect(container).toMatchSnapshot()
16
17
  expect(container.firstChild).toHaveClass('nav-group')
17
18
  expect(container.firstChild).toHaveClass('bazinga')
18
19
  const arr = container.getElementsByClassName('nav-link')
19
20
  if (arr.length > 0) {
20
- //expect(arr[0].innerText).toHaveTextContent('anchorText')
21
21
  expect(arr[0].innerHTML).toBe('anchorText')
22
22
  } else {
23
23
  expect(true).toBe(false)
24
24
  }
25
25
  })
26
+
27
+ test('CNavGroup toggles its own visibility when uncontrolled', async () => {
28
+ const { container } = render(
29
+ <CSidebarNav>
30
+ <CNavGroup toggler="anchorText">
31
+ <CNavItem href="#">Item</CNavItem>
32
+ </CNavGroup>
33
+ </CSidebarNav>
34
+ )
35
+
36
+ const group = container.querySelector('.nav-group') as HTMLElement
37
+ expect(group).not.toHaveClass('show')
38
+
39
+ fireEvent.click(container.querySelector('.nav-group-toggle') as HTMLElement)
40
+ expect(group).toHaveClass('show')
41
+
42
+ fireEvent.click(container.querySelector('.nav-group-toggle') as HTMLElement)
43
+ expect(group).not.toHaveClass('show')
44
+ })
45
+
46
+ test('CNavGroup follows the visible prop in controlled mode', async () => {
47
+ const { container, rerender } = render(<CNavGroup toggler="anchorText" visible={true} />)
48
+ expect(container.querySelector('.nav-group')).toHaveClass('show')
49
+
50
+ rerender(<CNavGroup toggler="anchorText" visible={false} />)
51
+ expect(container.querySelector('.nav-group')).not.toHaveClass('show')
52
+ })
53
+
54
+ test('CNavGroup stays open when the parent rejects the collapse (controlled)', async () => {
55
+ const onVisibleChange = jest.fn()
56
+ const { container } = render(
57
+ <CNavGroup toggler="anchorText" visible={true} onVisibleChange={onVisibleChange} />
58
+ )
59
+
60
+ expect(container.querySelector('.nav-group')).toHaveClass('show')
61
+
62
+ // Parent keeps `visible` at `true` (rejects the collapse).
63
+ fireEvent.click(container.querySelector('.nav-group-toggle') as HTMLElement)
64
+
65
+ expect(onVisibleChange).toHaveBeenCalledWith(false)
66
+ expect(container.querySelector('.nav-group')).toHaveClass('show')
67
+ })
68
+
69
+ test('CNavGroup toggler render function receives visible state', async () => {
70
+ render(<CNavGroup toggler={({ visible }) => <span>{visible ? 'expanded' : 'collapsed'}</span>} />)
71
+
72
+ expect(screen.getByText('collapsed')).toBeInTheDocument()
73
+
74
+ fireEvent.click(screen.getByRole('link'))
75
+
76
+ expect(screen.getByText('expanded')).toBeInTheDocument()
77
+ })
78
+
79
+ test('an active nav link opens its parent group', async () => {
80
+ const { container } = render(
81
+ <CSidebarNav>
82
+ <CNavGroup toggler="anchorText">
83
+ <CNavItem href="#" active>
84
+ Item
85
+ </CNavItem>
86
+ </CNavGroup>
87
+ </CSidebarNav>
88
+ )
89
+
90
+ expect(container.querySelector('.nav-group')).toHaveClass('show')
91
+ })
92
+
93
+ test('opening another group closes a controlled group when the parent accepts', async () => {
94
+ const Wrapper = () => {
95
+ const [visible, setVisible] = React.useState(true)
96
+ return (
97
+ <CSidebarNav>
98
+ <CNavGroup toggler="Controlled" visible={visible} onVisibleChange={setVisible}>
99
+ <CNavItem href="#">A</CNavItem>
100
+ </CNavGroup>
101
+ <CNavGroup toggler="Other">
102
+ <CNavItem href="#">B</CNavItem>
103
+ </CNavGroup>
104
+ </CSidebarNav>
105
+ )
106
+ }
107
+
108
+ const { container } = render(<Wrapper />)
109
+ const [controlled, other] = Array.from(container.querySelectorAll('.nav-group'))
110
+ expect(controlled).toHaveClass('show')
111
+
112
+ fireEvent.click(container.querySelectorAll('.nav-group-toggle')[1] as HTMLElement)
113
+
114
+ expect(other).toHaveClass('show')
115
+ expect(controlled).not.toHaveClass('show')
116
+ })
117
+
118
+ test('a locked controlled group stays open when another group opens', async () => {
119
+ const Wrapper = () => {
120
+ const [visible, setVisible] = React.useState(true)
121
+ const onVisibleChange = (value: boolean) => {
122
+ if (value) {
123
+ setVisible(true)
124
+ }
125
+ }
126
+ return (
127
+ <CSidebarNav>
128
+ <CNavGroup toggler="Locked" visible={visible} onVisibleChange={onVisibleChange}>
129
+ <CNavItem href="#">A</CNavItem>
130
+ </CNavGroup>
131
+ <CNavGroup toggler="Other">
132
+ <CNavItem href="#">B</CNavItem>
133
+ </CNavGroup>
134
+ </CSidebarNav>
135
+ )
136
+ }
137
+
138
+ const { container } = render(<Wrapper />)
139
+ const [locked, other] = Array.from(container.querySelectorAll('.nav-group'))
140
+ expect(locked).toHaveClass('show')
141
+
142
+ fireEvent.click(container.querySelectorAll('.nav-group-toggle')[1] as HTMLElement)
143
+
144
+ expect(other).toHaveClass('show')
145
+ expect(locked).toHaveClass('show')
146
+ })
147
+
148
+ test('opening an uncontrolled group collapses its sibling', async () => {
149
+ const { container } = render(
150
+ <CSidebarNav>
151
+ <CNavGroup toggler="A">
152
+ <CNavItem href="#">Item</CNavItem>
153
+ </CNavGroup>
154
+ <CNavGroup toggler="B">
155
+ <CNavItem href="#">Item</CNavItem>
156
+ </CNavGroup>
157
+ </CSidebarNav>
158
+ )
159
+
160
+ const [groupA, groupB] = Array.from(container.querySelectorAll('.nav-group'))
161
+ const [togglerA, togglerB] = Array.from(container.querySelectorAll('.nav-group-toggle'))
162
+
163
+ fireEvent.click(togglerA as HTMLElement)
164
+ expect(groupA).toHaveClass('show')
165
+ expect(groupB).not.toHaveClass('show')
166
+
167
+ fireEvent.click(togglerB as HTMLElement)
168
+ expect(groupA).not.toHaveClass('show')
169
+ expect(groupB).toHaveClass('show')
170
+ })
171
+
172
+ test('reopening a parent restores the open state of its nested subgroups', async () => {
173
+ const { container } = render(
174
+ <CSidebarNav>
175
+ <CNavGroup toggler="A" visible>
176
+ <CNavGroup toggler="B" visible>
177
+ <CNavGroup toggler="C" visible>
178
+ <CNavItem href="#">Item</CNavItem>
179
+ </CNavGroup>
180
+ </CNavGroup>
181
+ </CNavGroup>
182
+ </CSidebarNav>
183
+ )
184
+
185
+ const [groupA, groupB, groupC] = Array.from(container.querySelectorAll('.nav-group'))
186
+ expect(groupA).toHaveClass('show')
187
+ expect(groupB).toHaveClass('show')
188
+ expect(groupC).toHaveClass('show')
189
+
190
+ const outerToggler = container.querySelectorAll('.nav-group-toggle')[0] as HTMLElement
191
+
192
+ // Collapse the parent: the whole branch is hidden.
193
+ fireEvent.click(outerToggler)
194
+ expect(groupA).not.toHaveClass('show')
195
+
196
+ // Reopen the parent: nested subgroups come back open (matches vanilla/Vue).
197
+ fireEvent.click(outerToggler)
198
+ expect(groupA).toHaveClass('show')
199
+ expect(groupB).toHaveClass('show')
200
+ expect(groupC).toHaveClass('show')
201
+ })
202
+
203
+ test('nested default-open groups render open and stay independently toggleable', async () => {
204
+ const { container } = render(
205
+ <CSidebarNav>
206
+ <CNavGroup toggler="Group A" visible>
207
+ <CNavGroup toggler="Group B" visible>
208
+ <CNavItem href="#">Item</CNavItem>
209
+ </CNavGroup>
210
+ </CNavGroup>
211
+ </CSidebarNav>
212
+ )
213
+
214
+ const [groupA, groupB] = Array.from(container.querySelectorAll('.nav-group'))
215
+ expect(groupA).toHaveClass('show')
216
+ expect(groupB).toHaveClass('show')
217
+
218
+ // Collapsing the inner group keeps the outer one open.
219
+ const innerToggler = container.querySelectorAll('.nav-group-toggle')[1] as HTMLElement
220
+ fireEvent.click(innerToggler)
221
+ expect(groupA).toHaveClass('show')
222
+ expect(groupB).not.toHaveClass('show')
223
+
224
+ // Collapsing the outer group closes the whole branch.
225
+ const outerToggler = container.querySelectorAll('.nav-group-toggle')[0] as HTMLElement
226
+ fireEvent.click(outerToggler)
227
+ expect(groupA).not.toHaveClass('show')
228
+ })