@coreui/react-pro 5.25.0 → 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 (291) hide show
  1. package/dist/cjs/components/card/CCardImage.js.map +1 -1
  2. package/dist/cjs/components/carousel/CCarousel.js +44 -33
  3. package/dist/cjs/components/carousel/CCarousel.js.map +1 -1
  4. package/dist/cjs/components/carousel/CCarouselItem.js +19 -28
  5. package/dist/cjs/components/carousel/CCarouselItem.js.map +1 -1
  6. package/dist/cjs/components/chip/CChip.d.ts +12 -0
  7. package/dist/cjs/components/chip/CChip.js +16 -63
  8. package/dist/cjs/components/chip/CChip.js.map +1 -1
  9. package/dist/cjs/components/chip/const.d.ts +1 -0
  10. package/dist/cjs/components/chip/const.js +8 -0
  11. package/dist/cjs/components/chip/const.js.map +1 -0
  12. package/dist/cjs/components/chip-set/CChipSet.d.ts +73 -0
  13. package/dist/cjs/components/chip-set/CChipSet.js +66 -0
  14. package/dist/cjs/components/chip-set/CChipSet.js.map +1 -0
  15. package/dist/cjs/components/chip-set/index.d.ts +2 -0
  16. package/dist/cjs/components/chip-set/useChipSet.d.ts +48 -0
  17. package/dist/cjs/components/chip-set/useChipSet.js +163 -0
  18. package/dist/cjs/components/chip-set/useChipSet.js.map +1 -0
  19. package/dist/cjs/components/chip-set/utils.d.ts +7 -0
  20. package/dist/cjs/components/chip-set/utils.js +18 -0
  21. package/dist/cjs/components/chip-set/utils.js.map +1 -0
  22. package/dist/cjs/components/collapse/CCollapse.js +14 -6
  23. package/dist/cjs/components/collapse/CCollapse.js.map +1 -1
  24. package/dist/cjs/components/conditional-portal/CConditionalPortal.js +3 -1
  25. package/dist/cjs/components/conditional-portal/CConditionalPortal.js.map +1 -1
  26. package/dist/cjs/components/dropdown/CDropdown.js +22 -29
  27. package/dist/cjs/components/dropdown/CDropdown.js.map +1 -1
  28. package/dist/cjs/components/dropdown/CDropdownToggle.js.map +1 -1
  29. package/dist/cjs/components/form/CChipInput.d.ts +14 -2
  30. package/dist/cjs/components/form/CChipInput.js +77 -49
  31. package/dist/cjs/components/form/CChipInput.js.map +1 -1
  32. package/dist/cjs/components/form/CFormCheck.js.map +1 -1
  33. package/dist/cjs/components/form/CFormInput.js.map +1 -1
  34. package/dist/cjs/components/form/CFormSelect.js.map +1 -1
  35. package/dist/cjs/components/form/CFormTextarea.js.map +1 -1
  36. package/dist/cjs/components/form/CInputGroupText.js.map +1 -1
  37. package/dist/cjs/components/grid/CContainer.js +3 -1
  38. package/dist/cjs/components/grid/CContainer.js.map +1 -1
  39. package/dist/cjs/components/header/CHeaderBrand.js.map +1 -1
  40. package/dist/cjs/components/index.d.ts +1 -0
  41. package/dist/cjs/components/link/CLink.js +4 -2
  42. package/dist/cjs/components/link/CLink.js.map +1 -1
  43. package/dist/cjs/components/list-group/CListGroupItem.js.map +1 -1
  44. package/dist/cjs/components/modal/CModal.js +14 -2
  45. package/dist/cjs/components/modal/CModal.js.map +1 -1
  46. package/dist/cjs/components/multi-select/CMultiSelect.d.ts +73 -1
  47. package/dist/cjs/components/multi-select/CMultiSelect.js +157 -18
  48. package/dist/cjs/components/multi-select/CMultiSelect.js.map +1 -1
  49. package/dist/cjs/components/multi-select/CMultiSelectNativeSelect.js +1 -1
  50. package/dist/cjs/components/multi-select/CMultiSelectNativeSelect.js.map +1 -1
  51. package/dist/cjs/components/multi-select/CMultiSelectOptions.d.ts +3 -0
  52. package/dist/cjs/components/multi-select/CMultiSelectOptions.js +45 -2
  53. package/dist/cjs/components/multi-select/CMultiSelectOptions.js.map +1 -1
  54. package/dist/cjs/components/multi-select/CMultiSelectSelection.d.ts +1 -0
  55. package/dist/cjs/components/multi-select/CMultiSelectSelection.js +4 -3
  56. package/dist/cjs/components/multi-select/CMultiSelectSelection.js.map +1 -1
  57. package/dist/cjs/components/multi-select/types.d.ts +12 -0
  58. package/dist/cjs/components/multi-select/utils.js +1 -4
  59. package/dist/cjs/components/multi-select/utils.js.map +1 -1
  60. package/dist/cjs/components/nav/CNav.js.map +1 -1
  61. package/dist/cjs/components/nav/CNavGroup.d.ts +10 -5
  62. package/dist/cjs/components/nav/CNavGroup.js +83 -24
  63. package/dist/cjs/components/nav/CNavGroup.js.map +1 -1
  64. package/dist/cjs/components/nav/CNavGroupContext.d.ts +25 -0
  65. package/dist/cjs/components/nav/CNavGroupContext.js +13 -0
  66. package/dist/cjs/components/nav/CNavGroupContext.js.map +1 -0
  67. package/dist/cjs/components/nav/CNavLink.d.ts +1 -5
  68. package/dist/cjs/components/nav/CNavLink.js +21 -8
  69. package/dist/cjs/components/nav/CNavLink.js.map +1 -1
  70. package/dist/cjs/components/popover/CPopover.js +57 -9
  71. package/dist/cjs/components/popover/CPopover.js.map +1 -1
  72. package/dist/cjs/components/progress/CProgress.js.map +1 -1
  73. package/dist/cjs/components/rating/CRating.d.ts +1 -1
  74. package/dist/cjs/components/rating/CRating.js.map +1 -1
  75. package/dist/cjs/components/sidebar/CSidebar.js +40 -23
  76. package/dist/cjs/components/sidebar/CSidebar.js.map +1 -1
  77. package/dist/cjs/components/sidebar/CSidebarNav.js +6 -35
  78. package/dist/cjs/components/sidebar/CSidebarNav.js.map +1 -1
  79. package/dist/cjs/components/table/CTableDataCell.js.map +1 -1
  80. package/dist/cjs/components/table/types.d.ts +2 -1
  81. package/dist/cjs/components/table/utils.js +4 -4
  82. package/dist/cjs/components/table/utils.js.map +1 -1
  83. package/dist/cjs/components/tabs/CTabPanel.js +3 -1
  84. package/dist/cjs/components/tabs/CTabPanel.js.map +1 -1
  85. package/dist/cjs/components/tooltip/CTooltip.js +57 -9
  86. package/dist/cjs/components/tooltip/CTooltip.js.map +1 -1
  87. package/dist/cjs/helpers/polymorphicComponent.d.ts +1 -2
  88. package/dist/cjs/hooks/useForkedRef.d.ts +1 -1
  89. package/dist/cjs/hooks/useForkedRef.js +6 -3
  90. package/dist/cjs/hooks/useForkedRef.js.map +1 -1
  91. package/dist/cjs/hooks/usePopper.js +8 -6
  92. package/dist/cjs/hooks/usePopper.js.map +1 -1
  93. package/dist/cjs/index.js +2 -0
  94. package/dist/cjs/index.js.map +1 -1
  95. package/dist/cjs/node_modules/@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js +1 -1
  96. package/dist/cjs/node_modules/@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js.map +1 -1
  97. package/dist/cjs/node_modules/ua-parser-js/dist/ua-parser.min.js +3 -3
  98. package/dist/cjs/node_modules/ua-parser-js/dist/ua-parser.min.js.map +1 -1
  99. package/dist/cjs/utils/executeAfterTransition.js.map +1 -1
  100. package/dist/cjs/utils/index.d.ts +2 -1
  101. package/dist/cjs/utils/swipe.d.ts +26 -0
  102. package/dist/cjs/utils/swipe.js +94 -0
  103. package/dist/cjs/utils/swipe.js.map +1 -0
  104. package/dist/esm/components/card/CCardImage.js.map +1 -1
  105. package/dist/esm/components/carousel/CCarousel.js +44 -33
  106. package/dist/esm/components/carousel/CCarousel.js.map +1 -1
  107. package/dist/esm/components/carousel/CCarouselItem.js +19 -28
  108. package/dist/esm/components/carousel/CCarouselItem.js.map +1 -1
  109. package/dist/esm/components/chip/CChip.d.ts +12 -0
  110. package/dist/esm/components/chip/CChip.js +16 -63
  111. package/dist/esm/components/chip/CChip.js.map +1 -1
  112. package/dist/esm/components/chip/const.d.ts +1 -0
  113. package/dist/esm/components/chip/const.js +6 -0
  114. package/dist/esm/components/chip/const.js.map +1 -0
  115. package/dist/esm/components/chip-set/CChipSet.d.ts +73 -0
  116. package/dist/esm/components/chip-set/CChipSet.js +64 -0
  117. package/dist/esm/components/chip-set/CChipSet.js.map +1 -0
  118. package/dist/esm/components/chip-set/index.d.ts +2 -0
  119. package/dist/esm/components/chip-set/useChipSet.d.ts +48 -0
  120. package/dist/esm/components/chip-set/useChipSet.js +161 -0
  121. package/dist/esm/components/chip-set/useChipSet.js.map +1 -0
  122. package/dist/esm/components/chip-set/utils.d.ts +7 -0
  123. package/dist/esm/components/chip-set/utils.js +16 -0
  124. package/dist/esm/components/chip-set/utils.js.map +1 -0
  125. package/dist/esm/components/collapse/CCollapse.js +14 -6
  126. package/dist/esm/components/collapse/CCollapse.js.map +1 -1
  127. package/dist/esm/components/conditional-portal/CConditionalPortal.js +3 -1
  128. package/dist/esm/components/conditional-portal/CConditionalPortal.js.map +1 -1
  129. package/dist/esm/components/dropdown/CDropdown.js +22 -29
  130. package/dist/esm/components/dropdown/CDropdown.js.map +1 -1
  131. package/dist/esm/components/dropdown/CDropdownToggle.js.map +1 -1
  132. package/dist/esm/components/form/CChipInput.d.ts +14 -2
  133. package/dist/esm/components/form/CChipInput.js +78 -50
  134. package/dist/esm/components/form/CChipInput.js.map +1 -1
  135. package/dist/esm/components/form/CFormCheck.js.map +1 -1
  136. package/dist/esm/components/form/CFormInput.js.map +1 -1
  137. package/dist/esm/components/form/CFormSelect.js.map +1 -1
  138. package/dist/esm/components/form/CFormTextarea.js.map +1 -1
  139. package/dist/esm/components/form/CInputGroupText.js.map +1 -1
  140. package/dist/esm/components/grid/CContainer.js +3 -1
  141. package/dist/esm/components/grid/CContainer.js.map +1 -1
  142. package/dist/esm/components/header/CHeaderBrand.js.map +1 -1
  143. package/dist/esm/components/index.d.ts +1 -0
  144. package/dist/esm/components/link/CLink.js +4 -2
  145. package/dist/esm/components/link/CLink.js.map +1 -1
  146. package/dist/esm/components/list-group/CListGroupItem.js.map +1 -1
  147. package/dist/esm/components/modal/CModal.js +14 -2
  148. package/dist/esm/components/modal/CModal.js.map +1 -1
  149. package/dist/esm/components/multi-select/CMultiSelect.d.ts +73 -1
  150. package/dist/esm/components/multi-select/CMultiSelect.js +158 -19
  151. package/dist/esm/components/multi-select/CMultiSelect.js.map +1 -1
  152. package/dist/esm/components/multi-select/CMultiSelectNativeSelect.js +1 -1
  153. package/dist/esm/components/multi-select/CMultiSelectNativeSelect.js.map +1 -1
  154. package/dist/esm/components/multi-select/CMultiSelectOptions.d.ts +3 -0
  155. package/dist/esm/components/multi-select/CMultiSelectOptions.js +45 -2
  156. package/dist/esm/components/multi-select/CMultiSelectOptions.js.map +1 -1
  157. package/dist/esm/components/multi-select/CMultiSelectSelection.d.ts +1 -0
  158. package/dist/esm/components/multi-select/CMultiSelectSelection.js +4 -3
  159. package/dist/esm/components/multi-select/CMultiSelectSelection.js.map +1 -1
  160. package/dist/esm/components/multi-select/types.d.ts +12 -0
  161. package/dist/esm/components/multi-select/utils.js +1 -4
  162. package/dist/esm/components/multi-select/utils.js.map +1 -1
  163. package/dist/esm/components/nav/CNav.js.map +1 -1
  164. package/dist/esm/components/nav/CNavGroup.d.ts +10 -5
  165. package/dist/esm/components/nav/CNavGroup.js +84 -25
  166. package/dist/esm/components/nav/CNavGroup.js.map +1 -1
  167. package/dist/esm/components/nav/CNavGroupContext.d.ts +25 -0
  168. package/dist/esm/components/nav/CNavGroupContext.js +11 -0
  169. package/dist/esm/components/nav/CNavGroupContext.js.map +1 -0
  170. package/dist/esm/components/nav/CNavLink.d.ts +1 -5
  171. package/dist/esm/components/nav/CNavLink.js +21 -8
  172. package/dist/esm/components/nav/CNavLink.js.map +1 -1
  173. package/dist/esm/components/popover/CPopover.js +57 -9
  174. package/dist/esm/components/popover/CPopover.js.map +1 -1
  175. package/dist/esm/components/progress/CProgress.js.map +1 -1
  176. package/dist/esm/components/rating/CRating.d.ts +1 -1
  177. package/dist/esm/components/rating/CRating.js.map +1 -1
  178. package/dist/esm/components/sidebar/CSidebar.js +40 -23
  179. package/dist/esm/components/sidebar/CSidebar.js.map +1 -1
  180. package/dist/esm/components/sidebar/CSidebarNav.js +7 -36
  181. package/dist/esm/components/sidebar/CSidebarNav.js.map +1 -1
  182. package/dist/esm/components/table/CTableDataCell.js.map +1 -1
  183. package/dist/esm/components/table/types.d.ts +2 -1
  184. package/dist/esm/components/table/utils.js +4 -4
  185. package/dist/esm/components/table/utils.js.map +1 -1
  186. package/dist/esm/components/tabs/CTabPanel.js +3 -1
  187. package/dist/esm/components/tabs/CTabPanel.js.map +1 -1
  188. package/dist/esm/components/tooltip/CTooltip.js +57 -9
  189. package/dist/esm/components/tooltip/CTooltip.js.map +1 -1
  190. package/dist/esm/helpers/polymorphicComponent.d.ts +1 -2
  191. package/dist/esm/hooks/useForkedRef.d.ts +1 -1
  192. package/dist/esm/hooks/useForkedRef.js +6 -3
  193. package/dist/esm/hooks/useForkedRef.js.map +1 -1
  194. package/dist/esm/hooks/usePopper.js +9 -7
  195. package/dist/esm/hooks/usePopper.js.map +1 -1
  196. package/dist/esm/index.js +1 -0
  197. package/dist/esm/index.js.map +1 -1
  198. package/dist/esm/node_modules/@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js +1 -1
  199. package/dist/esm/node_modules/@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js.map +1 -1
  200. package/dist/esm/node_modules/ua-parser-js/dist/ua-parser.min.js +3 -3
  201. package/dist/esm/node_modules/ua-parser-js/dist/ua-parser.min.js.map +1 -1
  202. package/dist/esm/utils/executeAfterTransition.js.map +1 -1
  203. package/dist/esm/utils/index.d.ts +2 -1
  204. package/dist/esm/utils/swipe.d.ts +26 -0
  205. package/dist/esm/utils/swipe.js +90 -0
  206. package/dist/esm/utils/swipe.js.map +1 -0
  207. package/package.json +6 -6
  208. package/src/components/autocomplete/CAutocompleteOptions.tsx +1 -1
  209. package/src/components/card/CCardImage.tsx +3 -2
  210. package/src/components/carousel/CCarousel.tsx +48 -51
  211. package/src/components/carousel/CCarouselContext.ts +1 -1
  212. package/src/components/carousel/CCarouselItem.tsx +25 -26
  213. package/src/components/carousel/__tests__/CCarousel.spec.tsx +47 -4
  214. package/src/components/carousel/__tests__/CCarouselItem.spec.tsx +37 -0
  215. package/src/components/chip/CChip.tsx +45 -78
  216. package/src/components/chip/__tests__/CChip.spec.tsx +26 -19
  217. package/src/components/chip/const.ts +3 -0
  218. package/src/components/chip-set/CChipSet.tsx +183 -0
  219. package/src/components/chip-set/__tests__/CChipSet.spec.tsx +215 -0
  220. package/src/components/chip-set/__tests__/__snapshots__/CChipSet.spec.tsx.snap +22 -0
  221. package/src/components/chip-set/index.ts +3 -0
  222. package/src/components/chip-set/useChipSet.ts +243 -0
  223. package/src/components/chip-set/utils.ts +19 -0
  224. package/src/components/collapse/CCollapse.tsx +18 -6
  225. package/src/components/conditional-portal/CConditionalPortal.tsx +4 -2
  226. package/src/components/dropdown/CDropdown.tsx +28 -33
  227. package/src/components/dropdown/CDropdownToggle.tsx +1 -1
  228. package/src/components/dropdown/__tests__/CDropdown.spec.tsx +55 -0
  229. package/src/components/focus-trap/__tests__/CFocusTrap.spec.tsx +1 -1
  230. package/src/components/form/CChipInput.tsx +105 -67
  231. package/src/components/form/CFormCheck.tsx +1 -2
  232. package/src/components/form/CFormInput.tsx +1 -2
  233. package/src/components/form/CFormSelect.tsx +1 -2
  234. package/src/components/form/CFormTextarea.tsx +1 -2
  235. package/src/components/form/CInputGroupText.tsx +3 -2
  236. package/src/components/form/__tests__/CChipInput.spec.tsx +67 -1
  237. package/src/components/form/__tests__/__snapshots__/CChipInput.spec.tsx.snap +7 -0
  238. package/src/components/grid/CContainer.tsx +3 -1
  239. package/src/components/header/CHeaderBrand.tsx +3 -2
  240. package/src/components/index.ts +1 -0
  241. package/src/components/link/CLink.tsx +7 -4
  242. package/src/components/list-group/CListGroupItem.tsx +3 -2
  243. package/src/components/modal/CModal.tsx +19 -2
  244. package/src/components/modal/__tests__/CModal.spec.tsx +43 -0
  245. package/src/components/multi-select/CMultiSelect.tsx +341 -46
  246. package/src/components/multi-select/CMultiSelectNativeSelect.tsx +1 -1
  247. package/src/components/multi-select/CMultiSelectOptions.tsx +74 -3
  248. package/src/components/multi-select/CMultiSelectSelection.tsx +5 -1
  249. package/src/components/multi-select/__tests__/CMultiSelect.spec.tsx +12 -8
  250. package/src/components/multi-select/__tests__/__snapshots__/CMultiSelect.spec.tsx.snap +62 -45
  251. package/src/components/multi-select/__tests__/__snapshots__/CMultiSelectNativeSelect.spec.tsx.snap +2 -2
  252. package/src/components/multi-select/__tests__/__snapshots__/CMultiSelectOptions.spec.tsx.snap +1 -0
  253. package/src/components/multi-select/__tests__/__snapshots__/CMultiSelectSelection.spec.tsx.snap +5 -1
  254. package/src/components/multi-select/types.ts +14 -0
  255. package/src/components/nav/CNav.tsx +3 -2
  256. package/src/components/nav/CNavGroup.tsx +193 -107
  257. package/src/components/nav/CNavGroupContext.ts +27 -0
  258. package/src/components/nav/CNavLink.tsx +26 -12
  259. package/src/components/nav/__tests__/CNavGroup.spec.tsx +195 -20
  260. package/src/components/nav/__tests__/__snapshots__/CNavGroup.spec.tsx.snap +2 -0
  261. package/src/components/popover/CPopover.tsx +59 -9
  262. package/src/components/popover/__tests__/CPopover.spec.tsx +76 -1
  263. package/src/components/progress/CProgress.tsx +1 -2
  264. package/src/components/rating/CRating.tsx +1 -0
  265. package/src/components/search-button/__tests__/CSearchButton.spec.tsx +2 -2
  266. package/src/components/sidebar/CSidebar.tsx +51 -26
  267. package/src/components/sidebar/CSidebarNav.tsx +12 -51
  268. package/src/components/sidebar/__tests__/CSidebar.spec.tsx +26 -0
  269. package/src/components/table/CTableDataCell.tsx +2 -1
  270. package/src/components/table/types.ts +3 -1
  271. package/src/components/table/utils.ts +4 -4
  272. package/src/components/tabs/CTabPanel.tsx +3 -1
  273. package/src/components/tabs/CTabsContext.ts +1 -1
  274. package/src/components/tooltip/CTooltip.tsx +59 -9
  275. package/src/components/tooltip/__tests__/CTooltip.spec.tsx +96 -1
  276. package/src/helpers/polymorphicComponent.ts +1 -1
  277. package/src/hooks/useColorModes.ts +2 -2
  278. package/src/hooks/useForkedRef.ts +20 -15
  279. package/src/hooks/usePopper.ts +13 -9
  280. package/src/utils/__tests__/swipe.spec.ts +82 -0
  281. package/src/utils/executeAfterTransition.ts +1 -1
  282. package/src/utils/index.ts +2 -0
  283. package/src/utils/mergeClassNames.ts +1 -1
  284. package/src/utils/swipe.ts +114 -0
  285. package/dist/cjs/components/sidebar/CSidebarNavContext.d.ts +0 -5
  286. package/dist/cjs/components/sidebar/CSidebarNavContext.js +0 -8
  287. package/dist/cjs/components/sidebar/CSidebarNavContext.js.map +0 -1
  288. package/dist/esm/components/sidebar/CSidebarNavContext.d.ts +0 -5
  289. package/dist/esm/components/sidebar/CSidebarNavContext.js +0 -6
  290. package/dist/esm/components/sidebar/CSidebarNavContext.js.map +0 -1
  291. package/src/components/sidebar/CSidebarNavContext.ts +0 -8
@@ -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,7 +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'
22
+ import { CNavGroupContext, CNavGroupContextValue } from './CNavGroupContext'
20
23
  export interface CNavGroupProps extends HTMLAttributes<HTMLDivElement | HTMLLIElement> {
21
24
  /**
22
25
  * Component used for the root node. Either a string to use a HTML element or a component.
@@ -32,146 +35,229 @@ export interface CNavGroupProps extends HTMLAttributes<HTMLDivElement | HTMLLIEl
32
35
  * Make nav group more compact by cutting all `padding` in half.
33
36
  */
34
37
  compact?: boolean
38
+ /**
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
44
+ */
45
+ onVisibleChange?: (visible: boolean) => void
35
46
  /**
36
47
  * Set group toggler label.
37
48
  */
38
49
  toggler?: string | ReactNode | (({ visible }: { visible: boolean }) => ReactNode)
39
50
  /**
40
- * Show nav group items.
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`.
41
53
  */
42
54
  visible?: boolean
43
- /**
44
- * @ignore
45
- */
46
- idx?: string
47
- }
48
-
49
- const isInVisibleGroup = (el1: string, el2: string) => {
50
- const array1 = el1.toString().split('.')
51
- const array2 = el2.toString().split('.')
52
-
53
- return array2.every((item, index) => item === array1[index])
54
55
  }
55
56
 
56
57
  export const CNavGroup: PolymorphicRefForwardingComponent<'li', CNavGroupProps> = forwardRef<
57
58
  HTMLDivElement | HTMLLIElement,
58
59
  CNavGroupProps
59
- >(({ children, as: Component = 'li', className, compact, idx, toggler, visible, ...rest }, ref) => {
60
- const [height, setHeight] = useState<number | string>(0)
61
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
62
- 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])
63
118
 
64
- 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
+ }
65
125
 
66
- const [_visible, setVisible] = useState(
67
- Boolean(visible || (idx && visibleGroup && isInVisibleGroup(visibleGroup, idx)))
68
- )
126
+ const activeId = parentContext?.activeId
127
+ if (activeId !== undefined && activeId !== id) {
128
+ onVisibleChange?.(false)
129
+ }
130
+ }, [controlled, visible, parentContext?.activeId, id, onVisibleChange])
69
131
 
70
- useEffect(() => {
71
- visible !== undefined && setVisible(visible)
72
- }, [visible])
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
+ }
73
139
 
74
- useEffect(() => {
75
- visibleGroup && setVisible(Boolean(idx && visibleGroup && isInVisibleGroup(visibleGroup, idx)))
76
- }, [idx, visibleGroup])
140
+ parent.setActiveId(id)
141
+ parent.openBranch()
142
+ }, [id])
77
143
 
78
- const handleTogglerOnCLick = (event: React.MouseEvent<HTMLElement>) => {
79
- event.preventDefault()
80
- setVisibleGroup(
81
- _visible ? (idx?.toString().includes('.') ? idx.slice(0, idx.lastIndexOf('.')) : '') : idx
144
+ const childContextValue = useMemo<CNavGroupContextValue>(
145
+ () => ({ activeId: activeChildId, setActiveId: setActiveChildId, openBranch }),
146
+ [activeChildId, openBranch]
82
147
  )
83
- setVisible(!_visible)
84
- }
85
148
 
86
- const style: CSSProperties = {
87
- height: 0,
88
- }
149
+ const handleTogglerOnClick = (event: React.MouseEvent<HTMLElement>) => {
150
+ event.preventDefault()
151
+ const next = !_visible
89
152
 
90
- const onEntering = () => {
91
- navItemsRef.current && setHeight(navItemsRef.current.scrollHeight)
92
- }
153
+ if (!controlled) {
154
+ if (parentContext) {
155
+ parentContext.setActiveId(next ? id : undefined)
156
+ } else {
157
+ setUncontrolledVisible(next)
158
+ }
159
+ }
93
160
 
94
- const onEntered = () => {
95
- setHeight('auto')
96
- }
161
+ onVisibleChange?.(next)
162
+ }
97
163
 
98
- const onExit = () => {
99
- navItemsRef.current && setHeight(navItemsRef.current.scrollHeight)
100
- }
164
+ const style: CSSProperties = {
165
+ height: 0,
166
+ }
101
167
 
102
- const onExiting = () => {
103
- // @ts-expect-error reflow is necessary to get correct height of the element
104
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
105
- const reflow = navItemsRef.current?.offsetHeight
106
- setHeight(0)
107
- }
168
+ const onEntering = () => {
169
+ if (navItemsRef.current) {
170
+ setHeight(navItemsRef.current.scrollHeight)
171
+ }
172
+ }
108
173
 
109
- const onExited = () => {
110
- setHeight(0)
111
- }
174
+ const onEntered = () => {
175
+ setHeight('auto')
176
+ }
112
177
 
113
- const transitionStyles = {
114
- entering: { display: 'block', height: height },
115
- entered: { display: 'block', height: height },
116
- exiting: { display: 'block', height: height },
117
- exited: { height: height },
118
- unmounted: {},
119
- }
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
+ }
120
202
 
121
- const NavGroupItemsComponent = Component === 'li' ? 'ul' : 'div'
122
- const togglerContent = typeof toggler === 'function' ? toggler({ visible: _visible }) : toggler
123
-
124
- return (
125
- <Component
126
- className={classNames('nav-group', { show: _visible }, className)}
127
- {...rest}
128
- ref={ref}
129
- >
130
- {toggler && (
131
- <a
132
- className="nav-link nav-group-toggle"
133
- href="#"
134
- 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}
135
212
  >
136
- {togglerContent}
137
- </a>
138
- )}
139
- <Transition
140
- appear
141
- in={_visible}
142
- nodeRef={navItemsRef}
143
- onEntering={onEntering}
144
- onEntered={onEntered}
145
- onExit={onExit}
146
- onExiting={onExiting}
147
- onExited={onExited}
148
- timeout={300}
149
- >
150
- {(state) => (
151
- <NavGroupItemsComponent
152
- className={classNames('nav-group-items', {
153
- compact: compact,
154
- })}
155
- style={{
156
- ...style,
157
- ...transitionStyles[state as TransitionStatus],
158
- }}
159
- 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}
160
233
  >
161
- {children}
162
- </NavGroupItemsComponent>
163
- )}
164
- </Transition>
165
- </Component>
166
- )
167
- })
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
+ )
168
254
 
169
255
  CNavGroup.propTypes = {
170
256
  as: PropTypes.elementType,
171
257
  children: PropTypes.node,
172
258
  className: PropTypes.string,
173
259
  compact: PropTypes.bool,
174
- idx: PropTypes.string,
260
+ onVisibleChange: PropTypes.func,
175
261
  toggler: PropTypes.oneOfType([PropTypes.string, PropTypes.node, PropTypes.func]),
176
262
  visible: PropTypes.bool,
177
263
  }
@@ -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'