@coreui/react 4.9.1 → 4.10.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/modal/CModal.d.ts +6 -0
- package/dist/index.es.js +116 -45
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +116 -45
- package/dist/index.js.map +1 -1
- package/dist/utils/executeAfterTransition.d.ts +2 -0
- package/dist/utils/getTransitionDurationFromElement.d.ts +2 -0
- package/dist/utils/index.d.ts +3 -1
- package/package.json +10 -10
- package/src/components/modal/CModal.tsx +20 -6
- package/src/components/nav/CNavGroup.tsx +9 -2
- package/src/components/offcanvas/COffcanvas.tsx +1 -1
- package/src/components/popover/CPopover.tsx +2 -2
- package/src/components/sidebar/CSidebar.tsx +1 -1
- package/src/components/tooltip/CTooltip.tsx +2 -2
- package/src/hooks/usePopper.ts +10 -2
- package/src/utils/executeAfterTransition.ts +46 -0
- package/src/utils/getTransitionDurationFromElement.ts +24 -0
- package/src/utils/index.ts +9 -1
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import executeAfterTransition from './executeAfterTransition';
|
|
1
2
|
import getRTLPlacement from './getRTLPlacement';
|
|
3
|
+
import getTransitionDurationFromElement from './getTransitionDurationFromElement';
|
|
2
4
|
import isInViewport from './isInViewport';
|
|
3
5
|
import isRTL from './isRTL';
|
|
4
|
-
export { getRTLPlacement, isInViewport, isRTL };
|
|
6
|
+
export { executeAfterTransition, getRTLPlacement, getTransitionDurationFromElement, isInViewport, isRTL, };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coreui/react",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.10.0",
|
|
4
4
|
"description": "UI Components Library for React.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -38,29 +38,29 @@
|
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@popperjs/core": "^2.11.8",
|
|
41
|
-
"@rollup/plugin-commonjs": "^25.0.
|
|
41
|
+
"@rollup/plugin-commonjs": "^25.0.3",
|
|
42
42
|
"@rollup/plugin-node-resolve": "^15.1.0",
|
|
43
43
|
"@rollup/plugin-typescript": "^11.1.2",
|
|
44
|
-
"@testing-library/jest-dom": "^5.
|
|
44
|
+
"@testing-library/jest-dom": "^5.17.0",
|
|
45
45
|
"@testing-library/react": "^14.0.0",
|
|
46
|
-
"@types/react": "18.2.
|
|
47
|
-
"@types/react-dom": "^18.2.
|
|
46
|
+
"@types/react": "18.2.18",
|
|
47
|
+
"@types/react-dom": "^18.2.7",
|
|
48
48
|
"@types/react-transition-group": "^4.4.6",
|
|
49
49
|
"classnames": "^2.3.2",
|
|
50
|
-
"jest": "^29.6.
|
|
51
|
-
"jest-environment-jsdom": "^29.6.
|
|
50
|
+
"jest": "^29.6.2",
|
|
51
|
+
"jest-environment-jsdom": "^29.6.2",
|
|
52
52
|
"prop-types": "^15.8.1",
|
|
53
53
|
"react": "^18.2.0",
|
|
54
54
|
"react-dom": "^18.2.0",
|
|
55
55
|
"react-popper": "^2.3.0",
|
|
56
56
|
"react-transition-group": "^4.4.5",
|
|
57
|
-
"rollup": "^3.
|
|
57
|
+
"rollup": "^3.27.0",
|
|
58
58
|
"ts-jest": "^29.1.1",
|
|
59
|
-
"tslib": "^2.6.
|
|
59
|
+
"tslib": "^2.6.1",
|
|
60
60
|
"typescript": "^4.9.5"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
|
-
"@coreui/coreui": "4.
|
|
63
|
+
"@coreui/coreui": "4.3.0",
|
|
64
64
|
"react": ">=17",
|
|
65
65
|
"react-dom": ">=17"
|
|
66
66
|
}
|
|
@@ -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
|
|
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)
|
|
@@ -129,8 +137,11 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
|
|
|
129
137
|
|
|
130
138
|
useEffect(() => {
|
|
131
139
|
if (_visible) {
|
|
140
|
+
activeElementRef.current = document.activeElement as HTMLElement | null
|
|
132
141
|
document.addEventListener('mouseup', handleClickOutside)
|
|
133
142
|
document.addEventListener('keydown', handleKeyDown)
|
|
143
|
+
} else {
|
|
144
|
+
activeElementRef.current?.focus()
|
|
134
145
|
}
|
|
135
146
|
|
|
136
147
|
return () => {
|
|
@@ -145,6 +156,7 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
|
|
|
145
156
|
}
|
|
146
157
|
|
|
147
158
|
setVisible(false)
|
|
159
|
+
|
|
148
160
|
return onClose && onClose()
|
|
149
161
|
}
|
|
150
162
|
|
|
@@ -165,7 +177,7 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
|
|
|
165
177
|
|
|
166
178
|
setTimeout(
|
|
167
179
|
() => {
|
|
168
|
-
modalRef.current?.focus()
|
|
180
|
+
focus && modalRef.current?.focus()
|
|
169
181
|
},
|
|
170
182
|
transition ? duration : 0,
|
|
171
183
|
)
|
|
@@ -227,10 +239,13 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
|
|
|
227
239
|
className,
|
|
228
240
|
)}
|
|
229
241
|
tabIndex={-1}
|
|
230
|
-
|
|
242
|
+
{...(_visible
|
|
243
|
+
? { 'aria-modal': true, role: 'dialog' }
|
|
244
|
+
: { 'aria-hidden': 'true' })}
|
|
231
245
|
style={{
|
|
232
246
|
...(state !== 'exited' && { display: 'block' }),
|
|
233
247
|
}}
|
|
248
|
+
{...rest}
|
|
234
249
|
ref={forkedRef}
|
|
235
250
|
>
|
|
236
251
|
<CModalDialog
|
|
@@ -239,9 +254,7 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
|
|
|
239
254
|
scrollable={scrollable}
|
|
240
255
|
size={size}
|
|
241
256
|
>
|
|
242
|
-
<CModalContent
|
|
243
|
-
{children}
|
|
244
|
-
</CModalContent>
|
|
257
|
+
<CModalContent ref={modalContentRef}>{children}</CModalContent>
|
|
245
258
|
</CModalDialog>
|
|
246
259
|
</div>
|
|
247
260
|
</CModalContext.Provider>
|
|
@@ -264,6 +277,7 @@ CModal.propTypes = {
|
|
|
264
277
|
children: PropTypes.node,
|
|
265
278
|
className: PropTypes.string,
|
|
266
279
|
duration: PropTypes.number,
|
|
280
|
+
focus: PropTypes.bool,
|
|
267
281
|
fullscreen: PropTypes.oneOfType([
|
|
268
282
|
PropTypes.bool,
|
|
269
283
|
PropTypes.oneOf<'sm' | 'md' | 'lg' | 'xl' | 'xxl'>(['sm', 'md', 'lg', 'xl', 'xxl']),
|
|
@@ -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
|
|
55
|
+
visible || (idx && visibleGroup && isInVisibleGroup(visibleGroup, idx)),
|
|
49
56
|
),
|
|
50
57
|
)
|
|
51
58
|
|
|
52
59
|
useEffect(() => {
|
|
53
|
-
setVisible(Boolean(idx && visibleGroup && visibleGroup
|
|
60
|
+
setVisible(Boolean(idx && visibleGroup && isInVisibleGroup(visibleGroup, idx)))
|
|
54
61
|
}, [visibleGroup])
|
|
55
62
|
|
|
56
63
|
const handleTogglerOnCLick = (event: React.MouseEvent<HTMLElement>) => {
|
|
@@ -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
|
|
6
|
+
import { CBackdrop } from '../backdrop'
|
|
7
7
|
import { CConditionalPortal } from '../conditional-portal'
|
|
8
8
|
|
|
9
9
|
import { useForkedRef } from '../../hooks'
|
|
@@ -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,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
|
|
6
|
+
import { CBackdrop } from '../backdrop'
|
|
7
7
|
|
|
8
8
|
import { isInViewport } from '../../utils'
|
|
9
9
|
import { useForkedRef } from '../../hooks'
|
|
@@ -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 CTooltipProps extends Omit<HTMLAttributes<HTMLDivElement>, 'content'> {
|
|
13
13
|
/**
|
|
@@ -158,7 +158,7 @@ export const CTooltip: FC<CTooltipProps> = ({
|
|
|
158
158
|
onExit={onHide}
|
|
159
159
|
timeout={{
|
|
160
160
|
enter: 0,
|
|
161
|
-
exit: 200,
|
|
161
|
+
exit: tooltipRef.current ? getTransitionDurationFromElement(tooltipRef.current) + 50 : 200,
|
|
162
162
|
}}
|
|
163
163
|
unmountOnExit
|
|
164
164
|
>
|
package/src/hooks/usePopper.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { useRef } from 'react'
|
|
|
2
2
|
import { createPopper } from '@popperjs/core'
|
|
3
3
|
import type { Instance, Options } from '@popperjs/core'
|
|
4
4
|
|
|
5
|
+
import { executeAfterTransition } from '../utils'
|
|
6
|
+
|
|
5
7
|
interface UsePopperOutput {
|
|
6
8
|
popper: Instance | undefined
|
|
7
9
|
initPopper: (reference: HTMLElement, popper: HTMLElement, options: Partial<Options>) => void
|
|
@@ -10,14 +12,20 @@ interface UsePopperOutput {
|
|
|
10
12
|
|
|
11
13
|
export const usePopper = (): UsePopperOutput => {
|
|
12
14
|
const _popper = useRef<Instance>()
|
|
15
|
+
const el = useRef<HTMLElement>()
|
|
13
16
|
|
|
14
17
|
const initPopper = (reference: HTMLElement, popper: HTMLElement, options: Partial<Options>) => {
|
|
15
18
|
_popper.current = createPopper(reference, popper, options)
|
|
19
|
+
el.current = popper
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
const destroyPopper = () => {
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
const popperInstance = _popper.current
|
|
24
|
+
|
|
25
|
+
if (popperInstance && el.current) {
|
|
26
|
+
executeAfterTransition(() => {
|
|
27
|
+
popperInstance.destroy()
|
|
28
|
+
}, el.current)
|
|
21
29
|
}
|
|
22
30
|
|
|
23
31
|
_popper.current = undefined
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import getTransitionDurationFromElement from './getTransitionDurationFromElement'
|
|
2
|
+
|
|
3
|
+
const execute = (callback: () => void) => {
|
|
4
|
+
if (typeof callback === 'function') {
|
|
5
|
+
callback()
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const triggerTransitionEnd = (element: HTMLElement) => {
|
|
10
|
+
element.dispatchEvent(new Event('transitionend'))
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const executeAfterTransition = (
|
|
14
|
+
callback: () => void,
|
|
15
|
+
transitionElement: HTMLElement,
|
|
16
|
+
waitForTransition = true,
|
|
17
|
+
) => {
|
|
18
|
+
if (!waitForTransition) {
|
|
19
|
+
execute(callback)
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const durationPadding = 5
|
|
24
|
+
const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding
|
|
25
|
+
|
|
26
|
+
let called = false
|
|
27
|
+
|
|
28
|
+
const handler = ({ target }: { target: any }) => {
|
|
29
|
+
if (target !== transitionElement) {
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
called = true
|
|
34
|
+
transitionElement.removeEventListener('transitionend', handler)
|
|
35
|
+
execute(callback)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
transitionElement.addEventListener('transitionend', handler)
|
|
39
|
+
setTimeout(() => {
|
|
40
|
+
if (!called) {
|
|
41
|
+
triggerTransitionEnd(transitionElement)
|
|
42
|
+
}
|
|
43
|
+
}, emulatedDuration)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export default executeAfterTransition
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const getTransitionDurationFromElement = (element: HTMLElement) => {
|
|
2
|
+
if (!element) {
|
|
3
|
+
return 0
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
// Get transition-duration of the element
|
|
7
|
+
let { transitionDuration, transitionDelay } = window.getComputedStyle(element)
|
|
8
|
+
|
|
9
|
+
const floatTransitionDuration = Number.parseFloat(transitionDuration)
|
|
10
|
+
const floatTransitionDelay = Number.parseFloat(transitionDelay)
|
|
11
|
+
|
|
12
|
+
// Return 0 if element or transition duration is not found
|
|
13
|
+
if (!floatTransitionDuration && !floatTransitionDelay) {
|
|
14
|
+
return 0
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// If multiple durations are defined, take the first
|
|
18
|
+
transitionDuration = transitionDuration.split(',')[0]
|
|
19
|
+
transitionDelay = transitionDelay.split(',')[0]
|
|
20
|
+
|
|
21
|
+
return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * 1000
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default getTransitionDurationFromElement
|
package/src/utils/index.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
|
+
import executeAfterTransition from './executeAfterTransition'
|
|
1
2
|
import getRTLPlacement from './getRTLPlacement'
|
|
3
|
+
import getTransitionDurationFromElement from './getTransitionDurationFromElement'
|
|
2
4
|
import isInViewport from './isInViewport'
|
|
3
5
|
import isRTL from './isRTL'
|
|
4
6
|
|
|
5
|
-
export {
|
|
7
|
+
export {
|
|
8
|
+
executeAfterTransition,
|
|
9
|
+
getRTLPlacement,
|
|
10
|
+
getTransitionDurationFromElement,
|
|
11
|
+
isInViewport,
|
|
12
|
+
isRTL,
|
|
13
|
+
}
|