@coreui/react 5.0.0-alpha.0 → 5.0.0-alpha.1
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/close-button/CCloseButton.d.ts +6 -0
- package/dist/components/modal/CModal.d.ts +6 -0
- package/dist/components/nav/CNav.d.ts +1 -1
- package/dist/components/navbar/CNavbar.d.ts +1 -1
- package/dist/components/offcanvas/COffcanvas.d.ts +4 -0
- package/dist/index.es.js +136 -62
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +136 -62
- 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 +2 -2
- package/src/components/carousel/CCarousel.tsx +9 -5
- package/src/components/close-button/CCloseButton.tsx +9 -1
- package/src/components/dropdown/CDropdownMenu.tsx +1 -1
- package/src/components/modal/CModal.tsx +25 -9
- package/src/components/nav/CNav.tsx +2 -2
- package/src/components/nav/CNavGroup.tsx +9 -2
- package/src/components/navbar/CNavbar.tsx +2 -2
- package/src/components/offcanvas/COffcanvas.tsx +8 -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": "5.0.0-alpha.
|
|
3
|
+
"version": "5.0.0-alpha.1",
|
|
4
4
|
"description": "UI Components Library for React.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"typescript": "^5.1.6"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
|
-
"@coreui/coreui": "^5.0.0-alpha.
|
|
63
|
+
"@coreui/coreui": "^5.0.0-alpha.2",
|
|
64
64
|
"react": ">=17",
|
|
65
65
|
"react-dom": ">=17"
|
|
66
66
|
}
|
|
@@ -226,11 +226,11 @@ export const CCarousel = forwardRef<HTMLDivElement, CCarouselProps>(
|
|
|
226
226
|
className={classNames(
|
|
227
227
|
'carousel slide',
|
|
228
228
|
{
|
|
229
|
-
'carousel-dark': dark,
|
|
230
229
|
'carousel-fade': transition === 'crossfade',
|
|
231
230
|
},
|
|
232
231
|
className,
|
|
233
232
|
)}
|
|
233
|
+
{...(dark && { 'data-coreui-theme': 'dark' })}
|
|
234
234
|
onMouseEnter={_pause}
|
|
235
235
|
onMouseLeave={cycle}
|
|
236
236
|
{...(touch && { onTouchStart: handleTouchStart, onTouchMove: handleTouchMove })}
|
|
@@ -244,20 +244,24 @@ export const CCarousel = forwardRef<HTMLDivElement, CCarouselProps>(
|
|
|
244
244
|
}}
|
|
245
245
|
>
|
|
246
246
|
{indicators && (
|
|
247
|
-
<
|
|
247
|
+
<div className="carousel-indicators">
|
|
248
248
|
{Array.from({ length: itemsNumber }, (_, i) => i).map((index) => {
|
|
249
249
|
return (
|
|
250
|
-
<
|
|
250
|
+
<button
|
|
251
251
|
key={`indicator${index}`}
|
|
252
252
|
onClick={() => {
|
|
253
253
|
!animating && handleIndicatorClick(index)
|
|
254
254
|
}}
|
|
255
|
-
className={
|
|
255
|
+
className={classNames({
|
|
256
|
+
active: active === index
|
|
257
|
+
})}
|
|
256
258
|
data-coreui-target=""
|
|
259
|
+
{...(active === index && { 'aria-current': true })}
|
|
260
|
+
aria-label={`Slide ${index + 1}`}
|
|
257
261
|
/>
|
|
258
262
|
)
|
|
259
263
|
})}
|
|
260
|
-
</
|
|
264
|
+
</div>
|
|
261
265
|
)}
|
|
262
266
|
<div className="carousel-inner">
|
|
263
267
|
{Children.map(children, (child, index) => {
|
|
@@ -7,18 +7,24 @@ export interface CCloseButtonProps extends HTMLAttributes<HTMLButtonElement> {
|
|
|
7
7
|
* A string of all className you want applied to the base component.
|
|
8
8
|
*/
|
|
9
9
|
className?: string
|
|
10
|
+
/**
|
|
11
|
+
* Invert the default color.
|
|
12
|
+
*/
|
|
13
|
+
dark?: boolean
|
|
10
14
|
/**
|
|
11
15
|
* Toggle the disabled state for the component.
|
|
12
16
|
*/
|
|
13
17
|
disabled?: boolean
|
|
14
18
|
/**
|
|
15
19
|
* Change the default color to white.
|
|
20
|
+
*
|
|
21
|
+
* @deprecated 5.0.0
|
|
16
22
|
*/
|
|
17
23
|
white?: boolean
|
|
18
24
|
}
|
|
19
25
|
|
|
20
26
|
export const CCloseButton = forwardRef<HTMLButtonElement, CCloseButtonProps>(
|
|
21
|
-
({ className, disabled, white, ...rest }, ref) => {
|
|
27
|
+
({ className, dark, disabled, white, ...rest }, ref) => {
|
|
22
28
|
return (
|
|
23
29
|
<button
|
|
24
30
|
type="button"
|
|
@@ -33,6 +39,7 @@ export const CCloseButton = forwardRef<HTMLButtonElement, CCloseButtonProps>(
|
|
|
33
39
|
)}
|
|
34
40
|
aria-label="Close"
|
|
35
41
|
disabled={disabled}
|
|
42
|
+
{...(dark && { 'data-coreui-theme': 'dark' })}
|
|
36
43
|
{...rest}
|
|
37
44
|
ref={ref}
|
|
38
45
|
/>
|
|
@@ -42,6 +49,7 @@ export const CCloseButton = forwardRef<HTMLButtonElement, CCloseButtonProps>(
|
|
|
42
49
|
|
|
43
50
|
CCloseButton.propTypes = {
|
|
44
51
|
className: PropTypes.string,
|
|
52
|
+
dark: PropTypes.bool,
|
|
45
53
|
disabled: PropTypes.bool,
|
|
46
54
|
white: PropTypes.bool,
|
|
47
55
|
}
|
|
@@ -46,7 +46,6 @@ export const CDropdownMenu = forwardRef<HTMLDivElement | HTMLUListElement, CDrop
|
|
|
46
46
|
className={classNames(
|
|
47
47
|
'dropdown-menu',
|
|
48
48
|
{
|
|
49
|
-
'dropdown-menu-dark': dark,
|
|
50
49
|
show: visible,
|
|
51
50
|
},
|
|
52
51
|
alignment && alignmentClassNames(alignment),
|
|
@@ -56,6 +55,7 @@ export const CDropdownMenu = forwardRef<HTMLDivElement | HTMLUListElement, CDrop
|
|
|
56
55
|
role="menu"
|
|
57
56
|
aria-hidden={!visible}
|
|
58
57
|
{...(!popper && { 'data-coreui-popper': 'static' })}
|
|
58
|
+
{...(dark && { 'data-coreui-theme': 'dark' })}
|
|
59
59
|
{...rest}
|
|
60
60
|
>
|
|
61
61
|
{Component === 'ul'
|
|
@@ -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)
|
|
@@ -128,11 +136,16 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
|
|
|
128
136
|
}, [visible])
|
|
129
137
|
|
|
130
138
|
useEffect(() => {
|
|
131
|
-
|
|
132
|
-
|
|
139
|
+
if (_visible) {
|
|
140
|
+
activeElementRef.current = document.activeElement as HTMLElement | null
|
|
141
|
+
document.addEventListener('mouseup', handleClickOutside)
|
|
142
|
+
document.addEventListener('keydown', handleKeyDown)
|
|
143
|
+
} else {
|
|
144
|
+
activeElementRef.current?.focus()
|
|
145
|
+
}
|
|
133
146
|
|
|
134
147
|
return () => {
|
|
135
|
-
document.removeEventListener('
|
|
148
|
+
document.removeEventListener('mouseup', handleClickOutside)
|
|
136
149
|
document.removeEventListener('keydown', handleKeyDown)
|
|
137
150
|
}
|
|
138
151
|
}, [_visible])
|
|
@@ -143,6 +156,7 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
|
|
|
143
156
|
}
|
|
144
157
|
|
|
145
158
|
setVisible(false)
|
|
159
|
+
|
|
146
160
|
return onClose && onClose()
|
|
147
161
|
}
|
|
148
162
|
|
|
@@ -163,7 +177,7 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
|
|
|
163
177
|
|
|
164
178
|
setTimeout(
|
|
165
179
|
() => {
|
|
166
|
-
modalRef.current?.focus()
|
|
180
|
+
focus && modalRef.current?.focus()
|
|
167
181
|
},
|
|
168
182
|
transition ? duration : 0,
|
|
169
183
|
)
|
|
@@ -225,10 +239,13 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
|
|
|
225
239
|
className,
|
|
226
240
|
)}
|
|
227
241
|
tabIndex={-1}
|
|
228
|
-
|
|
242
|
+
{...(_visible
|
|
243
|
+
? { 'aria-modal': true, role: 'dialog' }
|
|
244
|
+
: { 'aria-hidden': 'true' })}
|
|
229
245
|
style={{
|
|
230
246
|
...(state !== 'exited' && { display: 'block' }),
|
|
231
247
|
}}
|
|
248
|
+
{...rest}
|
|
232
249
|
ref={forkedRef}
|
|
233
250
|
>
|
|
234
251
|
<CModalDialog
|
|
@@ -237,9 +254,7 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
|
|
|
237
254
|
scrollable={scrollable}
|
|
238
255
|
size={size}
|
|
239
256
|
>
|
|
240
|
-
<CModalContent
|
|
241
|
-
{children}
|
|
242
|
-
</CModalContent>
|
|
257
|
+
<CModalContent ref={modalContentRef}>{children}</CModalContent>
|
|
243
258
|
</CModalDialog>
|
|
244
259
|
</div>
|
|
245
260
|
</CModalContext.Provider>
|
|
@@ -262,6 +277,7 @@ CModal.propTypes = {
|
|
|
262
277
|
children: PropTypes.node,
|
|
263
278
|
className: PropTypes.string,
|
|
264
279
|
duration: PropTypes.number,
|
|
280
|
+
focus: PropTypes.bool,
|
|
265
281
|
fullscreen: PropTypes.oneOfType([
|
|
266
282
|
PropTypes.bool,
|
|
267
283
|
PropTypes.oneOf<'sm' | 'md' | 'lg' | 'xl' | 'xxl'>(['sm', 'md', 'lg', 'xl', 'xxl']),
|
|
@@ -19,7 +19,7 @@ export interface CNavProps
|
|
|
19
19
|
/**
|
|
20
20
|
* Set the nav variant to tabs or pills.
|
|
21
21
|
*/
|
|
22
|
-
variant?: 'tabs' | '
|
|
22
|
+
variant?: 'pills' | 'tabs' | 'underline'
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export const CNav = forwardRef<HTMLDivElement | HTMLUListElement | HTMLOListElement, CNavProps>(
|
|
@@ -49,7 +49,7 @@ CNav.propTypes = {
|
|
|
49
49
|
className: PropTypes.string,
|
|
50
50
|
component: PropTypes.elementType,
|
|
51
51
|
layout: PropTypes.oneOf(['fill', 'justified']),
|
|
52
|
-
variant: PropTypes.oneOf(['tabs', '
|
|
52
|
+
variant: PropTypes.oneOf(['pills', 'tabs', 'underline']),
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
CNav.displayName = 'CNav'
|
|
@@ -36,6 +36,13 @@ export interface CNavGroupProps {
|
|
|
36
36
|
idx?: string
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
const isInVisibleGroup = (el1: string, el2: string) => {
|
|
40
|
+
const array1 = el1.toString().split('.')
|
|
41
|
+
const array2 = el2.toString().split('.')
|
|
42
|
+
|
|
43
|
+
return array2.every((item, index) => item === array1[index])
|
|
44
|
+
}
|
|
45
|
+
|
|
39
46
|
export const CNavGroup = forwardRef<HTMLLIElement, CNavGroupProps>(
|
|
40
47
|
({ children, className, compact, idx, toggler, visible, ...rest }, ref) => {
|
|
41
48
|
const [height, setHeight] = useState<number | string>()
|
|
@@ -45,12 +52,12 @@ export const CNavGroup = forwardRef<HTMLLIElement, CNavGroupProps>(
|
|
|
45
52
|
|
|
46
53
|
const [_visible, setVisible] = useState(
|
|
47
54
|
Boolean(
|
|
48
|
-
visible || (idx && visibleGroup && visibleGroup
|
|
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>) => {
|
|
@@ -17,7 +17,7 @@ export interface CNavbarProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
17
17
|
*/
|
|
18
18
|
color?: Colors
|
|
19
19
|
/**
|
|
20
|
-
* Sets if the color of text should be colored for a light or dark
|
|
20
|
+
* Sets if the color of text should be colored for a light or dark background.
|
|
21
21
|
*/
|
|
22
22
|
colorScheme?: 'dark' | 'light'
|
|
23
23
|
/**
|
|
@@ -59,12 +59,12 @@ export const CNavbar = forwardRef<HTMLDivElement, CNavbarProps>(
|
|
|
59
59
|
'navbar',
|
|
60
60
|
{
|
|
61
61
|
[`bg-${color}`]: color,
|
|
62
|
-
[`navbar-${colorScheme}`]: colorScheme,
|
|
63
62
|
[typeof expand === 'boolean' ? 'navbar-expand' : `navbar-expand-${expand}`]: expand,
|
|
64
63
|
},
|
|
65
64
|
placement,
|
|
66
65
|
className,
|
|
67
66
|
)}
|
|
67
|
+
{...(colorScheme && { 'data-coreui-theme': colorScheme })}
|
|
68
68
|
{...rest}
|
|
69
69
|
ref={ref}
|
|
70
70
|
>
|
|
@@ -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'
|
|
@@ -17,6 +17,10 @@ export interface COffcanvasProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
17
17
|
* A string of all className you want applied to the base component.
|
|
18
18
|
*/
|
|
19
19
|
className?: string
|
|
20
|
+
/**
|
|
21
|
+
* Sets a darker color scheme.
|
|
22
|
+
*/
|
|
23
|
+
dark?: boolean
|
|
20
24
|
/**
|
|
21
25
|
* Closes the offcanvas when escape key is pressed.
|
|
22
26
|
*/
|
|
@@ -59,6 +63,7 @@ export const COffcanvas = forwardRef<HTMLDivElement, COffcanvasProps>(
|
|
|
59
63
|
children,
|
|
60
64
|
backdrop = true,
|
|
61
65
|
className,
|
|
66
|
+
dark,
|
|
62
67
|
keyboard = true,
|
|
63
68
|
onHide,
|
|
64
69
|
onShow,
|
|
@@ -135,6 +140,7 @@ export const COffcanvas = forwardRef<HTMLDivElement, COffcanvasProps>(
|
|
|
135
140
|
role="dialog"
|
|
136
141
|
tabIndex={-1}
|
|
137
142
|
onKeyDown={handleKeyDown}
|
|
143
|
+
{...(dark && { 'data-coreui-theme': 'dark' })}
|
|
138
144
|
{...rest}
|
|
139
145
|
ref={forkedRef}
|
|
140
146
|
>
|
|
@@ -161,6 +167,7 @@ COffcanvas.propTypes = {
|
|
|
161
167
|
backdrop: PropTypes.oneOfType([PropTypes.bool, PropTypes.oneOf<'static'>(['static'])]),
|
|
162
168
|
children: PropTypes.node,
|
|
163
169
|
className: PropTypes.string,
|
|
170
|
+
dark: PropTypes.bool,
|
|
164
171
|
keyboard: PropTypes.bool,
|
|
165
172
|
onHide: PropTypes.func,
|
|
166
173
|
onShow: PropTypes.func,
|
|
@@ -7,7 +7,7 @@ import { Transition } from 'react-transition-group'
|
|
|
7
7
|
import { usePopper } from '../../hooks'
|
|
8
8
|
import { fallbackPlacementsPropType, triggerPropType } from '../../props'
|
|
9
9
|
import type { Placements, Triggers } from '../../types'
|
|
10
|
-
import { getRTLPlacement } from '../../utils'
|
|
10
|
+
import { getRTLPlacement, getTransitionDurationFromElement } from '../../utils'
|
|
11
11
|
|
|
12
12
|
export interface CPopoverProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title' | 'content'> {
|
|
13
13
|
/**
|
|
@@ -164,7 +164,7 @@ export const CPopover: FC<CPopoverProps> = ({
|
|
|
164
164
|
onExit={onHide}
|
|
165
165
|
timeout={{
|
|
166
166
|
enter: 0,
|
|
167
|
-
exit: 200,
|
|
167
|
+
exit: popoverRef.current ? getTransitionDurationFromElement(popoverRef.current) + 50 : 200,
|
|
168
168
|
}}
|
|
169
169
|
unmountOnExit
|
|
170
170
|
>
|
|
@@ -3,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
|
+
}
|