@coreui/react-pro 4.13.1 → 4.14.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.
@@ -1,10 +1,17 @@
1
- import React, { FC, HTMLAttributes, ReactNode, useRef, useEffect, useState } from 'react'
1
+ import React, {
2
+ forwardRef,
3
+ HTMLAttributes,
4
+ ReactNode,
5
+ useRef,
6
+ useEffect,
7
+ useState,
8
+ } from 'react'
2
9
  import { createPortal } from 'react-dom'
3
10
  import classNames from 'classnames'
4
11
  import PropTypes from 'prop-types'
5
12
  import { Transition } from 'react-transition-group'
6
13
 
7
- import { usePopper } from '../../hooks'
14
+ import { useForkedRef, usePopper } from '../../hooks'
8
15
  import { fallbackPlacementsPropType, triggerPropType } from '../../props'
9
16
  import type { Placements, Triggers } from '../../types'
10
17
  import { getRTLPlacement, getTransitionDurationFromElement } from '../../utils'
@@ -64,129 +71,139 @@ export interface CTooltipProps extends Omit<HTMLAttributes<HTMLDivElement>, 'con
64
71
  visible?: boolean
65
72
  }
66
73
 
67
- export const CTooltip: FC<CTooltipProps> = ({
68
- children,
69
- animation = true,
70
- className,
71
- content,
72
- delay = 0,
73
- fallbackPlacements = ['top', 'right', 'bottom', 'left'],
74
- offset = [0, 6],
75
- onHide,
76
- onShow,
77
- placement = 'top',
78
- trigger = ['hover', 'focus'],
79
- visible,
80
- ...rest
81
- }) => {
82
- const tooltipRef = useRef(null)
83
- const togglerRef = useRef(null)
84
- const { initPopper, destroyPopper } = usePopper()
85
- const [_visible, setVisible] = useState(visible)
74
+ export const CTooltip = forwardRef<HTMLDivElement, CTooltipProps>(
75
+ (
76
+ {
77
+ children,
78
+ animation = true,
79
+ className,
80
+ content,
81
+ delay = 0,
82
+ fallbackPlacements = ['top', 'right', 'bottom', 'left'],
83
+ offset = [0, 6],
84
+ onHide,
85
+ onShow,
86
+ placement = 'top',
87
+ trigger = ['hover', 'focus'],
88
+ visible,
89
+ ...rest
90
+ },
91
+ ref,
92
+ ) => {
93
+ const tooltipRef = useRef(null)
94
+ const togglerRef = useRef(null)
95
+ const forkedRef = useForkedRef(ref, tooltipRef)
86
96
 
87
- const _delay = typeof delay === 'number' ? { show: delay, hide: delay } : delay
97
+ const { initPopper, destroyPopper } = usePopper()
98
+ const [_visible, setVisible] = useState(visible)
88
99
 
89
- const popperConfig = {
90
- modifiers: [
91
- {
92
- name: 'arrow',
93
- options: {
94
- element: '.tooltip-arrow',
100
+ const _delay = typeof delay === 'number' ? { show: delay, hide: delay } : delay
101
+
102
+ const popperConfig = {
103
+ modifiers: [
104
+ {
105
+ name: 'arrow',
106
+ options: {
107
+ element: '.tooltip-arrow',
108
+ },
95
109
  },
96
- },
97
- {
98
- name: 'flip',
99
- options: {
100
- fallbackPlacements: fallbackPlacements,
110
+ {
111
+ name: 'flip',
112
+ options: {
113
+ fallbackPlacements: fallbackPlacements,
114
+ },
101
115
  },
102
- },
103
- {
104
- name: 'offset',
105
- options: {
106
- offset: offset,
116
+ {
117
+ name: 'offset',
118
+ options: {
119
+ offset: offset,
120
+ },
107
121
  },
108
- },
109
- ],
110
- placement: getRTLPlacement(placement, togglerRef.current),
111
- }
122
+ ],
123
+ placement: getRTLPlacement(placement, togglerRef.current),
124
+ }
112
125
 
113
- useEffect(() => {
114
- setVisible(visible)
115
- }, [visible])
126
+ useEffect(() => {
127
+ setVisible(visible)
128
+ }, [visible])
116
129
 
117
- useEffect(() => {
118
- if (_visible && togglerRef.current && tooltipRef.current) {
119
- initPopper(togglerRef.current, tooltipRef.current, popperConfig)
120
- }
130
+ useEffect(() => {
131
+ if (_visible && togglerRef.current && tooltipRef.current) {
132
+ initPopper(togglerRef.current, tooltipRef.current, popperConfig)
133
+ }
121
134
 
122
- return () => {
123
- destroyPopper()
124
- }
125
- }, [_visible])
135
+ return () => {
136
+ destroyPopper()
137
+ }
138
+ }, [_visible])
126
139
 
127
- const toggleVisible = (visible: boolean) => {
128
- if (visible) {
129
- setTimeout(() => setVisible(true), _delay.show)
130
- return
131
- }
140
+ const toggleVisible = (visible: boolean) => {
141
+ if (visible) {
142
+ setTimeout(() => setVisible(true), _delay.show)
143
+ return
144
+ }
132
145
 
133
- setTimeout(() => setVisible(false), _delay.hide)
134
- }
146
+ setTimeout(() => setVisible(false), _delay.hide)
147
+ }
135
148
 
136
- return (
137
- <>
138
- {React.cloneElement(children as React.ReactElement<any>, {
139
- ref: togglerRef,
140
- ...((trigger === 'click' || trigger.includes('click')) && {
141
- onClick: () => toggleVisible(!_visible),
142
- }),
143
- ...((trigger === 'focus' || trigger.includes('focus')) && {
144
- onFocus: () => toggleVisible(true),
145
- onBlur: () => toggleVisible(false),
146
- }),
147
- ...((trigger === 'hover' || trigger.includes('hover')) && {
148
- onMouseEnter: () => toggleVisible(true),
149
- onMouseLeave: () => toggleVisible(false),
150
- }),
151
- })}
152
- {typeof window !== 'undefined' &&
153
- createPortal(
154
- <Transition
155
- in={_visible}
156
- mountOnEnter
157
- onEnter={onShow}
158
- onExit={onHide}
159
- timeout={{
160
- enter: 0,
161
- exit: tooltipRef.current ? getTransitionDurationFromElement(tooltipRef.current) + 50 : 200,
162
- }}
163
- unmountOnExit
164
- >
165
- {(state) => (
166
- <div
167
- className={classNames(
168
- 'tooltip',
169
- 'bs-tooltip-auto',
170
- {
171
- fade: animation,
172
- show: state === 'entered',
173
- },
174
- className,
175
- )}
176
- ref={tooltipRef}
177
- role="tooltip"
178
- {...rest}
179
- >
180
- <div className="tooltip-arrow"></div>
181
- <div className="tooltip-inner">{content}</div>
182
- </div>
183
- )}
184
- </Transition>,
185
- document.body,
186
- )}
187
- </>
188
- )
189
- }
149
+ return (
150
+ <>
151
+ {React.cloneElement(children as React.ReactElement<any>, {
152
+ ref: togglerRef,
153
+ ...((trigger === 'click' || trigger.includes('click')) && {
154
+ onClick: () => toggleVisible(!_visible),
155
+ }),
156
+ ...((trigger === 'focus' || trigger.includes('focus')) && {
157
+ onFocus: () => toggleVisible(true),
158
+ onBlur: () => toggleVisible(false),
159
+ }),
160
+ ...((trigger === 'hover' || trigger.includes('hover')) && {
161
+ onMouseEnter: () => toggleVisible(true),
162
+ onMouseLeave: () => toggleVisible(false),
163
+ }),
164
+ })}
165
+ {typeof window !== 'undefined' &&
166
+ createPortal(
167
+ <Transition
168
+ in={_visible}
169
+ mountOnEnter
170
+ nodeRef={tooltipRef}
171
+ onEnter={onShow}
172
+ onExit={onHide}
173
+ timeout={{
174
+ enter: 0,
175
+ exit: tooltipRef.current
176
+ ? getTransitionDurationFromElement(tooltipRef.current) + 50
177
+ : 200,
178
+ }}
179
+ unmountOnExit
180
+ >
181
+ {(state) => (
182
+ <div
183
+ className={classNames(
184
+ 'tooltip',
185
+ 'bs-tooltip-auto',
186
+ {
187
+ fade: animation,
188
+ show: state === 'entered',
189
+ },
190
+ className,
191
+ )}
192
+ ref={forkedRef}
193
+ role="tooltip"
194
+ {...rest}
195
+ >
196
+ <div className="tooltip-arrow"></div>
197
+ <div className="tooltip-inner">{content}</div>
198
+ </div>
199
+ )}
200
+ </Transition>,
201
+ document.body,
202
+ )}
203
+ </>
204
+ )
205
+ },
206
+ )
190
207
 
191
208
  CTooltip.propTypes = {
192
209
  animation: PropTypes.bool,
@@ -1,5 +1,7 @@
1
+ import { useDebouncedCallback } from './useDebouncedCallback'
1
2
  import { useForkedRef } from './useForkedRef'
3
+ import { useIsVisible } from './useIsVisible'
2
4
  import { usePopper } from './usePopper'
3
5
  import { useStateWithCallback } from './useStateWithCallback'
4
6
 
5
- export { useForkedRef, usePopper, useStateWithCallback }
7
+ export { useDebouncedCallback, useForkedRef, useIsVisible, usePopper, useStateWithCallback }
@@ -0,0 +1,18 @@
1
+ import { useRef, useCallback, } from 'react'
2
+
3
+ export const useDebouncedCallback = <F extends Function>(callback: F, delay: number) => {
4
+ const timeout = useRef<ReturnType<typeof setTimeout>>()
5
+
6
+ return useCallback(
7
+ (...args: any[]) => {
8
+ const handler = () => {
9
+ clearTimeout(timeout.current)
10
+ callback(...args)
11
+ }
12
+
13
+ clearTimeout(timeout.current)
14
+ timeout.current = setTimeout(handler, delay)
15
+ },
16
+ [callback, delay],
17
+ )
18
+ }
@@ -0,0 +1,14 @@
1
+ import { RefObject, useEffect, useState } from 'react'
2
+
3
+ export const useIsVisible = (ref: RefObject<HTMLElement>) => {
4
+ const [isIntersecting, setIntersecting] = useState(false)
5
+
6
+ useEffect(() => {
7
+ const observer = new IntersectionObserver(([entry]) => setIntersecting(entry.isIntersecting))
8
+
9
+ ref.current && observer.observe(ref.current)
10
+ return () => observer.disconnect()
11
+ }, [])
12
+
13
+ return isIntersecting
14
+ }