@coreui/react-pro 4.1.0 → 4.1.4
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.
- package/README.md +1 -1
- package/dist/components/Types.d.ts +1 -1
- package/dist/components/dropdown/CDropdownToggleCustom.d.ts +15 -0
- package/dist/components/modal/CModal.d.ts +1 -0
- package/dist/components/popover/CPopover.d.ts +2 -2
- package/dist/components/smart-table/CSmartTableBody.d.ts +3 -3
- package/dist/components/smart-table/CSmartTableInterface.d.ts +9 -15
- package/dist/components/tooltip/CTooltip.d.ts +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.es.js +193 -114
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +193 -113
- package/dist/index.js.map +1 -1
- package/package.json +10 -8
- package/src/components/Types.tsx +2 -2
- package/src/components/dropdown/CDropdown.tsx +2 -2
- package/src/components/dropdown/CDropdownToggleCustom.tsx +81 -0
- package/src/components/modal/CModal.tsx +42 -19
- package/src/components/modal/__tests__/CModal.spec.tsx +1 -1
- package/src/components/modal/__tests__/__snapshots__/CModal.spec.tsx.snap +2 -10
- package/src/components/popover/CPopover.tsx +4 -4
- package/src/components/smart-table/CSmartTable.tsx +57 -103
- package/src/components/smart-table/CSmartTableBody.tsx +9 -4
- package/src/components/smart-table/CSmartTableCleaner.tsx +3 -16
- package/src/components/smart-table/CSmartTableHead.tsx +1 -1
- package/src/components/smart-table/CSmartTableInterface.tsx +10 -15
- package/src/components/tooltip/CTooltip.tsx +2 -2
- package/src/index.ts +2 -0
- package/src/utils/hooks/useForkedRef.ts +5 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coreui/react-pro",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.4",
|
|
4
4
|
"description": "UI Components Library for React.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -35,24 +35,26 @@
|
|
|
35
35
|
"build": "rollup -c"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@
|
|
38
|
+
"@coreui/icons-pro": "^2.0.3",
|
|
39
|
+
"@coreui/icons-react": "^2.0.0",
|
|
40
|
+
"@popperjs/core": "^2.11.2",
|
|
39
41
|
"@rollup/plugin-commonjs": "^21.0.1",
|
|
40
|
-
"@rollup/plugin-node-resolve": "^13.
|
|
42
|
+
"@rollup/plugin-node-resolve": "^13.1.3",
|
|
41
43
|
"@rollup/plugin-typescript": "^8.3.0",
|
|
42
|
-
"@testing-library/jest-dom": "^5.
|
|
44
|
+
"@testing-library/jest-dom": "^5.16.1",
|
|
43
45
|
"@testing-library/react": "^12.1.2",
|
|
44
|
-
"@types/react": "^17.0.
|
|
46
|
+
"@types/react": "^17.0.38",
|
|
45
47
|
"@types/react-dom": "^17.0.11",
|
|
46
48
|
"@types/react-transition-group": "^4.4.4",
|
|
47
49
|
"classnames": "^2.3.1",
|
|
48
|
-
"prop-types": "^15.
|
|
50
|
+
"prop-types": "^15.8.1",
|
|
49
51
|
"react": "^17.0.2",
|
|
50
52
|
"react-dom": "^17.0.2",
|
|
51
53
|
"react-popper": "^2.2.5",
|
|
52
54
|
"react-transition-group": "^4.4.2",
|
|
53
|
-
"rollup": "^2.
|
|
55
|
+
"rollup": "^2.67.0",
|
|
54
56
|
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
55
|
-
"typescript": "^4.5.
|
|
57
|
+
"typescript": "^4.5.5"
|
|
56
58
|
},
|
|
57
59
|
"peerDependencies": {
|
|
58
60
|
"react": "^17",
|
package/src/components/Types.tsx
CHANGED
|
@@ -133,6 +133,6 @@ export const textColorsPropType = PropTypes.oneOfType([
|
|
|
133
133
|
PropTypes.string,
|
|
134
134
|
])
|
|
135
135
|
|
|
136
|
-
export type Triggers = 'hover' | 'focus' | 'click'
|
|
136
|
+
export type Triggers = 'hover' | 'focus' | 'click' | 'click-init'
|
|
137
137
|
|
|
138
|
-
export const triggerPropType = PropTypes.oneOf<Triggers>(['hover', 'focus', 'click'])
|
|
138
|
+
export const triggerPropType = PropTypes.oneOf<Triggers>(['hover', 'focus', 'click', 'click-init'])
|
|
@@ -138,12 +138,12 @@ export const CDropdown = forwardRef<HTMLDivElement | HTMLLIElement, CDropdownPro
|
|
|
138
138
|
useEffect(() => {
|
|
139
139
|
_visible &&
|
|
140
140
|
setTimeout(() => {
|
|
141
|
-
window.addEventListener('
|
|
141
|
+
window.addEventListener('mouseup', handleClickOutside)
|
|
142
142
|
window.addEventListener('keyup', handleKeyup)
|
|
143
143
|
})
|
|
144
144
|
|
|
145
145
|
return () => {
|
|
146
|
-
window.removeEventListener('
|
|
146
|
+
window.removeEventListener('mouseup', handleClickOutside)
|
|
147
147
|
window.removeEventListener('keyup', handleKeyup)
|
|
148
148
|
}
|
|
149
149
|
}, [_visible])
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import React, { FC, HTMLAttributes, useContext } from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import classNames from 'classnames'
|
|
4
|
+
import { Reference } from 'react-popper'
|
|
5
|
+
|
|
6
|
+
import { Triggers, triggerPropType } from '../Types'
|
|
7
|
+
|
|
8
|
+
import { CDropdownContext } from './CDropdown'
|
|
9
|
+
|
|
10
|
+
export interface CDropdownToggleCustomProps extends HTMLAttributes<HTMLDivElement> {
|
|
11
|
+
/**
|
|
12
|
+
* Toggle the disabled state for the component.
|
|
13
|
+
*/
|
|
14
|
+
disabled?: boolean
|
|
15
|
+
/**
|
|
16
|
+
* Sets which event handlers you’d like provided to your toggle prop. You can specify one trigger or an array of them.
|
|
17
|
+
*
|
|
18
|
+
* @type 'hover' | 'focus' | 'click'
|
|
19
|
+
*/
|
|
20
|
+
trigger?: Triggers | Triggers[]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const CDropdownToggleCustom: FC<CDropdownToggleCustomProps> = ({
|
|
24
|
+
children,
|
|
25
|
+
className,
|
|
26
|
+
disabled,
|
|
27
|
+
trigger = 'click',
|
|
28
|
+
...rest
|
|
29
|
+
}) => {
|
|
30
|
+
const { popper, visible, setVisible } = useContext(CDropdownContext)
|
|
31
|
+
const _className = classNames(className)
|
|
32
|
+
|
|
33
|
+
const triggers = {
|
|
34
|
+
...((trigger === 'click' || trigger.includes('click')) &&
|
|
35
|
+
!disabled && {
|
|
36
|
+
onClick: (event: React.MouseEvent<HTMLElement>) => {
|
|
37
|
+
event.preventDefault()
|
|
38
|
+
setVisible(!visible)
|
|
39
|
+
},
|
|
40
|
+
}),
|
|
41
|
+
...((trigger === 'click-init' || trigger.includes('click-init')) &&
|
|
42
|
+
!disabled && {
|
|
43
|
+
onClick: (event: React.MouseEvent<HTMLElement>) => {
|
|
44
|
+
event.preventDefault()
|
|
45
|
+
setVisible(true)
|
|
46
|
+
},
|
|
47
|
+
}),
|
|
48
|
+
...((trigger === 'focus' || trigger.includes('focus')) &&
|
|
49
|
+
!disabled && {
|
|
50
|
+
onFocus: () => setVisible(true),
|
|
51
|
+
onBlur: () => setVisible(false),
|
|
52
|
+
}),
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const togglerProps = {
|
|
56
|
+
className: _className,
|
|
57
|
+
'aria-expanded': visible,
|
|
58
|
+
...triggers,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// We use any because Toggler can be `a` as well as `button`.
|
|
62
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
63
|
+
const Toggler = (ref?: React.Ref<any>) => {
|
|
64
|
+
return (
|
|
65
|
+
<div {...togglerProps} {...rest} ref={ref}>
|
|
66
|
+
{children}
|
|
67
|
+
</div>
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return popper ? <Reference>{({ ref }) => Toggler(ref)}</Reference> : Toggler()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
CDropdownToggleCustom.propTypes = {
|
|
75
|
+
children: PropTypes.node,
|
|
76
|
+
className: PropTypes.string,
|
|
77
|
+
disabled: PropTypes.bool,
|
|
78
|
+
trigger: triggerPropType,
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
CDropdownToggleCustom.displayName = 'CDropdownToggleCustom'
|
|
@@ -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
|
-
<
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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.
|
|
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 />`;
|
|
@@ -13,7 +13,7 @@ export interface CPopoverProps {
|
|
|
13
13
|
/**
|
|
14
14
|
* Content node for your component.
|
|
15
15
|
*/
|
|
16
|
-
content: ReactNode
|
|
16
|
+
content: ReactNode | string
|
|
17
17
|
/**
|
|
18
18
|
* Offset of the popover relative to its target.
|
|
19
19
|
*/
|
|
@@ -29,7 +29,7 @@ export interface CPopoverProps {
|
|
|
29
29
|
/**
|
|
30
30
|
* Title node for your component.
|
|
31
31
|
*/
|
|
32
|
-
title?: ReactNode
|
|
32
|
+
title?: ReactNode | string
|
|
33
33
|
/**
|
|
34
34
|
* Sets which event handlers you’d like provided to your toggle prop. You can specify one trigger or an array of them.
|
|
35
35
|
*
|
|
@@ -147,12 +147,12 @@ export const CPopover: FC<CPopoverProps> = ({
|
|
|
147
147
|
|
|
148
148
|
CPopover.propTypes = {
|
|
149
149
|
children: PropTypes.any,
|
|
150
|
-
content: PropTypes.node,
|
|
150
|
+
content: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
|
151
151
|
placement: PropTypes.oneOf(['auto', 'top', 'right', 'bottom', 'left']),
|
|
152
152
|
offset: PropTypes.any, // TODO: find good proptype
|
|
153
153
|
onHide: PropTypes.func,
|
|
154
154
|
onShow: PropTypes.func,
|
|
155
|
-
title: PropTypes.string,
|
|
155
|
+
title: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
|
156
156
|
trigger: triggerPropType,
|
|
157
157
|
visible: PropTypes.bool,
|
|
158
158
|
}
|
|
@@ -1,7 +1,15 @@
|
|
|
1
|
-
import React, { ChangeEvent, forwardRef, useEffect, useMemo,
|
|
1
|
+
import React, { ChangeEvent, forwardRef, useEffect, useMemo, useState } from 'react'
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { cilArrowBottom, cilArrowTop, cilSwapVertical } from '@coreui/icons-pro'
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
ColumnFilterValue,
|
|
8
|
+
CSmartTableProps,
|
|
9
|
+
Item,
|
|
10
|
+
ItemInternal,
|
|
11
|
+
SorterValue,
|
|
12
|
+
} from './CSmartTableInterface'
|
|
5
13
|
|
|
6
14
|
import { CSmartPagination } from '../pagination/CSmartPagination'
|
|
7
15
|
import { CElementCover } from '../element-cover/CElementCover'
|
|
@@ -49,36 +57,9 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
|
|
|
49
57
|
scopedColumns,
|
|
50
58
|
selectable,
|
|
51
59
|
sorterValue,
|
|
52
|
-
sortingIcon =
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
icon={[
|
|
56
|
-
'512 512',
|
|
57
|
-
'<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>',
|
|
58
|
-
]}
|
|
59
|
-
key="csv"
|
|
60
|
-
/>
|
|
61
|
-
),
|
|
62
|
-
sortingIconAscending = (
|
|
63
|
-
<CIcon
|
|
64
|
-
width={18}
|
|
65
|
-
icon={[
|
|
66
|
-
'512 512',
|
|
67
|
-
'<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>',
|
|
68
|
-
]}
|
|
69
|
-
key="cat"
|
|
70
|
-
/>
|
|
71
|
-
),
|
|
72
|
-
sortingIconDescending = (
|
|
73
|
-
<CIcon
|
|
74
|
-
width={18}
|
|
75
|
-
icon={[
|
|
76
|
-
'512 512',
|
|
77
|
-
'<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>',
|
|
78
|
-
]}
|
|
79
|
-
key="cab"
|
|
80
|
-
/>
|
|
81
|
-
),
|
|
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" />,
|
|
82
63
|
tableBodyProps,
|
|
83
64
|
tableFootProps,
|
|
84
65
|
tableFilter,
|
|
@@ -92,45 +73,40 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
|
|
|
92
73
|
ref,
|
|
93
74
|
) => {
|
|
94
75
|
// instance data
|
|
95
|
-
const compData = useRef({ firstRun: true, columnFiltered: 0, changeItems: 0 }).current
|
|
96
|
-
|
|
97
|
-
const previousSorterValue = useRef<SorterValue>()
|
|
98
|
-
const previousItemsValue = useRef<Item[]>()
|
|
99
|
-
|
|
100
76
|
const [_activePage, setActivePage] = useState<number>(activePage)
|
|
101
|
-
const [_items, setItems] = useState<
|
|
77
|
+
const [_items, setItems] = useState<ItemInternal[]>([])
|
|
102
78
|
const [_itemsPerPage, setItemsPerPage] = useState(itemsPerPage)
|
|
103
|
-
const [columnFilterState, setColumnFilterState] = useState<ColumnFilterValue>(
|
|
104
|
-
columnFilterValue ? columnFilterValue : {},
|
|
105
|
-
)
|
|
79
|
+
const [columnFilterState, setColumnFilterState] = useState<ColumnFilterValue>({})
|
|
106
80
|
const [selectedAll, setSelectedAll] = useState<boolean | string>()
|
|
107
|
-
const [sorterState, setSorterState] = useState<SorterValue>(
|
|
81
|
+
const [sorterState, setSorterState] = useState<SorterValue>({})
|
|
108
82
|
const [tableFilterState, setTableFilterState] = useState<string>(
|
|
109
83
|
tableFilterValue ? tableFilterValue : '',
|
|
110
84
|
)
|
|
111
85
|
|
|
86
|
+
// watch
|
|
112
87
|
useMemo(() => {
|
|
113
|
-
if (
|
|
114
|
-
|
|
115
|
-
setSorterState({ ...sorterValue })
|
|
88
|
+
if (items && items.length < _itemsPerPage * _activePage - _itemsPerPage) {
|
|
89
|
+
setActivePage(1)
|
|
116
90
|
}
|
|
117
|
-
|
|
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)])
|
|
118
100
|
|
|
119
101
|
useMemo(() => {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
items?.map((item: Item, index: number) => {
|
|
129
|
-
return { ...item, _id: index }
|
|
130
|
-
}),
|
|
131
|
-
)
|
|
132
|
-
}
|
|
133
|
-
}, [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])
|
|
134
110
|
|
|
135
111
|
// functions
|
|
136
112
|
|
|
@@ -219,17 +195,7 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
|
|
|
219
195
|
const itemsDataColumns = rawColumnNames.filter((name) => genCols.includes(name))
|
|
220
196
|
|
|
221
197
|
// variables
|
|
222
|
-
|
|
223
|
-
useMemo(() => {
|
|
224
|
-
compData.columnFiltered++
|
|
225
|
-
}, [
|
|
226
|
-
JSON.stringify(columnFilter),
|
|
227
|
-
JSON.stringify(columnFilterState),
|
|
228
|
-
itemsDataColumns.join(''),
|
|
229
|
-
compData.changeItems,
|
|
230
|
-
])
|
|
231
|
-
|
|
232
|
-
const columnFiltered: Item[] = useMemo(() => {
|
|
198
|
+
const filteredColumns: ItemInternal[] = useMemo(() => {
|
|
233
199
|
let items = _items
|
|
234
200
|
if (columnFilter && typeof columnFilter === 'object' && columnFilter.external) {
|
|
235
201
|
return items
|
|
@@ -243,10 +209,10 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
|
|
|
243
209
|
}
|
|
244
210
|
})
|
|
245
211
|
return items
|
|
246
|
-
}, [
|
|
212
|
+
}, [JSON.stringify(columnFilterState), JSON.stringify(_items)])
|
|
247
213
|
|
|
248
|
-
const
|
|
249
|
-
let items =
|
|
214
|
+
const filteredTable: ItemInternal[] = useMemo(() => {
|
|
215
|
+
let items = filteredColumns
|
|
250
216
|
if (
|
|
251
217
|
!tableFilterState ||
|
|
252
218
|
(tableFilter && typeof tableFilter === 'object' && tableFilter.external)
|
|
@@ -259,26 +225,20 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
|
|
|
259
225
|
return !!itemsDataColumns.find((key) => valueContainFilter(item[key]))
|
|
260
226
|
})
|
|
261
227
|
return items
|
|
262
|
-
}, [
|
|
263
|
-
compData.columnFiltered,
|
|
264
|
-
tableFilterState,
|
|
265
|
-
JSON.stringify(tableFilter),
|
|
266
|
-
JSON.stringify(columnFiltered),
|
|
267
|
-
])
|
|
228
|
+
}, [tableFilterState, JSON.stringify(tableFilterValue), JSON.stringify(filteredColumns)])
|
|
268
229
|
|
|
269
|
-
const sortedItems:
|
|
230
|
+
const sortedItems: ItemInternal[] = useMemo(() => {
|
|
270
231
|
const col = sorterState?.column
|
|
271
232
|
if (
|
|
272
233
|
!col ||
|
|
273
234
|
!itemsDataColumns.includes(col) ||
|
|
274
235
|
(columnSorter && typeof columnSorter === 'object' && columnSorter.external)
|
|
275
236
|
) {
|
|
276
|
-
return
|
|
237
|
+
return filteredTable
|
|
277
238
|
}
|
|
278
|
-
|
|
279
|
-
// const flip = sorterState.asc ? 1 : -1
|
|
239
|
+
|
|
280
240
|
const flip = sorterState.state === 'asc' ? 1 : sorterState.state === 'desc' ? -1 : 0
|
|
281
|
-
const sorted =
|
|
241
|
+
const sorted = filteredTable.slice().sort((item, item2) => {
|
|
282
242
|
const value = item[col]
|
|
283
243
|
const value2 = item2[col]
|
|
284
244
|
const a = typeof value === 'number' ? value : String(value).toLowerCase()
|
|
@@ -286,18 +246,24 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
|
|
|
286
246
|
return a > b ? 1 * flip : b > a ? -1 * flip : 0
|
|
287
247
|
})
|
|
288
248
|
return sorted
|
|
289
|
-
}, [
|
|
249
|
+
}, [
|
|
250
|
+
JSON.stringify(filteredTable),
|
|
251
|
+
JSON.stringify(sorterState),
|
|
252
|
+
JSON.stringify(columnSorter),
|
|
253
|
+
JSON.stringify(filteredColumns),
|
|
254
|
+
JSON.stringify(_items),
|
|
255
|
+
])
|
|
290
256
|
|
|
291
257
|
const numberOfPages: number = _itemsPerPage ? Math.ceil(sortedItems.length / _itemsPerPage) : 1
|
|
292
258
|
|
|
293
259
|
const firstItemOnActivePageIndex: number = _activePage ? (_activePage - 1) * _itemsPerPage : 0
|
|
294
260
|
|
|
295
|
-
const itemsOnActivePage:
|
|
261
|
+
const itemsOnActivePage: ItemInternal[] = sortedItems.slice(
|
|
296
262
|
firstItemOnActivePageIndex,
|
|
297
263
|
firstItemOnActivePageIndex + _itemsPerPage,
|
|
298
264
|
)
|
|
299
265
|
|
|
300
|
-
const currentItems:
|
|
266
|
+
const currentItems: ItemInternal[] = _activePage ? itemsOnActivePage : sortedItems
|
|
301
267
|
|
|
302
268
|
const isFiltered: string =
|
|
303
269
|
tableFilterState || sorterState?.column || Object.values(columnFilterState).join('')
|
|
@@ -326,21 +292,9 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
|
|
|
326
292
|
}, [tableFilterState])
|
|
327
293
|
|
|
328
294
|
useEffect(() => {
|
|
329
|
-
|
|
295
|
+
onFilteredItemsChange && onFilteredItemsChange(sortedItems)
|
|
330
296
|
}, [JSON.stringify(sortedItems)])
|
|
331
297
|
|
|
332
|
-
// watch
|
|
333
|
-
useMemo(() => setItemsPerPage(itemsPerPage), [itemsPerPage])
|
|
334
|
-
useMemo(
|
|
335
|
-
() =>
|
|
336
|
-
JSON.stringify(previousSorterValue.current) !== JSON.stringify(sorterValue) &&
|
|
337
|
-
setSorterState({ ...sorterValue }),
|
|
338
|
-
[sorterValue],
|
|
339
|
-
)
|
|
340
|
-
useMemo(() => setColumnFilterState({ ...columnFilterValue }), [columnFilterValue])
|
|
341
|
-
|
|
342
|
-
compData.firstRun = false
|
|
343
|
-
|
|
344
298
|
const handleRowChecked = (id: number, value: boolean) => {
|
|
345
299
|
const newArr = [..._items]
|
|
346
300
|
newArr[id]._selected = value
|
|
@@ -350,7 +304,7 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
|
|
|
350
304
|
const handleSelectAllChecked = () => {
|
|
351
305
|
if (selectedAll === true) {
|
|
352
306
|
setItems(
|
|
353
|
-
_items.map((item:
|
|
307
|
+
_items.map((item: ItemInternal) => {
|
|
354
308
|
return { ...item, _selected: false }
|
|
355
309
|
}),
|
|
356
310
|
)
|
|
@@ -358,7 +312,7 @@ export const CSmartTable = forwardRef<HTMLDivElement, CSmartTableProps>(
|
|
|
358
312
|
}
|
|
359
313
|
|
|
360
314
|
setItems(
|
|
361
|
-
_items.map((item:
|
|
315
|
+
_items.map((item: ItemInternal) => {
|
|
362
316
|
return { ...item, _selected: true }
|
|
363
317
|
}),
|
|
364
318
|
)
|
|
@@ -7,15 +7,20 @@ import { CTableDataCell } from '../table/CTableDataCell'
|
|
|
7
7
|
|
|
8
8
|
import { CFormCheck } from '../form/CFormCheck'
|
|
9
9
|
|
|
10
|
-
import { Item, ScopedColumns } from './CSmartTableInterface'
|
|
10
|
+
import { Item, ItemInternal, ScopedColumns } from './CSmartTableInterface'
|
|
11
11
|
|
|
12
12
|
export interface CSmartTableBodyProps extends CTableBodyProps {
|
|
13
13
|
clickableRows?: boolean
|
|
14
|
-
currentItems:
|
|
14
|
+
currentItems: ItemInternal[]
|
|
15
15
|
firstItemOnActivePageIndex: number
|
|
16
16
|
noItemsLabel?: string | ReactNode
|
|
17
17
|
onRowChecked?: (id: number, value: boolean) => void
|
|
18
|
-
onRowClick?: (
|
|
18
|
+
onRowClick?: (
|
|
19
|
+
item: ItemInternal,
|
|
20
|
+
index: number,
|
|
21
|
+
columnName: string,
|
|
22
|
+
event: MouseEvent | boolean,
|
|
23
|
+
) => void
|
|
19
24
|
rawColumnNames: string[]
|
|
20
25
|
scopedColumns?: ScopedColumns
|
|
21
26
|
selectable?: boolean
|
|
@@ -64,7 +69,7 @@ export const CSmartTableBody = forwardRef<HTMLTableSectionElement, CSmartTableBo
|
|
|
64
69
|
{...rest}
|
|
65
70
|
ref={ref}
|
|
66
71
|
>
|
|
67
|
-
{currentItems.map((item:
|
|
72
|
+
{currentItems.map((item: ItemInternal, trIndex) => {
|
|
68
73
|
return (
|
|
69
74
|
<React.Fragment key={trIndex}>
|
|
70
75
|
<CTableRow
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import PropTypes from 'prop-types'
|
|
2
2
|
import React, { forwardRef, HTMLAttributes, ReactNode } from 'react'
|
|
3
3
|
|
|
4
|
+
import { cilFilterX } from '@coreui/icons-pro'
|
|
5
|
+
|
|
4
6
|
import CIcon from '@coreui/icons-react'
|
|
5
7
|
|
|
6
8
|
interface CSmartTableCleanerProps extends HTMLAttributes<HTMLButtonElement> {
|
|
@@ -9,22 +11,7 @@ interface CSmartTableCleanerProps extends HTMLAttributes<HTMLButtonElement> {
|
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
export const CSmartTableCleaner = forwardRef<HTMLButtonElement, CSmartTableCleanerProps>(
|
|
12
|
-
(
|
|
13
|
-
{
|
|
14
|
-
content = (
|
|
15
|
-
<CIcon
|
|
16
|
-
width={18}
|
|
17
|
-
icon={[
|
|
18
|
-
'512 512',
|
|
19
|
-
'<polygon fill="var(--ci-primary-color, currentColor)" points="40 16 40 53.828 109.024 136 150.815 136 76.896 48 459.51 48 304 242.388 304 401.373 241.373 464 240 464 240 368 208 368 208 496 254.627 496 336 414.627 336 253.612 496 53.612 496 16 40 16" class="ci-primary"></polygon><polygon fill="var(--ci-primary-color, currentColor)" points="166.403 248.225 226.864 187.763 204.237 165.135 143.775 225.597 83.313 165.135 60.687 187.763 121.148 248.225 60.687 308.687 83.313 331.314 143.775 270.852 204.237 331.314 226.864 308.687 166.403 248.225" class="ci-primary"></polygon>',
|
|
20
|
-
]}
|
|
21
|
-
/>
|
|
22
|
-
),
|
|
23
|
-
isFiltered,
|
|
24
|
-
...rest
|
|
25
|
-
},
|
|
26
|
-
ref,
|
|
27
|
-
) => {
|
|
14
|
+
({ content = <CIcon width={18} icon={cilFilterX} />, isFiltered, ...rest }, ref) => {
|
|
28
15
|
return (
|
|
29
16
|
<button
|
|
30
17
|
type="button"
|
|
@@ -205,7 +205,7 @@ export const CSmartTableHead = forwardRef<HTMLTableSectionElement, CSmartTableHe
|
|
|
205
205
|
CSmartTableHead.propTypes = {
|
|
206
206
|
columnFilter: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]),
|
|
207
207
|
columnFilterState: PropTypes.object,
|
|
208
|
-
columnSorter: PropTypes.bool,
|
|
208
|
+
columnSorter: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]),
|
|
209
209
|
component: PropTypes.elementType,
|
|
210
210
|
children: PropTypes.node,
|
|
211
211
|
columns: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.any, PropTypes.string])).isRequired, // TODO: improve this Prop Type,
|