@coreui/react-pro 4.1.2 → 4.2.0-beta.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 (39) hide show
  1. package/README.md +1 -1
  2. package/dist/components/calendar/CCalendar.d.ts +89 -0
  3. package/dist/components/calendar/CCalendar.utils.d.ts +20 -0
  4. package/dist/components/datepicker/CDatePicker.d.ts +13 -0
  5. package/dist/components/daterangepicker/CDateRangePicker.d.ts +50 -0
  6. package/dist/components/dropdown/CDropdown.d.ts +10 -1
  7. package/dist/components/dropdown/CDropdownToggle.d.ts +4 -0
  8. package/dist/components/dropdown/CDropdownToggleCustom.d.ts +15 -0
  9. package/dist/components/modal/CModal.d.ts +1 -0
  10. package/dist/components/picker/CPicker.d.ts +37 -0
  11. package/dist/components/smart-table/CSmartTableInterface.d.ts +0 -9
  12. package/dist/components/timepicker/CTimePicker.d.ts +49 -0
  13. package/dist/components/timepicker/CTimePicker.utils.d.ts +4 -0
  14. package/dist/components/timepicker/CTimePickerRollCol.d.ts +11 -0
  15. package/dist/index.d.ts +5 -1
  16. package/dist/index.es.js +2976 -1148
  17. package/dist/index.es.js.map +1 -1
  18. package/dist/index.js +4691 -2859
  19. package/dist/index.js.map +1 -1
  20. package/package.json +10 -8
  21. package/src/components/accordion/CAccordionButton.tsx +2 -1
  22. package/src/components/calendar/CCalendar.tsx +482 -0
  23. package/src/components/calendar/CCalendar.utils.ts +183 -0
  24. package/src/components/datepicker/CDatePicker.tsx +49 -0
  25. package/src/components/daterangepicker/CDateRangePicker.tsx +366 -0
  26. package/src/components/dropdown/CDropdown.tsx +19 -24
  27. package/src/components/dropdown/CDropdownMenu.tsx +55 -3
  28. package/src/components/dropdown/CDropdownToggle.tsx +28 -5
  29. package/src/components/modal/CModal.tsx +42 -19
  30. package/src/components/modal/__tests__/CModal.spec.tsx +1 -1
  31. package/src/components/modal/__tests__/__snapshots__/CModal.spec.tsx.snap +2 -10
  32. package/src/components/picker/CPicker.tsx +142 -0
  33. package/src/components/smart-table/CSmartTable.tsx +44 -96
  34. package/src/components/smart-table/CSmartTableCleaner.tsx +3 -16
  35. package/src/components/smart-table/CSmartTableInterface.tsx +0 -9
  36. package/src/components/timepicker/CTimePicker.tsx +341 -0
  37. package/src/components/timepicker/CTimePicker.utils.ts +27 -0
  38. package/src/components/timepicker/CTimePickerRollCol.tsx +57 -0
  39. package/src/index.ts +8 -0
@@ -1,5 +1,5 @@
1
1
  import PropTypes from 'prop-types'
2
- import React, { ElementType, FC, HTMLAttributes, useContext } from 'react'
2
+ import React, { ElementType, FC, HTMLAttributes, useContext, useEffect, useRef } from 'react'
3
3
  import classNames from 'classnames'
4
4
  import { Popper, PopperChildrenProps } from 'react-popper'
5
5
 
@@ -35,7 +35,57 @@ export const CDropdownMenu: FC<CDropdownMenuProps> = ({
35
35
  component: Component = 'ul',
36
36
  ...rest
37
37
  }) => {
38
- const { alignment, dark, direction, placement, popper, visible } = useContext(CDropdownContext)
38
+ const {
39
+ alignment,
40
+ autoClose,
41
+ dark,
42
+ direction,
43
+ dropdownToggleRef,
44
+ placement,
45
+ popper,
46
+ visible,
47
+ setVisible,
48
+ } = useContext(CDropdownContext)
49
+
50
+ const dropdownMenuRef = useRef<HTMLDivElement>(null)
51
+
52
+ useEffect(() => {
53
+ visible && window.addEventListener('mouseup', handleMouseUp)
54
+ visible && window.addEventListener('keyup', handleKeyup)
55
+
56
+ return () => {
57
+ window.removeEventListener('mouseup', handleMouseUp)
58
+ window.removeEventListener('keyup', handleKeyup)
59
+ }
60
+ }, [visible])
61
+
62
+ const handleKeyup = (event: Event) => {
63
+ if (autoClose === false) {
64
+ return
65
+ }
66
+ if (!dropdownMenuRef.current?.contains(event.target as HTMLElement)) {
67
+ setVisible(false)
68
+ }
69
+ }
70
+ const handleMouseUp = (event: Event) => {
71
+ if (dropdownToggleRef && dropdownToggleRef.current.contains(event.target as HTMLElement)) {
72
+ return
73
+ }
74
+ if (autoClose === true) {
75
+ setVisible(false)
76
+ return
77
+ }
78
+ if (autoClose === 'inside' && dropdownMenuRef.current?.contains(event.target as HTMLElement)) {
79
+ setVisible(false)
80
+ return
81
+ }
82
+ if (
83
+ autoClose === 'outside' &&
84
+ !dropdownMenuRef.current?.contains(event.target as HTMLElement)
85
+ ) {
86
+ setVisible(false)
87
+ }
88
+ }
39
89
 
40
90
  let _placement: Placements = placement
41
91
 
@@ -101,7 +151,9 @@ export const CDropdownMenu: FC<CDropdownMenuProps> = ({
101
151
  }
102
152
 
103
153
  return popper && visible ? (
104
- <Popper placement={_placement}>{({ ref, style }) => dropdownMenuComponent(style, ref)}</Popper>
154
+ <Popper innerRef={dropdownMenuRef} placement={_placement}>
155
+ {({ ref, style }) => dropdownMenuComponent(style, ref)}
156
+ </Popper>
105
157
  ) : (
106
158
  dropdownMenuComponent()
107
159
  )
@@ -3,6 +3,8 @@ import PropTypes from 'prop-types'
3
3
  import classNames from 'classnames'
4
4
  import { Reference } from 'react-popper'
5
5
 
6
+ import { useForkedRef } from '../../utils/hooks'
7
+
6
8
  import { Triggers, triggerPropType } from '../Types'
7
9
 
8
10
  import { CButton, CButtonProps } from '../button/CButton'
@@ -13,6 +15,10 @@ export interface CDropdownToggleProps extends Omit<CButtonProps, 'type'> {
13
15
  * Enables pseudo element caret on toggler.
14
16
  */
15
17
  caret?: boolean
18
+ /**
19
+ * Create a custom toggler which accepts any content.
20
+ */
21
+ custom?: boolean
16
22
  /**
17
23
  * Similarly, create split button dropdowns with virtually the same markup as single button dropdowns, but with the addition of `.dropdown-toggle-split` className for proper spacing around the dropdown caret.
18
24
  */
@@ -28,12 +34,13 @@ export interface CDropdownToggleProps extends Omit<CButtonProps, 'type'> {
28
34
  export const CDropdownToggle: FC<CDropdownToggleProps> = ({
29
35
  children,
30
36
  caret = true,
37
+ custom,
31
38
  className,
32
39
  split,
33
40
  trigger = 'click',
34
41
  ...rest
35
42
  }) => {
36
- const { popper, variant, visible, setVisible } = useContext(CDropdownContext)
43
+ const { dropdownToggleRef, popper, variant, visible, setVisible } = useContext(CDropdownContext)
37
44
  const _className = classNames(
38
45
  {
39
46
  'dropdown-toggle': caret,
@@ -59,31 +66,47 @@ export const CDropdownToggle: FC<CDropdownToggleProps> = ({
59
66
  const togglerProps = {
60
67
  className: _className,
61
68
  'aria-expanded': visible,
69
+ ...(!rest.disabled && { ...triggers }),
62
70
  ...triggers,
63
71
  }
64
72
 
65
73
  // We use any because Toggler can be `a` as well as `button`.
66
74
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
67
75
  const Toggler = (ref?: React.Ref<any>) => {
68
- return variant === 'nav-item' ? (
69
- <a href="#" {...togglerProps} ref={ref}>
76
+ return custom && React.isValidElement(children) ? (
77
+ <>
78
+ {React.cloneElement(children, {
79
+ 'aria-expanded': visible,
80
+ ...(!rest.disabled && { ...triggers }),
81
+ ref: useForkedRef(ref, dropdownToggleRef),
82
+ })}
83
+ </>
84
+ ) : variant === 'nav-item' ? (
85
+ <a href="#" {...togglerProps} ref={useForkedRef(ref, dropdownToggleRef)}>
70
86
  {children}
71
87
  </a>
72
88
  ) : (
73
- <CButton type="button" {...togglerProps} tabIndex={0} {...rest} ref={ref}>
89
+ <CButton
90
+ type="button"
91
+ {...togglerProps}
92
+ tabIndex={0}
93
+ {...rest}
94
+ ref={useForkedRef(ref, dropdownToggleRef)}
95
+ >
74
96
  {children}
75
97
  {split && <span className="visually-hidden">Toggle Dropdown</span>}
76
98
  </CButton>
77
99
  )
78
100
  }
79
101
 
80
- return popper ? <Reference>{({ ref }) => Toggler(ref)}</Reference> : Toggler()
102
+ return popper ? <Reference>{({ ref }) => Toggler(ref)}</Reference> : Toggler(dropdownToggleRef)
81
103
  }
82
104
 
83
105
  CDropdownToggle.propTypes = {
84
106
  caret: PropTypes.bool,
85
107
  children: PropTypes.node,
86
108
  className: PropTypes.string,
109
+ custom: PropTypes.bool,
87
110
  split: PropTypes.bool,
88
111
  trigger: triggerPropType,
89
112
  }
@@ -72,6 +72,10 @@ export interface CModalProps extends HTMLAttributes<HTMLDivElement> {
72
72
  * Remove animation to create modal that simply appear rather than fade in to view.
73
73
  */
74
74
  transition?: boolean
75
+ /*
76
+ * By default the component is unmounted after close animation, if you want to keep the component mounted set this property to false
77
+ */
78
+ unmountOnClose?: boolean
75
79
  /**
76
80
  * Toggle the visibility of modal component.
77
81
  */
@@ -102,11 +106,13 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
102
106
  scrollable,
103
107
  size,
104
108
  transition = true,
109
+ unmountOnClose = true,
105
110
  visible,
106
111
  },
107
112
  ref,
108
113
  ) => {
109
114
  const modalRef = useRef<HTMLDivElement>(null)
115
+ const modalContentRef = useRef<HTMLDivElement>(null)
110
116
  const forkedRef = useForkedRef(ref, modalRef)
111
117
 
112
118
  const [_visible, setVisible] = useState(visible)
@@ -121,6 +127,16 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
121
127
  setVisible,
122
128
  }
123
129
 
130
+ useEffect(() => {
131
+ modalRef.current && modalRef.current.addEventListener('click', handleClickOutside)
132
+ modalRef.current && modalRef.current.addEventListener('keyup', handleKeyDown)
133
+
134
+ return () => {
135
+ modalRef.current && modalRef.current.removeEventListener('click', handleClickOutside)
136
+ modalRef.current && modalRef.current.removeEventListener('keyup', handleKeyDown)
137
+ }
138
+ }, [_visible])
139
+
124
140
  const handleDismiss = () => {
125
141
  if (backdrop === 'static') {
126
142
  return setStaticBackdrop(true)
@@ -167,6 +183,15 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
167
183
  return () => document.body.classList.remove('modal-open')
168
184
  }, [_visible])
169
185
 
186
+ const handleClickOutside = (event: Event) => {
187
+ if (
188
+ modalContentRef.current &&
189
+ !modalContentRef.current.contains(event.target as HTMLElement)
190
+ ) {
191
+ handleDismiss()
192
+ }
193
+ }
194
+
170
195
  const handleKeyDown = useCallback(
171
196
  (event) => {
172
197
  if (event.key === 'Escape' && keyboard) {
@@ -190,9 +215,8 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
190
215
  fullscreen={fullscreen}
191
216
  scrollable={scrollable}
192
217
  size={size}
193
- onClick={(event) => event.stopPropagation()}
194
218
  >
195
- <CModalContent>{children}</CModalContent>
219
+ <CModalContent ref={modalContentRef}>{children}</CModalContent>
196
220
  </CModalDialog>
197
221
  </div>
198
222
  </CModalContext.Provider>
@@ -201,23 +225,21 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
201
225
 
202
226
  return (
203
227
  <>
204
- <div onClick={handleDismiss} onKeyDown={handleKeyDown}>
205
- <Transition
206
- in={_visible}
207
- mountOnEnter
208
- onEnter={onShow}
209
- onExit={onClose}
210
- unmountOnExit
211
- timeout={!transition ? 0 : duration}
212
- >
213
- {(state) => {
214
- const transitionClass = getTransitionClass(state)
215
- return typeof window !== 'undefined' && portal
216
- ? createPortal(modal(forkedRef, transitionClass), document.body)
217
- : modal(forkedRef, transitionClass)
218
- }}
219
- </Transition>
220
- </div>
228
+ <Transition
229
+ in={_visible}
230
+ mountOnEnter
231
+ onEnter={onShow}
232
+ onExit={onClose}
233
+ unmountOnExit={unmountOnClose}
234
+ timeout={!transition ? 0 : duration}
235
+ >
236
+ {(state) => {
237
+ const transitionClass = getTransitionClass(state)
238
+ return typeof window !== 'undefined' && portal
239
+ ? createPortal(modal(forkedRef, transitionClass), document.body)
240
+ : modal(forkedRef, transitionClass)
241
+ }}
242
+ </Transition>
221
243
  {typeof window !== 'undefined' && portal
222
244
  ? backdrop && createPortal(<CBackdrop visible={_visible} />, document.body)
223
245
  : backdrop && <CBackdrop visible={_visible} />}
@@ -244,6 +266,7 @@ CModal.propTypes = {
244
266
  scrollable: PropTypes.bool,
245
267
  size: PropTypes.oneOf(['sm', 'lg', 'xl']),
246
268
  transition: PropTypes.bool,
269
+ unmountOnClose: PropTypes.bool,
247
270
  visible: PropTypes.bool,
248
271
  }
249
272
 
@@ -36,7 +36,7 @@ test('CModal dialog close on press ESC', async () => {
36
36
  expect(onClose).toHaveBeenCalledTimes(0)
37
37
  const modal = document.querySelector('.modal')
38
38
  if (modal !== null) {
39
- fireEvent.keyDown(modal, {
39
+ fireEvent.keyUp(modal, {
40
40
  key: 'Escape',
41
41
  code: 'Escape',
42
42
  keyCode: 27,
@@ -1,13 +1,5 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
- exports[`CModal customize 1`] = `
4
- <div>
5
- <div />
6
- </div>
7
- `;
3
+ exports[`CModal customize 1`] = `<div />`;
8
4
 
9
- exports[`loads and displays CModal component 1`] = `
10
- <div>
11
- <div />
12
- </div>
13
- `;
5
+ exports[`loads and displays CModal component 1`] = `<div />`;
@@ -0,0 +1,142 @@
1
+ import React, { forwardRef, ReactNode, useEffect, useState } from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import classNames from 'classnames'
4
+
5
+ import { CButton } from '../button/CButton'
6
+ import { CDropdown, CDropdownProps } from '../dropdown/CDropdown'
7
+ import { CDropdownMenu } from '../dropdown/CDropdownMenu'
8
+ import { CDropdownToggle } from '../dropdown/CDropdownToggle'
9
+
10
+ export interface CPickerProps extends Omit<CDropdownProps, 'variant'> {
11
+ /**
12
+ * Cancel button text.
13
+ */
14
+ cancelButtonText?: ReactNode
15
+ /**
16
+ * Set container type for the component.
17
+ */
18
+ container?: 'dropdown' | 'inline'
19
+ /**
20
+ * Toggle the disabled state for the component.
21
+ */
22
+ disabled?: boolean
23
+ /**
24
+ * Toggle visibility of footer element or set the content of footer.
25
+ */
26
+ footer?: boolean | ReactNode
27
+ /**
28
+ * Ok button text
29
+ */
30
+ okButtonText?: ReactNode
31
+ /**
32
+ * Callback fired when the cancel button has been clicked.
33
+ */
34
+ onCancelClick?: () => void
35
+ /**
36
+ * Callback fired when the ok button has been clicked.
37
+ */
38
+ onOkClick?: () => void
39
+ /**
40
+ * The content of toggler.
41
+ */
42
+ toggler?: ReactNode
43
+ }
44
+
45
+ export const CPicker = forwardRef<HTMLDivElement | HTMLLIElement, CPickerProps>(
46
+ (
47
+ {
48
+ children,
49
+ cancelButtonText = 'Cancel',
50
+ className,
51
+ container = 'dropdown',
52
+ disabled,
53
+ footer,
54
+ okButtonText = 'OK',
55
+ onCancelClick,
56
+ onOkClick,
57
+ onHide,
58
+ onShow,
59
+ toggler: Toggler,
60
+ visible,
61
+ ...rest
62
+ },
63
+ ref,
64
+ ) => {
65
+ const [_visible, setVisible] = useState(visible)
66
+
67
+ useEffect(() => {
68
+ setVisible(visible)
69
+ }, [visible])
70
+
71
+ const Footer = () => (
72
+ <>
73
+ <CButton
74
+ color="primary"
75
+ size="sm"
76
+ variant="ghost"
77
+ onClick={() => onCancelClick && onCancelClick()}
78
+ >
79
+ {cancelButtonText}
80
+ </CButton>
81
+ <CButton
82
+ color="primary"
83
+ size="sm"
84
+ onClick={() => {
85
+ onOkClick && onOkClick()
86
+ setVisible(false)
87
+ }}
88
+ >
89
+ {okButtonText}
90
+ </CButton>
91
+ </>
92
+ )
93
+
94
+ const _className = classNames('picker', className)
95
+
96
+ switch (container) {
97
+ case 'inline':
98
+ return <div className={_className}>{children}</div>
99
+ default:
100
+ return (
101
+ <CDropdown
102
+ autoClose="outside"
103
+ className={_className}
104
+ onHide={() => {
105
+ setVisible(false)
106
+ onHide && onHide()
107
+ }}
108
+ onShow={() => {
109
+ setVisible(true)
110
+ onShow && onShow()
111
+ }}
112
+ variant="dropdown"
113
+ visible={_visible}
114
+ {...rest}
115
+ ref={ref}
116
+ >
117
+ <CDropdownToggle custom disabled={_visible || disabled}>
118
+ {Toggler}
119
+ </CDropdownToggle>
120
+ <CDropdownMenu component="div">
121
+ {children}
122
+ {footer && (
123
+ <div className="picker-footer">
124
+ {typeof footer === 'boolean' ? Footer() : footer}
125
+ </div>
126
+ )}
127
+ </CDropdownMenu>
128
+ </CDropdown>
129
+ )
130
+ }
131
+ },
132
+ )
133
+
134
+ CPicker.displayName = 'CPicker'
135
+
136
+ CPicker.propTypes = {
137
+ ...CDropdown.propTypes,
138
+ container: PropTypes.oneOf(['dropdown', 'inline']),
139
+ disabled: PropTypes.bool,
140
+ onCancelClick: PropTypes.func,
141
+ onOkClick: PropTypes.func,
142
+ }
@@ -1,6 +1,8 @@
1
- import React, { ChangeEvent, forwardRef, useEffect, useMemo, useRef, useState } from 'react'
1
+ import React, { ChangeEvent, forwardRef, useEffect, useMemo, useState } from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
 
4
+ import { cilArrowBottom, cilArrowTop, cilSwapVertical } from '@coreui/icons-pro'
5
+
4
6
  import {
5
7
  ColumnFilterValue,
6
8
  CSmartTableProps,
@@ -55,36 +57,9 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
55
57
  scopedColumns,
56
58
  selectable,
57
59
  sorterValue,
58
- sortingIcon = (
59
- <CIcon
60
- width={18}
61
- icon={[
62
- '512 512',
63
- '<polygon fill="var(--ci-primary-color, currentColor)" points="384 433.373 384 160 352 160 352 434.51 282.177 364.687 259.55 387.313 367.432 495.196 475.313 387.313 452.687 364.687 384 433.373" class="ci-primary"></polygon><polygon fill="var(--ci-primary-color, currentColor)" points="159.432 17.372 51.55 125.255 74.177 147.882 144 78.059 144 352 176 352 176 79.195 244.687 147.882 267.313 125.255 159.432 17.372" class="ci-primary"></polygon>',
64
- ]}
65
- key="csv"
66
- />
67
- ),
68
- sortingIconAscending = (
69
- <CIcon
70
- width={18}
71
- icon={[
72
- '512 512',
73
- '<polygon fill="var(--ci-primary-color, currentColor)" points="390.624 150.625 256 16 121.376 150.625 144.004 173.252 240.001 77.254 240.001 495.236 272.001 495.236 272.001 77.257 367.996 173.252 390.624 150.625" class="ci-primary"></polygon>',
74
- ]}
75
- key="cat"
76
- />
77
- ),
78
- sortingIconDescending = (
79
- <CIcon
80
- width={18}
81
- icon={[
82
- '512 512',
83
- '<polygon fill="var(--ci-primary-color, currentColor)" points="367.997 338.75 271.999 434.747 271.999 17.503 239.999 17.503 239.999 434.745 144.003 338.75 121.376 361.377 256 496 390.624 361.377 367.997 338.75" class="ci-primary"></polygon>',
84
- ]}
85
- key="cab"
86
- />
87
- ),
60
+ sortingIcon = <CIcon width={18} icon={cilSwapVertical} key="csv" />,
61
+ sortingIconAscending = <CIcon width={18} icon={cilArrowTop} key="cat" />,
62
+ sortingIconDescending = <CIcon width={18} icon={cilArrowBottom} key="cab" />,
88
63
  tableBodyProps,
89
64
  tableFootProps,
90
65
  tableFilter,
@@ -98,45 +73,40 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
98
73
  ref,
99
74
  ) => {
100
75
  // instance data
101
- const compData = useRef({ firstRun: true, columnFiltered: 0, changeItems: 0 }).current
102
-
103
- const previousSorterValue = useRef<SorterValue>()
104
- const previousItemsValue = useRef<Item[]>()
105
-
106
76
  const [_activePage, setActivePage] = useState<number>(activePage)
107
77
  const [_items, setItems] = useState<ItemInternal[]>([])
108
78
  const [_itemsPerPage, setItemsPerPage] = useState(itemsPerPage)
109
- const [columnFilterState, setColumnFilterState] = useState<ColumnFilterValue>(
110
- columnFilterValue ? columnFilterValue : {},
111
- )
79
+ const [columnFilterState, setColumnFilterState] = useState<ColumnFilterValue>({})
112
80
  const [selectedAll, setSelectedAll] = useState<boolean | string>()
113
- const [sorterState, setSorterState] = useState<SorterValue>(previousSorterValue.current || {})
81
+ const [sorterState, setSorterState] = useState<SorterValue>({})
114
82
  const [tableFilterState, setTableFilterState] = useState<string>(
115
83
  tableFilterValue ? tableFilterValue : '',
116
84
  )
117
85
 
86
+ // watch
118
87
  useMemo(() => {
119
- if (JSON.stringify(previousSorterValue.current) !== JSON.stringify(sorterValue)) {
120
- previousSorterValue.current = sorterValue
121
- setSorterState({ ...sorterValue })
88
+ if (items && items.length < _itemsPerPage * _activePage - _itemsPerPage) {
89
+ setActivePage(1)
122
90
  }
123
- }, [sorterValue])
91
+
92
+ // Create the internal array of items
93
+ Array.isArray(items) &&
94
+ setItems(
95
+ items?.map((item: Item, index: number) => {
96
+ return { ...item, _id: index }
97
+ }),
98
+ )
99
+ }, [JSON.stringify(items)])
124
100
 
125
101
  useMemo(() => {
126
- if (JSON.stringify(previousItemsValue.current) !== JSON.stringify(items)) {
127
- if (items && items.length < _itemsPerPage * _activePage - _itemsPerPage) {
128
- setActivePage(1)
129
- }
130
- previousItemsValue.current = items
131
-
132
- Array.isArray(items) &&
133
- setItems(
134
- items?.map((item: Item, index: number) => {
135
- return { ...item, _id: index }
136
- }),
137
- )
138
- }
139
- }, [items])
102
+ columnFilterValue && setColumnFilterState(columnFilterValue)
103
+ }, [JSON.stringify(columnFilterValue)])
104
+
105
+ useMemo(() => {
106
+ setSorterState({ ...sorterValue })
107
+ }, [JSON.stringify(sorterValue)])
108
+
109
+ useMemo(() => setItemsPerPage(itemsPerPage), [itemsPerPage])
140
110
 
141
111
  // functions
142
112
 
@@ -225,17 +195,7 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
225
195
  const itemsDataColumns = rawColumnNames.filter((name) => genCols.includes(name))
226
196
 
227
197
  // variables
228
-
229
- useMemo(() => {
230
- compData.columnFiltered++
231
- }, [
232
- JSON.stringify(columnFilter),
233
- JSON.stringify(columnFilterState),
234
- itemsDataColumns.join(''),
235
- compData.changeItems,
236
- ])
237
-
238
- const columnFiltered: ItemInternal[] = useMemo(() => {
198
+ const filteredColumns: ItemInternal[] = useMemo(() => {
239
199
  let items = _items
240
200
  if (columnFilter && typeof columnFilter === 'object' && columnFilter.external) {
241
201
  return items
@@ -249,10 +209,10 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
249
209
  }
250
210
  })
251
211
  return items
252
- }, [compData.columnFiltered, _items])
212
+ }, [JSON.stringify(columnFilterState), JSON.stringify(_items)])
253
213
 
254
- const tableFiltered: ItemInternal[] = useMemo(() => {
255
- let items = columnFiltered
214
+ const filteredTable: ItemInternal[] = useMemo(() => {
215
+ let items = filteredColumns
256
216
  if (
257
217
  !tableFilterState ||
258
218
  (tableFilter && typeof tableFilter === 'object' && tableFilter.external)
@@ -265,12 +225,7 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
265
225
  return !!itemsDataColumns.find((key) => valueContainFilter(item[key]))
266
226
  })
267
227
  return items
268
- }, [
269
- compData.columnFiltered,
270
- tableFilterState,
271
- JSON.stringify(tableFilter),
272
- JSON.stringify(columnFiltered),
273
- ])
228
+ }, [tableFilterState, JSON.stringify(tableFilterValue), JSON.stringify(filteredColumns)])
274
229
 
275
230
  const sortedItems: ItemInternal[] = useMemo(() => {
276
231
  const col = sorterState?.column
@@ -279,12 +234,11 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
279
234
  !itemsDataColumns.includes(col) ||
280
235
  (columnSorter && typeof columnSorter === 'object' && columnSorter.external)
281
236
  ) {
282
- return tableFiltered
237
+ return filteredTable
283
238
  }
284
- //if values in column are to be sorted by numeric value they all have to be type number
285
- // const flip = sorterState.asc ? 1 : -1
239
+
286
240
  const flip = sorterState.state === 'asc' ? 1 : sorterState.state === 'desc' ? -1 : 0
287
- const sorted = tableFiltered.slice().sort((item, item2) => {
241
+ const sorted = filteredTable.slice().sort((item, item2) => {
288
242
  const value = item[col]
289
243
  const value2 = item2[col]
290
244
  const a = typeof value === 'number' ? value : String(value).toLowerCase()
@@ -292,7 +246,13 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
292
246
  return a > b ? 1 * flip : b > a ? -1 * flip : 0
293
247
  })
294
248
  return sorted
295
- }, [JSON.stringify(tableFiltered), JSON.stringify(sorterState), JSON.stringify(columnSorter)])
249
+ }, [
250
+ JSON.stringify(filteredTable),
251
+ JSON.stringify(sorterState),
252
+ JSON.stringify(columnSorter),
253
+ JSON.stringify(filteredColumns),
254
+ JSON.stringify(_items),
255
+ ])
296
256
 
297
257
  const numberOfPages: number = _itemsPerPage ? Math.ceil(sortedItems.length / _itemsPerPage) : 1
298
258
 
@@ -332,21 +292,9 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
332
292
  }, [tableFilterState])
333
293
 
334
294
  useEffect(() => {
335
- !compData.firstRun && onFilteredItemsChange && onFilteredItemsChange(sortedItems)
295
+ onFilteredItemsChange && onFilteredItemsChange(sortedItems)
336
296
  }, [JSON.stringify(sortedItems)])
337
297
 
338
- // watch
339
- useMemo(() => setItemsPerPage(itemsPerPage), [itemsPerPage])
340
- useMemo(
341
- () =>
342
- JSON.stringify(previousSorterValue.current) !== JSON.stringify(sorterValue) &&
343
- setSorterState({ ...sorterValue }),
344
- [sorterValue],
345
- )
346
- useMemo(() => setColumnFilterState({ ...columnFilterValue }), [columnFilterValue])
347
-
348
- compData.firstRun = false
349
-
350
298
  const handleRowChecked = (id: number, value: boolean) => {
351
299
  const newArr = [..._items]
352
300
  newArr[id]._selected = value