@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.
- package/README.md +1 -1
- package/dist/components/calendar/CCalendar.d.ts +89 -0
- package/dist/components/calendar/CCalendar.utils.d.ts +20 -0
- package/dist/components/datepicker/CDatePicker.d.ts +13 -0
- package/dist/components/daterangepicker/CDateRangePicker.d.ts +50 -0
- package/dist/components/dropdown/CDropdown.d.ts +10 -1
- package/dist/components/dropdown/CDropdownToggle.d.ts +4 -0
- package/dist/components/dropdown/CDropdownToggleCustom.d.ts +15 -0
- package/dist/components/modal/CModal.d.ts +1 -0
- package/dist/components/picker/CPicker.d.ts +37 -0
- package/dist/components/smart-table/CSmartTableInterface.d.ts +0 -9
- package/dist/components/timepicker/CTimePicker.d.ts +49 -0
- package/dist/components/timepicker/CTimePicker.utils.d.ts +4 -0
- package/dist/components/timepicker/CTimePickerRollCol.d.ts +11 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.es.js +2976 -1148
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +4691 -2859
- package/dist/index.js.map +1 -1
- package/package.json +10 -8
- package/src/components/accordion/CAccordionButton.tsx +2 -1
- package/src/components/calendar/CCalendar.tsx +482 -0
- package/src/components/calendar/CCalendar.utils.ts +183 -0
- package/src/components/datepicker/CDatePicker.tsx +49 -0
- package/src/components/daterangepicker/CDateRangePicker.tsx +366 -0
- package/src/components/dropdown/CDropdown.tsx +19 -24
- package/src/components/dropdown/CDropdownMenu.tsx +55 -3
- package/src/components/dropdown/CDropdownToggle.tsx +28 -5
- 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/picker/CPicker.tsx +142 -0
- package/src/components/smart-table/CSmartTable.tsx +44 -96
- package/src/components/smart-table/CSmartTableCleaner.tsx +3 -16
- package/src/components/smart-table/CSmartTableInterface.tsx +0 -9
- package/src/components/timepicker/CTimePicker.tsx +341 -0
- package/src/components/timepicker/CTimePicker.utils.ts +27 -0
- package/src/components/timepicker/CTimePickerRollCol.tsx +57 -0
- 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 {
|
|
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}>
|
|
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
|
|
69
|
-
|
|
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
|
|
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
|
-
<
|
|
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 />`;
|
|
@@ -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,
|
|
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
|
-
|
|
60
|
-
|
|
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>(
|
|
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 (
|
|
120
|
-
|
|
121
|
-
setSorterState({ ...sorterValue })
|
|
88
|
+
if (items && items.length < _itemsPerPage * _activePage - _itemsPerPage) {
|
|
89
|
+
setActivePage(1)
|
|
122
90
|
}
|
|
123
|
-
|
|
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
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
}, [
|
|
212
|
+
}, [JSON.stringify(columnFilterState), JSON.stringify(_items)])
|
|
253
213
|
|
|
254
|
-
const
|
|
255
|
-
let items =
|
|
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
|
|
237
|
+
return filteredTable
|
|
283
238
|
}
|
|
284
|
-
|
|
285
|
-
// const flip = sorterState.asc ? 1 : -1
|
|
239
|
+
|
|
286
240
|
const flip = sorterState.state === 'asc' ? 1 : sorterState.state === 'desc' ? -1 : 0
|
|
287
|
-
const sorted =
|
|
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
|
-
}, [
|
|
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
|
-
|
|
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
|