@coreui/react 4.10.1 → 4.11.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/conditional-portal/CConditionalPortal.d.ts +7 -1
- package/dist/components/dropdown/CDropdown.d.ts +6 -0
- package/dist/components/popover/CPopover.d.ts +6 -0
- package/dist/components/tooltip/CTooltip.d.ts +6 -0
- package/dist/index.es.js +63 -36
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +63 -36
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/conditional-portal/CConditionalPortal.tsx +31 -6
- package/src/components/dropdown/CDropdown.tsx +8 -0
- package/src/components/dropdown/CDropdownMenu.tsx +2 -2
- package/src/components/modal/CModal.tsx +1 -4
- package/src/components/popover/CPopover.tsx +69 -51
- package/src/components/tooltip/CTooltip.tsx +69 -58
package/package.json
CHANGED
|
@@ -1,21 +1,45 @@
|
|
|
1
|
-
import React, { FC, ReactNode } from 'react'
|
|
1
|
+
import React, { FC, ReactNode, useEffect, useState } from 'react'
|
|
2
2
|
import { createPortal } from 'react-dom'
|
|
3
3
|
import PropTypes from 'prop-types'
|
|
4
4
|
|
|
5
|
+
const getContainer = (container?: Element | (() => Element | null) | null) => {
|
|
6
|
+
if (container) {
|
|
7
|
+
return typeof container === 'function' ? container() : container
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return document.body
|
|
11
|
+
}
|
|
12
|
+
|
|
5
13
|
export interface CConditionalPortalProps {
|
|
6
14
|
/**
|
|
7
15
|
* @ignore
|
|
8
16
|
*/
|
|
9
17
|
children: ReactNode
|
|
18
|
+
/**
|
|
19
|
+
* An HTML element or function that returns a single element, with `document.body` as the default.
|
|
20
|
+
*
|
|
21
|
+
* @since v4.11.0
|
|
22
|
+
*/
|
|
23
|
+
container?: Element | (() => Element | null) | null
|
|
10
24
|
/**
|
|
11
25
|
* Render some children into a different part of the DOM
|
|
12
26
|
*/
|
|
13
|
-
portal: boolean
|
|
27
|
+
portal: boolean | any
|
|
14
28
|
}
|
|
15
29
|
|
|
16
|
-
export const CConditionalPortal: FC<CConditionalPortalProps> = ({
|
|
17
|
-
|
|
18
|
-
|
|
30
|
+
export const CConditionalPortal: FC<CConditionalPortalProps> = ({
|
|
31
|
+
children,
|
|
32
|
+
container,
|
|
33
|
+
portal,
|
|
34
|
+
}) => {
|
|
35
|
+
const [_container, setContainer] = useState<ReturnType<typeof getContainer>>(null)
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
portal && setContainer(getContainer(container) || document.body)
|
|
39
|
+
}, [container, portal])
|
|
40
|
+
|
|
41
|
+
return typeof window !== 'undefined' && portal && _container ? (
|
|
42
|
+
createPortal(children, _container)
|
|
19
43
|
) : (
|
|
20
44
|
<>{children}</>
|
|
21
45
|
)
|
|
@@ -23,7 +47,8 @@ export const CConditionalPortal: FC<CConditionalPortalProps> = ({ children, port
|
|
|
23
47
|
|
|
24
48
|
CConditionalPortal.propTypes = {
|
|
25
49
|
children: PropTypes.node,
|
|
26
|
-
|
|
50
|
+
container: PropTypes.any, // HTMLElement
|
|
51
|
+
portal: PropTypes.bool,
|
|
27
52
|
}
|
|
28
53
|
|
|
29
54
|
CConditionalPortal.displayName = 'CConditionalPortal'
|
|
@@ -51,6 +51,12 @@ export interface CDropdownProps extends HTMLAttributes<HTMLDivElement | HTMLLIEl
|
|
|
51
51
|
* Component used for the root node. Either a string to use a HTML element or a component.
|
|
52
52
|
*/
|
|
53
53
|
component?: string | ElementType
|
|
54
|
+
/**
|
|
55
|
+
* Appends the react dropdown menu to a specific element. You can pass an HTML element or function that returns a single element. By default `document.body`.
|
|
56
|
+
*
|
|
57
|
+
* @since v4.11.0
|
|
58
|
+
*/
|
|
59
|
+
container?: Element | (() => Element | null) | null
|
|
54
60
|
/**
|
|
55
61
|
* Sets a darker color scheme to match a dark navbar.
|
|
56
62
|
*/
|
|
@@ -147,6 +153,7 @@ export const CDropdown = forwardRef<HTMLDivElement | HTMLLIElement, CDropdownPro
|
|
|
147
153
|
alignment,
|
|
148
154
|
autoClose = true,
|
|
149
155
|
className,
|
|
156
|
+
container,
|
|
150
157
|
dark,
|
|
151
158
|
direction,
|
|
152
159
|
offset = [0, 2],
|
|
@@ -179,6 +186,7 @@ export const CDropdown = forwardRef<HTMLDivElement | HTMLLIElement, CDropdownPro
|
|
|
179
186
|
|
|
180
187
|
const contextValues = {
|
|
181
188
|
alignment,
|
|
189
|
+
container,
|
|
182
190
|
dark,
|
|
183
191
|
dropdownToggleRef,
|
|
184
192
|
dropdownMenuRef,
|
|
@@ -35,13 +35,13 @@ const alignmentClassNames = (alignment: Alignments) => {
|
|
|
35
35
|
|
|
36
36
|
export const CDropdownMenu = forwardRef<HTMLDivElement | HTMLUListElement, CDropdownMenuProps>(
|
|
37
37
|
({ children, className, component: Component = 'ul', ...rest }, ref) => {
|
|
38
|
-
const { alignment, dark, dropdownMenuRef, popper, portal, visible } =
|
|
38
|
+
const { alignment, container, dark, dropdownMenuRef, popper, portal, visible } =
|
|
39
39
|
useContext(CDropdownContext)
|
|
40
40
|
|
|
41
41
|
const forkedRef = useForkedRef(ref, dropdownMenuRef)
|
|
42
42
|
|
|
43
43
|
return (
|
|
44
|
-
<CConditionalPortal portal={portal ?? false}>
|
|
44
|
+
<CConditionalPortal container={container} portal={portal ?? false}>
|
|
45
45
|
<Component
|
|
46
46
|
className={classNames(
|
|
47
47
|
'dropdown-menu',
|
|
@@ -200,10 +200,7 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
|
|
|
200
200
|
}, [_visible])
|
|
201
201
|
|
|
202
202
|
const handleClickOutside = (event: Event) => {
|
|
203
|
-
if (
|
|
204
|
-
modalContentRef.current &&
|
|
205
|
-
!modalContentRef.current.contains(event.target as HTMLElement)
|
|
206
|
-
) {
|
|
203
|
+
if (modalRef.current && modalRef.current == event.target) {
|
|
207
204
|
handleDismiss()
|
|
208
205
|
}
|
|
209
206
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React, { forwardRef, HTMLAttributes, ReactNode, useRef, useEffect, useState } from 'react'
|
|
2
|
-
import { createPortal } from 'react-dom'
|
|
3
2
|
import classNames from 'classnames'
|
|
4
3
|
import PropTypes from 'prop-types'
|
|
5
4
|
import { Transition } from 'react-transition-group'
|
|
6
5
|
|
|
6
|
+
import { CConditionalPortal } from '../conditional-portal'
|
|
7
7
|
import { useForkedRef, usePopper } from '../../hooks'
|
|
8
8
|
import { fallbackPlacementsPropType, triggerPropType } from '../../props'
|
|
9
9
|
import type { Placements, Triggers } from '../../types'
|
|
@@ -20,6 +20,12 @@ export interface CPopoverProps extends Omit<HTMLAttributes<HTMLDivElement>, 'tit
|
|
|
20
20
|
* A string of all className you want applied to the component.
|
|
21
21
|
*/
|
|
22
22
|
className?: string
|
|
23
|
+
/**
|
|
24
|
+
* Appends the react popover to a specific element. You can pass an HTML element or function that returns a single element. By default `document.body`.
|
|
25
|
+
*
|
|
26
|
+
* @since v4.11.0
|
|
27
|
+
*/
|
|
28
|
+
container?: Element | (() => Element | null) | null
|
|
23
29
|
/**
|
|
24
30
|
* Content node for your component.
|
|
25
31
|
*/
|
|
@@ -74,6 +80,7 @@ export const CPopover = forwardRef<HTMLDivElement, CPopoverProps>(
|
|
|
74
80
|
children,
|
|
75
81
|
animation = true,
|
|
76
82
|
className,
|
|
83
|
+
container,
|
|
77
84
|
content,
|
|
78
85
|
delay = 0,
|
|
79
86
|
fallbackPlacements = ['top', 'right', 'bottom', 'left'],
|
|
@@ -88,9 +95,10 @@ export const CPopover = forwardRef<HTMLDivElement, CPopoverProps>(
|
|
|
88
95
|
},
|
|
89
96
|
ref,
|
|
90
97
|
) => {
|
|
91
|
-
const popoverRef = useRef(null)
|
|
98
|
+
const popoverRef = useRef<HTMLDivElement>(null)
|
|
92
99
|
const togglerRef = useRef(null)
|
|
93
100
|
const forkedRef = useForkedRef(ref, popoverRef)
|
|
101
|
+
const uID = useRef(`popover${Math.floor(Math.random() * 1_000_000)}`)
|
|
94
102
|
|
|
95
103
|
const { initPopper, destroyPopper } = usePopper()
|
|
96
104
|
const [_visible, setVisible] = useState(visible)
|
|
@@ -125,16 +133,6 @@ export const CPopover = forwardRef<HTMLDivElement, CPopoverProps>(
|
|
|
125
133
|
setVisible(visible)
|
|
126
134
|
}, [visible])
|
|
127
135
|
|
|
128
|
-
useEffect(() => {
|
|
129
|
-
if (_visible && togglerRef.current && popoverRef.current) {
|
|
130
|
-
initPopper(togglerRef.current, popoverRef.current, popperConfig)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return () => {
|
|
134
|
-
destroyPopper()
|
|
135
|
-
}
|
|
136
|
-
}, [_visible])
|
|
137
|
-
|
|
138
136
|
const toggleVisible = (visible: boolean) => {
|
|
139
137
|
if (visible) {
|
|
140
138
|
setTimeout(() => setVisible(true), _delay.show)
|
|
@@ -147,6 +145,9 @@ export const CPopover = forwardRef<HTMLDivElement, CPopoverProps>(
|
|
|
147
145
|
return (
|
|
148
146
|
<>
|
|
149
147
|
{React.cloneElement(children as React.ReactElement<any>, {
|
|
148
|
+
...(_visible && {
|
|
149
|
+
'aria-describedby': uID.current,
|
|
150
|
+
}),
|
|
150
151
|
ref: togglerRef,
|
|
151
152
|
...((trigger === 'click' || trigger.includes('click')) && {
|
|
152
153
|
onClick: () => toggleVisible(!_visible),
|
|
@@ -160,45 +161,61 @@ export const CPopover = forwardRef<HTMLDivElement, CPopoverProps>(
|
|
|
160
161
|
onMouseLeave: () => toggleVisible(false),
|
|
161
162
|
}),
|
|
162
163
|
})}
|
|
163
|
-
{
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
164
|
+
<CConditionalPortal container={container} portal={true}>
|
|
165
|
+
<Transition
|
|
166
|
+
in={_visible}
|
|
167
|
+
mountOnEnter
|
|
168
|
+
nodeRef={popoverRef}
|
|
169
|
+
onEnter={() => {
|
|
170
|
+
if (togglerRef.current && popoverRef.current) {
|
|
171
|
+
initPopper(togglerRef.current, popoverRef.current, popperConfig)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
onShow
|
|
175
|
+
}}
|
|
176
|
+
onEntering={() => {
|
|
177
|
+
if (togglerRef.current && popoverRef.current) {
|
|
178
|
+
popoverRef.current.style.display = 'initial'
|
|
179
|
+
}
|
|
180
|
+
}}
|
|
181
|
+
onExit={onHide}
|
|
182
|
+
onExited={() => {
|
|
183
|
+
destroyPopper()
|
|
184
|
+
}}
|
|
185
|
+
timeout={{
|
|
186
|
+
enter: 0,
|
|
187
|
+
exit: popoverRef.current
|
|
188
|
+
? getTransitionDurationFromElement(popoverRef.current) + 50
|
|
189
|
+
: 200,
|
|
190
|
+
}}
|
|
191
|
+
unmountOnExit
|
|
192
|
+
>
|
|
193
|
+
{(state) => (
|
|
194
|
+
<div
|
|
195
|
+
className={classNames(
|
|
196
|
+
'popover',
|
|
197
|
+
'bs-popover-auto',
|
|
198
|
+
{
|
|
199
|
+
fade: animation,
|
|
200
|
+
show: state === 'entered',
|
|
201
|
+
},
|
|
202
|
+
className,
|
|
203
|
+
)}
|
|
204
|
+
id={uID.current}
|
|
205
|
+
ref={forkedRef}
|
|
206
|
+
role="tooltip"
|
|
207
|
+
style={{
|
|
208
|
+
display: 'none',
|
|
209
|
+
}}
|
|
210
|
+
{...rest}
|
|
211
|
+
>
|
|
212
|
+
<div className="popover-arrow"></div>
|
|
213
|
+
<div className="popover-header">{title}</div>
|
|
214
|
+
<div className="popover-body">{content}</div>
|
|
215
|
+
</div>
|
|
216
|
+
)}
|
|
217
|
+
</Transition>
|
|
218
|
+
</CConditionalPortal>
|
|
202
219
|
</>
|
|
203
220
|
)
|
|
204
221
|
},
|
|
@@ -208,6 +225,7 @@ CPopover.propTypes = {
|
|
|
208
225
|
animation: PropTypes.bool,
|
|
209
226
|
children: PropTypes.node,
|
|
210
227
|
className: PropTypes.string,
|
|
228
|
+
container: PropTypes.any,
|
|
211
229
|
content: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
|
212
230
|
delay: PropTypes.oneOfType([
|
|
213
231
|
PropTypes.number,
|
|
@@ -1,16 +1,9 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
forwardRef,
|
|
3
|
-
HTMLAttributes,
|
|
4
|
-
ReactNode,
|
|
5
|
-
useRef,
|
|
6
|
-
useEffect,
|
|
7
|
-
useState,
|
|
8
|
-
} from 'react'
|
|
9
|
-
import { createPortal } from 'react-dom'
|
|
1
|
+
import React, { forwardRef, HTMLAttributes, ReactNode, useRef, useEffect, useState } from 'react'
|
|
10
2
|
import classNames from 'classnames'
|
|
11
3
|
import PropTypes from 'prop-types'
|
|
12
4
|
import { Transition } from 'react-transition-group'
|
|
13
5
|
|
|
6
|
+
import { CConditionalPortal } from '../conditional-portal'
|
|
14
7
|
import { useForkedRef, usePopper } from '../../hooks'
|
|
15
8
|
import { fallbackPlacementsPropType, triggerPropType } from '../../props'
|
|
16
9
|
import type { Placements, Triggers } from '../../types'
|
|
@@ -27,6 +20,12 @@ export interface CTooltipProps extends Omit<HTMLAttributes<HTMLDivElement>, 'con
|
|
|
27
20
|
* A string of all className you want applied to the component.
|
|
28
21
|
*/
|
|
29
22
|
className?: string
|
|
23
|
+
/**
|
|
24
|
+
* Appends the react tooltip to a specific element. You can pass an HTML element or function that returns a single element. By default `document.body`.
|
|
25
|
+
*
|
|
26
|
+
* @since v4.11.0
|
|
27
|
+
*/
|
|
28
|
+
container?: Element | (() => Element | null) | null
|
|
30
29
|
/**
|
|
31
30
|
* Content node for your component.
|
|
32
31
|
*/
|
|
@@ -77,6 +76,7 @@ export const CTooltip = forwardRef<HTMLDivElement, CTooltipProps>(
|
|
|
77
76
|
children,
|
|
78
77
|
animation = true,
|
|
79
78
|
className,
|
|
79
|
+
container,
|
|
80
80
|
content,
|
|
81
81
|
delay = 0,
|
|
82
82
|
fallbackPlacements = ['top', 'right', 'bottom', 'left'],
|
|
@@ -90,9 +90,10 @@ export const CTooltip = forwardRef<HTMLDivElement, CTooltipProps>(
|
|
|
90
90
|
},
|
|
91
91
|
ref,
|
|
92
92
|
) => {
|
|
93
|
-
const tooltipRef = useRef(null)
|
|
93
|
+
const tooltipRef = useRef<HTMLDivElement>(null)
|
|
94
94
|
const togglerRef = useRef(null)
|
|
95
95
|
const forkedRef = useForkedRef(ref, tooltipRef)
|
|
96
|
+
const uID = useRef(`tooltip${Math.floor(Math.random() * 1_000_000)}`)
|
|
96
97
|
|
|
97
98
|
const { initPopper, destroyPopper } = usePopper()
|
|
98
99
|
const [_visible, setVisible] = useState(visible)
|
|
@@ -127,16 +128,6 @@ export const CTooltip = forwardRef<HTMLDivElement, CTooltipProps>(
|
|
|
127
128
|
setVisible(visible)
|
|
128
129
|
}, [visible])
|
|
129
130
|
|
|
130
|
-
useEffect(() => {
|
|
131
|
-
if (_visible && togglerRef.current && tooltipRef.current) {
|
|
132
|
-
initPopper(togglerRef.current, tooltipRef.current, popperConfig)
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return () => {
|
|
136
|
-
destroyPopper()
|
|
137
|
-
}
|
|
138
|
-
}, [_visible])
|
|
139
|
-
|
|
140
131
|
const toggleVisible = (visible: boolean) => {
|
|
141
132
|
if (visible) {
|
|
142
133
|
setTimeout(() => setVisible(true), _delay.show)
|
|
@@ -149,6 +140,9 @@ export const CTooltip = forwardRef<HTMLDivElement, CTooltipProps>(
|
|
|
149
140
|
return (
|
|
150
141
|
<>
|
|
151
142
|
{React.cloneElement(children as React.ReactElement<any>, {
|
|
143
|
+
...(_visible && {
|
|
144
|
+
'aria-describedby': uID.current,
|
|
145
|
+
}),
|
|
152
146
|
ref: togglerRef,
|
|
153
147
|
...((trigger === 'click' || trigger.includes('click')) && {
|
|
154
148
|
onClick: () => toggleVisible(!_visible),
|
|
@@ -162,44 +156,60 @@ export const CTooltip = forwardRef<HTMLDivElement, CTooltipProps>(
|
|
|
162
156
|
onMouseLeave: () => toggleVisible(false),
|
|
163
157
|
}),
|
|
164
158
|
})}
|
|
165
|
-
{
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
159
|
+
<CConditionalPortal container={container} portal={true}>
|
|
160
|
+
<Transition
|
|
161
|
+
in={_visible}
|
|
162
|
+
mountOnEnter
|
|
163
|
+
nodeRef={tooltipRef}
|
|
164
|
+
onEnter={() => {
|
|
165
|
+
if (togglerRef.current && tooltipRef.current) {
|
|
166
|
+
initPopper(togglerRef.current, tooltipRef.current, popperConfig)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
onShow
|
|
170
|
+
}}
|
|
171
|
+
onEntering={() => {
|
|
172
|
+
if (togglerRef.current && tooltipRef.current) {
|
|
173
|
+
tooltipRef.current.style.display = 'initial'
|
|
174
|
+
}
|
|
175
|
+
}}
|
|
176
|
+
onExit={onHide}
|
|
177
|
+
onExited={() => {
|
|
178
|
+
destroyPopper()
|
|
179
|
+
}}
|
|
180
|
+
timeout={{
|
|
181
|
+
enter: 0,
|
|
182
|
+
exit: tooltipRef.current
|
|
183
|
+
? getTransitionDurationFromElement(tooltipRef.current) + 50
|
|
184
|
+
: 200,
|
|
185
|
+
}}
|
|
186
|
+
unmountOnExit
|
|
187
|
+
>
|
|
188
|
+
{(state) => (
|
|
189
|
+
<div
|
|
190
|
+
className={classNames(
|
|
191
|
+
'tooltip',
|
|
192
|
+
'bs-tooltip-auto',
|
|
193
|
+
{
|
|
194
|
+
fade: animation,
|
|
195
|
+
show: state === 'entered',
|
|
196
|
+
},
|
|
197
|
+
className,
|
|
198
|
+
)}
|
|
199
|
+
id={uID.current}
|
|
200
|
+
ref={forkedRef}
|
|
201
|
+
role="tooltip"
|
|
202
|
+
style={{
|
|
203
|
+
display: 'none',
|
|
204
|
+
}}
|
|
205
|
+
{...rest}
|
|
206
|
+
>
|
|
207
|
+
<div className="tooltip-arrow"></div>
|
|
208
|
+
<div className="tooltip-inner">{content}</div>
|
|
209
|
+
</div>
|
|
210
|
+
)}
|
|
211
|
+
</Transition>
|
|
212
|
+
</CConditionalPortal>
|
|
203
213
|
</>
|
|
204
214
|
)
|
|
205
215
|
},
|
|
@@ -208,6 +218,7 @@ export const CTooltip = forwardRef<HTMLDivElement, CTooltipProps>(
|
|
|
208
218
|
CTooltip.propTypes = {
|
|
209
219
|
animation: PropTypes.bool,
|
|
210
220
|
children: PropTypes.node,
|
|
221
|
+
container: PropTypes.any,
|
|
211
222
|
content: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
|
212
223
|
delay: PropTypes.oneOfType([
|
|
213
224
|
PropTypes.number,
|