@coreui/react-pro 5.0.0-alpha.0 → 5.0.0-alpha.2

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 (92) hide show
  1. package/README.md +1 -1
  2. package/dist/components/avatar/CAvatar.d.ts +1 -1
  3. package/dist/components/badge/CBadge.d.ts +1 -1
  4. package/dist/components/calendar/CCalendar.d.ts +25 -7
  5. package/dist/components/calendar/utils.d.ts +12 -3
  6. package/dist/components/card/CCard.d.ts +1 -1
  7. package/dist/components/close-button/CCloseButton.d.ts +6 -0
  8. package/dist/components/dropdown/CDropdown.d.ts +1 -0
  9. package/dist/components/modal/CModal.d.ts +6 -0
  10. package/dist/components/multi-select/types.d.ts +2 -2
  11. package/dist/components/multi-select/utils.d.ts +2 -2
  12. package/dist/components/nav/CNav.d.ts +1 -1
  13. package/dist/components/navbar/CNavbar.d.ts +1 -1
  14. package/dist/components/offcanvas/COffcanvas.d.ts +4 -0
  15. package/dist/components/smart-table/CSmartTableBody.d.ts +2 -1
  16. package/dist/components/smart-table/CSmartTableHead.d.ts +1 -1
  17. package/dist/components/smart-table/CSmartTableInterface.d.ts +1 -3
  18. package/dist/components/smart-table/types.d.ts +2 -2
  19. package/dist/components/smart-table/utils.d.ts +3 -1
  20. package/dist/index.es.js +1468 -1130
  21. package/dist/index.es.js.map +1 -1
  22. package/dist/index.js +1468 -1130
  23. package/dist/index.js.map +1 -1
  24. package/dist/types.d.ts +1 -1
  25. package/dist/utils/executeAfterTransition.d.ts +2 -0
  26. package/dist/utils/getTransitionDurationFromElement.d.ts +2 -0
  27. package/dist/utils/index.d.ts +3 -1
  28. package/package.json +2 -2
  29. package/src/components/avatar/CAvatar.tsx +1 -1
  30. package/src/components/badge/CBadge.tsx +1 -1
  31. package/src/components/button/CButton.tsx +1 -1
  32. package/src/components/button/__tests__/__snapshots__/CButton.spec.tsx.snap +0 -1
  33. package/src/components/calendar/CCalendar.tsx +396 -193
  34. package/src/components/calendar/utils.ts +91 -4
  35. package/src/components/card/CCard.tsx +1 -1
  36. package/src/components/carousel/CCarousel.tsx +9 -5
  37. package/src/components/carousel/__tests__/__snapshots__/CCarousel.spec.tsx.snap +9 -5
  38. package/src/components/close-button/CCloseButton.tsx +9 -1
  39. package/src/components/date-range-picker/CDateRangePicker.tsx +49 -45
  40. package/src/components/dropdown/CDropdown.tsx +43 -1
  41. package/src/components/dropdown/CDropdownMenu.tsx +1 -1
  42. package/src/components/dropdown/CDropdownToggle.tsx +3 -12
  43. package/src/components/modal/CModal.tsx +25 -9
  44. package/src/components/multi-select/CMultiSelect.tsx +3 -3
  45. package/src/components/multi-select/CMultiSelectNativeSelect.tsx +1 -1
  46. package/src/components/multi-select/CMultiSelectOptions.tsx +1 -1
  47. package/src/components/multi-select/CMultiSelectSelection.tsx +3 -3
  48. package/src/components/multi-select/types.ts +2 -2
  49. package/src/components/multi-select/utils.ts +5 -5
  50. package/src/components/nav/CNav.tsx +2 -2
  51. package/src/components/nav/CNavGroup.tsx +9 -2
  52. package/src/components/nav/__tests__/__snapshots__/CNav.spec.tsx.snap +5 -4
  53. package/src/components/navbar/CNavbar.tsx +2 -2
  54. package/src/components/navbar/__tests__/CNavbar.spec.tsx +1 -1
  55. package/src/components/navbar/__tests__/__snapshots__/CNavbar.spec.tsx.snap +2 -1
  56. package/src/components/offcanvas/COffcanvas.tsx +8 -1
  57. package/src/components/popover/CPopover.tsx +2 -2
  58. package/src/components/progress/__tests__/__snapshots__/CProgress.spec.tsx.snap +10 -5
  59. package/src/components/progress/__tests__/__snapshots__/CProgressBar.spec.tsx.snap +0 -8
  60. package/src/components/sidebar/CSidebar.tsx +1 -1
  61. package/src/components/smart-table/CSmartTable.tsx +13 -6
  62. package/src/components/smart-table/CSmartTableBody.tsx +11 -5
  63. package/src/components/smart-table/CSmartTableHead.tsx +31 -11
  64. package/src/components/smart-table/CSmartTableInterface.tsx +1 -3
  65. package/src/components/smart-table/types.ts +2 -2
  66. package/src/components/smart-table/utils.ts +40 -5
  67. package/src/components/time-picker/CTimePicker.tsx +2 -2
  68. package/src/components/time-picker/utils.ts +5 -1
  69. package/src/components/tooltip/CTooltip.tsx +2 -2
  70. package/src/components/widgets/CWidgetStatsA.tsx +1 -1
  71. package/src/components/widgets/CWidgetStatsB.tsx +2 -2
  72. package/src/components/widgets/CWidgetStatsC.tsx +4 -12
  73. package/src/components/widgets/CWidgetStatsD.tsx +1 -1
  74. package/src/components/widgets/CWidgetStatsE.tsx +1 -1
  75. package/src/components/widgets/CWidgetStatsF.tsx +1 -1
  76. package/src/components/widgets/__tests__/CWidgetStatsA.spec.tsx +1 -1
  77. package/src/components/widgets/__tests__/CWidgetStatsB.spec.tsx +1 -1
  78. package/src/components/widgets/__tests__/CWidgetStatsC.spec.tsx +1 -1
  79. package/src/components/widgets/__tests__/CWidgetStatsD.spec.tsx +1 -1
  80. package/src/components/widgets/__tests__/CWidgetStatsE.spec.tsx +1 -1
  81. package/src/components/widgets/__tests__/CWidgetStatsF.spec.tsx +1 -1
  82. package/src/components/widgets/__tests__/__snapshots__/CWidgetStatsA.spec.tsx.snap +1 -1
  83. package/src/components/widgets/__tests__/__snapshots__/CWidgetStatsB.spec.tsx.snap +12 -7
  84. package/src/components/widgets/__tests__/__snapshots__/CWidgetStatsC.spec.tsx.snap +14 -9
  85. package/src/components/widgets/__tests__/__snapshots__/CWidgetStatsD.spec.tsx.snap +2 -2
  86. package/src/components/widgets/__tests__/__snapshots__/CWidgetStatsE.spec.tsx.snap +1 -1
  87. package/src/components/widgets/__tests__/__snapshots__/CWidgetStatsF.spec.tsx.snap +2 -2
  88. package/src/hooks/usePopper.ts +10 -2
  89. package/src/types.ts +14 -7
  90. package/src/utils/executeAfterTransition.ts +46 -0
  91. package/src/utils/getTransitionDurationFromElement.ts +24 -0
  92. package/src/utils/index.ts +10 -1
@@ -11,7 +11,7 @@ import PropTypes from 'prop-types'
11
11
  import classNames from 'classnames'
12
12
  import { Transition } from 'react-transition-group'
13
13
 
14
- import { CBackdrop } from '../backdrop/CBackdrop'
14
+ import { CBackdrop } from '../backdrop'
15
15
  import { CConditionalPortal } from '../conditional-portal'
16
16
  import { CModalContent } from './CModalContent'
17
17
  import { CModalDialog } from './CModalDialog'
@@ -35,6 +35,12 @@ export interface CModalProps extends HTMLAttributes<HTMLDivElement> {
35
35
  * @ignore
36
36
  */
37
37
  duration?: number
38
+ /**
39
+ * Puts the focus on the modal when shown.
40
+ *
41
+ * @since v4.10.0
42
+ */
43
+ focus?: boolean
38
44
  /**
39
45
  * Set modal to covers the entire user viewport.
40
46
  */
@@ -96,6 +102,7 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
96
102
  backdrop = true,
97
103
  className,
98
104
  duration = 150,
105
+ focus = true,
99
106
  fullscreen,
100
107
  keyboard = true,
101
108
  onClose,
@@ -111,6 +118,7 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
111
118
  },
112
119
  ref,
113
120
  ) => {
121
+ const activeElementRef = useRef<HTMLElement | null>(null)
114
122
  const modalRef = useRef<HTMLDivElement>(null)
115
123
  const modalContentRef = useRef<HTMLDivElement>(null)
116
124
  const forkedRef = useForkedRef(ref, modalRef)
@@ -128,11 +136,16 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
128
136
  }, [visible])
129
137
 
130
138
  useEffect(() => {
131
- document.addEventListener('click', handleClickOutside)
132
- document.addEventListener('keydown', handleKeyDown)
139
+ if (_visible) {
140
+ activeElementRef.current = document.activeElement as HTMLElement | null
141
+ document.addEventListener('mouseup', handleClickOutside)
142
+ document.addEventListener('keydown', handleKeyDown)
143
+ } else {
144
+ activeElementRef.current?.focus()
145
+ }
133
146
 
134
147
  return () => {
135
- document.removeEventListener('click', handleClickOutside)
148
+ document.removeEventListener('mouseup', handleClickOutside)
136
149
  document.removeEventListener('keydown', handleKeyDown)
137
150
  }
138
151
  }, [_visible])
@@ -143,6 +156,7 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
143
156
  }
144
157
 
145
158
  setVisible(false)
159
+
146
160
  return onClose && onClose()
147
161
  }
148
162
 
@@ -163,7 +177,7 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
163
177
 
164
178
  setTimeout(
165
179
  () => {
166
- modalRef.current?.focus()
180
+ focus && modalRef.current?.focus()
167
181
  },
168
182
  transition ? duration : 0,
169
183
  )
@@ -225,10 +239,13 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
225
239
  className,
226
240
  )}
227
241
  tabIndex={-1}
228
- role="dialog"
242
+ {...(_visible
243
+ ? { 'aria-modal': true, role: 'dialog' }
244
+ : { 'aria-hidden': 'true' })}
229
245
  style={{
230
246
  ...(state !== 'exited' && { display: 'block' }),
231
247
  }}
248
+ {...rest}
232
249
  ref={forkedRef}
233
250
  >
234
251
  <CModalDialog
@@ -237,9 +254,7 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
237
254
  scrollable={scrollable}
238
255
  size={size}
239
256
  >
240
- <CModalContent {...rest} ref={modalContentRef}>
241
- {children}
242
- </CModalContent>
257
+ <CModalContent ref={modalContentRef}>{children}</CModalContent>
243
258
  </CModalDialog>
244
259
  </div>
245
260
  </CModalContext.Provider>
@@ -262,6 +277,7 @@ CModal.propTypes = {
262
277
  children: PropTypes.node,
263
278
  className: PropTypes.string,
264
279
  duration: PropTypes.number,
280
+ focus: PropTypes.bool,
265
281
  fullscreen: PropTypes.oneOfType([
266
282
  PropTypes.bool,
267
283
  PropTypes.oneOf<'sm' | 'md' | 'lg' | 'xl' | 'xxl'>(['sm', 'md', 'lg', 'xl', 'xxl']),
@@ -243,7 +243,7 @@ export const CMultiSelect = forwardRef<HTMLDivElement, CMultiSelectProps>(
243
243
  if (
244
244
  allowCreateOptions &&
245
245
  filteredOptions.some(
246
- (option) => option.text && option.text.toLowerCase() === searchValue.toLowerCase(),
246
+ (option) => option.label && option.label.toLowerCase() === searchValue.toLowerCase(),
247
247
  )
248
248
  ) {
249
249
  return false
@@ -354,7 +354,7 @@ export const CMultiSelect = forwardRef<HTMLDivElement, CMultiSelectProps>(
354
354
  setSelected([
355
355
  ...selected,
356
356
  filteredOptions.find(
357
- (option) => String(option.text).toLowerCase() === searchValue.toLowerCase(),
357
+ (option) => String(option.label).toLowerCase() === searchValue.toLowerCase(),
358
358
  ) as Option,
359
359
  ])
360
360
  }
@@ -491,7 +491,7 @@ export const CMultiSelect = forwardRef<HTMLDivElement, CMultiSelectProps>(
491
491
  placeholder: `${selected.length} ${selectionTypeCounterText}`,
492
492
  })}
493
493
  {...(selected.length > 0 &&
494
- !multiple && { placeholder: selected.map((option) => option.text)[0] })}
494
+ !multiple && { placeholder: selected.map((option) => option.label)[0] })}
495
495
  {...(multiple &&
496
496
  selected.length > 0 &&
497
497
  selectionType !== 'counter' && { size: searchValue.length + 2 })}
@@ -18,7 +18,7 @@ const createNativeOptions = (options: Option[]) =>
18
18
  </optgroup>
19
19
  ) : (
20
20
  <option value={option.value} key={index} disabled={option.disabled}>
21
- {option.text}
21
+ {option.label}
22
22
  </option>
23
23
  ),
24
24
  )
@@ -77,7 +77,7 @@ export const CMultiSelectOptions = forwardRef<HTMLDivElement, CMultiSelectOption
77
77
  onKeyDown={(event) => handleKeyDown(event, option as Option)}
78
78
  tabIndex={0}
79
79
  >
80
- {optionsTemplate ? optionsTemplate(option as Option) : option.text}
80
+ {optionsTemplate ? optionsTemplate(option as Option) : option.label}
81
81
  </div>
82
82
  ) : (
83
83
  <div className="form-multi-select-optgroup-label" key={index}>
@@ -48,7 +48,7 @@ export const CMultiSelectSelection = forwardRef<HTMLSpanElement, CMultiSelectSel
48
48
  if (selectionType === 'tags') {
49
49
  return (
50
50
  <span className="form-multi-select-tag" key={index}>
51
- {option.text}
51
+ {option.label}
52
52
  {!option.disabled && (
53
53
  <button
54
54
  className="form-multi-select-tag-delete"
@@ -65,11 +65,11 @@ export const CMultiSelectSelection = forwardRef<HTMLSpanElement, CMultiSelectSel
65
65
  selectionType === 'text' &&
66
66
  selected.map((option, index) => (
67
67
  <span key={index}>
68
- {option.text}
68
+ {option.label}
69
69
  {index === selected.length - 1 ? '' : ','}&nbsp;
70
70
  </span>
71
71
  ))}
72
- {!multiple && !search && selected.map((option) => option.text)[0]}
72
+ {!multiple && !search && selected.map((option) => option.label)[0]}
73
73
  {children}
74
74
  </span>
75
75
  )
@@ -2,7 +2,7 @@ export type Option = {
2
2
  custom?: boolean
3
3
  disabled?: boolean
4
4
  selected?: boolean
5
- text: string // TODO: change to label in v5
5
+ label: string
6
6
  value: number | string
7
7
  [key: string]: number | string | any
8
8
  }
@@ -15,7 +15,7 @@ export type OptionsGroup = {
15
15
 
16
16
  export type SelectedOption = {
17
17
  disabled?: boolean
18
- text: string
18
+ label: string
19
19
  value: number | string
20
20
  [key: string]: number | string | any
21
21
  }
@@ -1,7 +1,7 @@
1
1
  import type { Option, OptionsGroup, SelectedOption } from './types'
2
2
 
3
- export const createOption = (text: string, options: (Option | OptionsGroup)[]) => {
4
- const value = text.toLowerCase().replace(/\s/g, '-')
3
+ export const createOption = (label: string, options: (Option | OptionsGroup)[]) => {
4
+ const value = label.toLowerCase().replace(/\s/g, '-')
5
5
  let uniqueValue = value
6
6
  let i = 1
7
7
 
@@ -13,7 +13,7 @@ export const createOption = (text: string, options: (Option | OptionsGroup)[]) =
13
13
  return [
14
14
  {
15
15
  value: uniqueValue,
16
- text,
16
+ label,
17
17
  custom: true,
18
18
  },
19
19
  ]
@@ -28,10 +28,10 @@ export const filterOptionsList = (search: string, _options: (Option | OptionsGro
28
28
  option.options &&
29
29
  option.options.filter(
30
30
  (option: Option) =>
31
- option.text && option.text.toLowerCase().includes(search.toLowerCase()),
31
+ option.lable && option.label.toLowerCase().includes(search.toLowerCase()),
32
32
  )
33
33
  if (
34
- (option.text && option.text.toLowerCase().includes(search.toLowerCase())) ||
34
+ (option.lable && option.label.toLowerCase().includes(search.toLowerCase())) ||
35
35
  (options && options.length > 0)
36
36
  ) {
37
37
  optionsList.push(Object.assign({}, option, options && options.length > 0 && { options }))
@@ -19,7 +19,7 @@ export interface CNavProps
19
19
  /**
20
20
  * Set the nav variant to tabs or pills.
21
21
  */
22
- variant?: 'tabs' | 'pills' | 'underline'
22
+ variant?: 'pills' | 'tabs' | 'underline'
23
23
  }
24
24
 
25
25
  export const CNav = forwardRef<HTMLDivElement | HTMLUListElement | HTMLOListElement, CNavProps>(
@@ -49,7 +49,7 @@ CNav.propTypes = {
49
49
  className: PropTypes.string,
50
50
  component: PropTypes.elementType,
51
51
  layout: PropTypes.oneOf(['fill', 'justified']),
52
- variant: PropTypes.oneOf(['tabs', 'pills', 'underline']),
52
+ variant: PropTypes.oneOf(['pills', 'tabs', 'underline']),
53
53
  }
54
54
 
55
55
  CNav.displayName = 'CNav'
@@ -36,6 +36,13 @@ export interface CNavGroupProps {
36
36
  idx?: string
37
37
  }
38
38
 
39
+ const isInVisibleGroup = (el1: string, el2: string) => {
40
+ const array1 = el1.toString().split('.')
41
+ const array2 = el2.toString().split('.')
42
+
43
+ return array2.every((item, index) => item === array1[index])
44
+ }
45
+
39
46
  export const CNavGroup = forwardRef<HTMLLIElement, CNavGroupProps>(
40
47
  ({ children, className, compact, idx, toggler, visible, ...rest }, ref) => {
41
48
  const [height, setHeight] = useState<number | string>()
@@ -45,12 +52,12 @@ export const CNavGroup = forwardRef<HTMLLIElement, CNavGroupProps>(
45
52
 
46
53
  const [_visible, setVisible] = useState(
47
54
  Boolean(
48
- visible || (idx && visibleGroup && visibleGroup.toString().startsWith(idx.toString())),
55
+ visible || (idx && visibleGroup && isInVisibleGroup(visibleGroup, idx)),
49
56
  ),
50
57
  )
51
58
 
52
59
  useEffect(() => {
53
- setVisible(Boolean(idx && visibleGroup && visibleGroup.toString().startsWith(idx.toString())))
60
+ setVisible(Boolean(idx && visibleGroup && isInVisibleGroup(visibleGroup, idx)))
54
61
  }, [visibleGroup])
55
62
 
56
63
  const handleTogglerOnCLick = (event: React.MouseEvent<HTMLElement>) => {
@@ -41,13 +41,14 @@ exports[`CNav example 1`] = `
41
41
  <li
42
42
  class="nav-item dropdown"
43
43
  >
44
- <a
44
+ <button
45
45
  aria-expanded="false"
46
- class="dropdown-toggle nav-link"
47
- href="#"
46
+ class="btn btn-primary dropdown-toggle"
47
+ tabindex="0"
48
+ type="button"
48
49
  >
49
50
  A
50
- </a>
51
+ </button>
51
52
  <ul
52
53
  aria-hidden="true"
53
54
  class="dropdown-menu"
@@ -17,7 +17,7 @@ export interface CNavbarProps extends HTMLAttributes<HTMLDivElement> {
17
17
  */
18
18
  color?: Colors
19
19
  /**
20
- * Sets if the color of text should be colored for a light or dark dark background.
20
+ * Sets if the color of text should be colored for a light or dark background.
21
21
  */
22
22
  colorScheme?: 'dark' | 'light'
23
23
  /**
@@ -59,12 +59,12 @@ export const CNavbar = forwardRef<HTMLDivElement, CNavbarProps>(
59
59
  'navbar',
60
60
  {
61
61
  [`bg-${color}`]: color,
62
- [`navbar-${colorScheme}`]: colorScheme,
63
62
  [typeof expand === 'boolean' ? 'navbar-expand' : `navbar-expand-${expand}`]: expand,
64
63
  },
65
64
  placement,
66
65
  className,
67
66
  )}
67
+ {...(colorScheme && { 'data-coreui-theme': colorScheme })}
68
68
  {...rest}
69
69
  ref={ref}
70
70
  >
@@ -26,9 +26,9 @@ test('CNavbar customize', async () => {
26
26
  expect(container.firstChild).toHaveClass('bazinga')
27
27
  expect(container.firstChild).toHaveClass('navbar')
28
28
  expect(container.firstChild).toHaveClass('bg-warning')
29
- expect(container.firstChild).toHaveClass('navbar-dark')
30
29
  expect(container.firstChild).toHaveClass('navbar-expand-lg')
31
30
  expect(container.firstChild).toHaveClass('fixed-bottom')
31
+ expect(container.firstChild).toHaveAttribute('data-coreui-theme', 'dark')
32
32
  const arrLength = container.getElementsByClassName('container-xl').length
33
33
  expect(arrLength).toBe(1)
34
34
  })
@@ -17,7 +17,8 @@ exports[`CNavbar customize - container and expand are boolean 1`] = `
17
17
  exports[`CNavbar customize 1`] = `
18
18
  <div>
19
19
  <h3
20
- class="navbar bg-warning navbar-dark navbar-expand-lg fixed-bottom bazinga"
20
+ class="navbar bg-warning navbar-expand-lg fixed-bottom bazinga"
21
+ data-coreui-theme="dark"
21
22
  >
22
23
  <div
23
24
  class="container-xl"
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
3
3
  import classNames from 'classnames'
4
4
  import { Transition } from 'react-transition-group'
5
5
 
6
- import { CBackdrop } from '../backdrop/CBackdrop'
6
+ import { CBackdrop } from '../backdrop'
7
7
  import { CConditionalPortal } from '../conditional-portal'
8
8
 
9
9
  import { useForkedRef } from '../../hooks'
@@ -17,6 +17,10 @@ export interface COffcanvasProps extends HTMLAttributes<HTMLDivElement> {
17
17
  * A string of all className you want applied to the base component.
18
18
  */
19
19
  className?: string
20
+ /**
21
+ * Sets a darker color scheme.
22
+ */
23
+ dark?: boolean
20
24
  /**
21
25
  * Closes the offcanvas when escape key is pressed.
22
26
  */
@@ -59,6 +63,7 @@ export const COffcanvas = forwardRef<HTMLDivElement, COffcanvasProps>(
59
63
  children,
60
64
  backdrop = true,
61
65
  className,
66
+ dark,
62
67
  keyboard = true,
63
68
  onHide,
64
69
  onShow,
@@ -135,6 +140,7 @@ export const COffcanvas = forwardRef<HTMLDivElement, COffcanvasProps>(
135
140
  role="dialog"
136
141
  tabIndex={-1}
137
142
  onKeyDown={handleKeyDown}
143
+ {...(dark && { 'data-coreui-theme': 'dark' })}
138
144
  {...rest}
139
145
  ref={forkedRef}
140
146
  >
@@ -161,6 +167,7 @@ COffcanvas.propTypes = {
161
167
  backdrop: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf<'static'>(['static'])]),
162
168
  children: PropTypes.node,
163
169
  className: PropTypes.string,
170
+ dark: PropTypes.bool,
164
171
  keyboard: PropTypes.bool,
165
172
  onHide: PropTypes.func,
166
173
  onShow: PropTypes.func,
@@ -7,7 +7,7 @@ import { Transition } from 'react-transition-group'
7
7
  import { usePopper } from '../../hooks'
8
8
  import { fallbackPlacementsPropType, triggerPropType } from '../../props'
9
9
  import type { Placements, Triggers } from '../../types'
10
- import { getRTLPlacement } from '../../utils'
10
+ import { getRTLPlacement, getTransitionDurationFromElement } from '../../utils'
11
11
 
12
12
  export interface CPopoverProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title' | 'content'> {
13
13
  /**
@@ -164,7 +164,7 @@ export const CPopover: FC<CPopoverProps> = ({
164
164
  onExit={onHide}
165
165
  timeout={{
166
166
  enter: 0,
167
- exit: 200,
167
+ exit: popoverRef.current ? getTransitionDurationFromElement(popoverRef.current) + 50 : 200,
168
168
  }}
169
169
  unmountOnExit
170
170
  >
@@ -3,15 +3,15 @@
3
3
  exports[`CProgress customize 1`] = `
4
4
  <div>
5
5
  <div
6
+ aria-valuemax="100"
7
+ aria-valuemin="0"
8
+ aria-valuenow="50"
6
9
  class="progress bazinga"
10
+ role="progressbar"
7
11
  style="height: 100px;"
8
12
  >
9
13
  <div
10
- aria-valuemax="100"
11
- aria-valuemin="0"
12
- aria-valuenow="50"
13
14
  class="progress-bar bg-warning"
14
- role="progressbar"
15
15
  style="width: 50%;"
16
16
  >
17
17
  Test
@@ -25,7 +25,12 @@ exports[`loads and displays CProgress component 1`] = `
25
25
  <div
26
26
  class="progress"
27
27
  >
28
- Test
28
+ <div
29
+ class="progress-bar bg-warning"
30
+ style="width: 0%;"
31
+ >
32
+ Test
33
+ </div>
29
34
  </div>
30
35
  </div>
31
36
  `;
@@ -3,11 +3,7 @@
3
3
  exports[`CProgressBar customize 1`] = `
4
4
  <div>
5
5
  <div
6
- aria-valuemax="100"
7
- aria-valuemin="0"
8
- aria-valuenow="50"
9
6
  class="progress-bar bg-warning progress-bar-striped progress-bar-animated bazinga"
10
- role="progressbar"
11
7
  style="width: 50%;"
12
8
  >
13
9
  Test
@@ -18,11 +14,7 @@ exports[`CProgressBar customize 1`] = `
18
14
  exports[`loads and displays CProgressBar component 1`] = `
19
15
  <div>
20
16
  <div
21
- aria-valuemax="100"
22
- aria-valuemin="0"
23
- aria-valuenow="0"
24
17
  class="progress-bar bg-warning"
25
- role="progressbar"
26
18
  style="width: 0%;"
27
19
  >
28
20
  Test
@@ -3,7 +3,7 @@ import { createPortal } from 'react-dom'
3
3
  import PropTypes from 'prop-types'
4
4
  import classNames from 'classnames'
5
5
 
6
- import { CBackdrop } from '../backdrop/CBackdrop'
6
+ import { CBackdrop } from '../backdrop'
7
7
 
8
8
  import { isInViewport } from '../../utils'
9
9
  import { useForkedRef } from '../../hooks'
@@ -285,7 +285,7 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
285
285
  )
286
286
  }
287
287
 
288
- const handleSorterChange = (column: string, index: number): void => {
288
+ const handleSorterChange = (column: string, index: number, order?: 'asc' | 'desc'): void => {
289
289
  if (!isSortable(index, columns, columnSorter, itemsDataColumns, columnNames)) {
290
290
  return
291
291
  }
@@ -293,8 +293,14 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
293
293
  //if column changed or sort was descending change asc to true
294
294
  const state = sorterState ?? { column: '', state: '' }
295
295
 
296
+ if (order) {
297
+ state.state = order
298
+ }
299
+
296
300
  if (state.column === column) {
297
- if (state.state === 0) {
301
+ if (order) {
302
+ state.state = order
303
+ } else if (state.state === 0) {
298
304
  state.state = 'asc'
299
305
  } else if (state.state === 'asc') {
300
306
  state.state = 'desc'
@@ -303,13 +309,13 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
303
309
  }
304
310
  } else {
305
311
  state.column = column
306
- state.state = 'asc'
312
+ state.state = order || 'asc'
307
313
  }
308
314
 
309
315
  setSorterState({ ...state })
310
316
  }
311
317
 
312
- const handleTableFilterChange = (value: string, type: string): void => {
318
+ const handleTableFilterChange = (value: string, type: string): void => {to
313
319
  const isLazy = tableFilter && typeof tableFilter === 'object' && tableFilter.lazy === true
314
320
  if ((isLazy && type === 'input') || (!isLazy && type === 'change')) {
315
321
  return
@@ -404,11 +410,13 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
404
410
  handleFilterOnInput={(key, event) => handleColumnFilterChange(key, event, 'input')}
405
411
  handleOnCustomFilterChange={(key, event) => handleColumnFilterChange(key, event)}
406
412
  handleSelectAllChecked={() => handleSelectAllChecked()}
407
- handleSort={(key, index) => handleSorterChange(key, index)}
413
+ handleSort={(key, index, order) => handleSorterChange(key, index, order)}
408
414
  />
409
415
  )}
410
416
  <CSmartTableBody
411
417
  clickableRows={clickableRows}
418
+ columnNames={columnNames}
419
+ columns={columns ?? columnNames}
412
420
  currentItems={currentItems}
413
421
  firstItemOnActivePageIndex={firstItemOnActivePageIndex}
414
422
  noItemsLabel={noItemsLabel}
@@ -416,7 +424,6 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
416
424
  clickableRows && onRowClick && onRowClick(item, index, columnName, event)
417
425
  }
418
426
  onRowChecked={(item, value) => handleRowChecked(item, value)}
419
- columnNames={columnNames}
420
427
  scopedColumns={scopedColumns}
421
428
  selectable={selectable}
422
429
  selected={_selected}
@@ -7,12 +7,13 @@ import { CTableDataCell, CTableRow } from '../table'
7
7
 
8
8
  import { isObjectInArray } from '../../utils'
9
9
 
10
- import type { Item, ScopedColumns } from './types'
11
- import { getClickedColumnName, getTableDataCellProps } from './utils'
10
+ import type { Column, Item, ScopedColumns } from './types'
11
+ import { getClickedColumnName, getColumnName, getTableDataCellProps, getTableDataCellStyles } from './utils'
12
12
 
13
13
  export interface CSmartTableBodyProps extends CTableBodyProps {
14
14
  clickableRows?: boolean
15
15
  columnNames: string[]
16
+ columns: (Column | string)[]
16
17
  currentItems: Item[]
17
18
  firstItemOnActivePageIndex: number
18
19
  noItemsLabel?: string | ReactNode
@@ -28,6 +29,7 @@ export const CSmartTableBody = forwardRef<HTMLTableSectionElement, CSmartTableBo
28
29
  {
29
30
  clickableRows,
30
31
  columnNames,
32
+ columns,
31
33
  currentItems,
32
34
  firstItemOnActivePageIndex,
33
35
  noItemsLabel,
@@ -40,7 +42,7 @@ export const CSmartTableBody = forwardRef<HTMLTableSectionElement, CSmartTableBo
40
42
  },
41
43
  ref,
42
44
  ) => {
43
- const colspan: number = selectable ? columnNames.length + 1 : columnNames.length
45
+ const colspan: number = selectable ? columns.length + 1 : columns.length
44
46
 
45
47
  return (
46
48
  <CTableBody
@@ -84,7 +86,8 @@ export const CSmartTableBody = forwardRef<HTMLTableSectionElement, CSmartTableBo
84
86
  />
85
87
  </CTableDataCell>
86
88
  )}
87
- {columnNames.map((colName, index) => {
89
+ {columns.map((column, index) => {
90
+ const colName = getColumnName(column)
88
91
  return (
89
92
  (scopedColumns &&
90
93
  scopedColumns[colName] &&
@@ -95,7 +98,10 @@ export const CSmartTableBody = forwardRef<HTMLTableSectionElement, CSmartTableBo
95
98
  },
96
99
  )) ||
97
100
  (item[colName] !== undefined && (
98
- <CTableDataCell {...getTableDataCellProps(item, colName)} key={index}>
101
+ <CTableDataCell
102
+ {...getTableDataCellProps(column, item, colName)}
103
+ style={getTableDataCellStyles(column, item, colName)}
104
+ key={index}>
99
105
  {item[colName]}
100
106
  </CTableDataCell>
101
107
  ))
@@ -35,7 +35,7 @@ export interface CSmartTableHeadProps extends CTableHeadProps {
35
35
  handleFilterOnChange?: (key: string, value: string) => void
36
36
  handleFilterOnInput?: (key: string, value: string) => void
37
37
  handleSelectAllChecked?: () => void
38
- handleSort?: (key: string, index: number) => void
38
+ handleSort?: (key: string, index: number, order?: 'asc' | 'desc') => void
39
39
  items: Item[]
40
40
  selectable?: boolean
41
41
  selectAll?: boolean | { external?: boolean }
@@ -144,21 +144,41 @@ export const CSmartTableHead = forwardRef<HTMLTableSectionElement, CSmartTableHe
144
144
  </CTableHeaderCell>
145
145
  )}
146
146
  {_columns.map((column: Column | string, index: number) => {
147
+ const isSortable =
148
+ columnSorter &&
149
+ (typeof column === 'object'
150
+ ? column.sorter === undefined
151
+ ? true
152
+ : column.sorter
153
+ : true)
147
154
  return (
148
155
  <CTableHeaderCell
149
156
  {...getTableHeaderCellProps(column)}
150
- onClick={() => handleSort && handleSort(getColumnKey(column), index)}
157
+ // onClick={() => handleSort && handleSort(getColumnKey(column), index)}
151
158
  style={getTableHeaderCellStyles(column, columnSorter)}
152
159
  key={index}
160
+ {...(isSortable && {
161
+ onClick: () => handleSort && handleSort(getColumnKey(column), index),
162
+ onKeyDown: (event) => {
163
+ if (event.key === 'Enter') {
164
+ handleSort && handleSort(getColumnKey(column), index)
165
+ }
166
+
167
+ if (event.key === 'ArrowUp') {
168
+ event.preventDefault()
169
+ handleSort && handleSort(getColumnKey(column), index, 'asc')
170
+ }
171
+
172
+ if (event.key === 'ArrowDown') {
173
+ event.preventDefault()
174
+ handleSort && handleSort(getColumnKey(column), index, 'desc')
175
+ }
176
+ },
177
+ tabIndex: 0,
178
+ })}
153
179
  >
154
180
  <div className="d-inline">{getColumnLabel(column)}</div>
155
- {columnSorter &&
156
- (typeof column === 'object'
157
- ? (column.sorter === undefined
158
- ? true
159
- : column.sorter)
160
- : true) &&
161
- columnSorterIcon(column)}
181
+ {isSortable && columnSorterIcon(column)}
162
182
  </CTableHeaderCell>
163
183
  )
164
184
  })}
@@ -171,9 +191,9 @@ export const CSmartTableHead = forwardRef<HTMLTableSectionElement, CSmartTableHe
171
191
  <CTableHeaderCell {...getTableHeaderCellProps(column)} key={index}>
172
192
  {(
173
193
  typeof column === 'object'
174
- ? (column.filter === undefined
194
+ ? column.filter === undefined
175
195
  ? true
176
- : column.filter)
196
+ : column.filter
177
197
  : true
178
198
  ) ? (
179
199
  typeof column !== 'string' && typeof column.filter === 'function' ? (