@coreui/react 4.9.2 → 4.10.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.
@@ -0,0 +1,2 @@
1
+ declare const executeAfterTransition: (callback: () => void, transitionElement: HTMLElement, waitForTransition?: boolean) => void;
2
+ export default executeAfterTransition;
@@ -0,0 +1,2 @@
1
+ declare const getTransitionDurationFromElement: (element: HTMLElement) => number;
2
+ export default getTransitionDurationFromElement;
@@ -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.9.2",
3
+ "version": "4.10.1",
4
4
  "description": "UI Components Library for React.js",
5
5
  "keywords": [
6
6
  "react",
@@ -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/CBackdrop'
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
- role="dialog"
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 {...rest} ref={modalContentRef}>
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']),
@@ -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/CBackdrop'
6
+ import { CBackdrop } from '../backdrop'
7
7
  import { CConditionalPortal } from '../conditional-portal'
8
8
 
9
9
  import { useForkedRef } from '../../hooks'
@@ -1,13 +1,13 @@
1
- import React, { FC, HTMLAttributes, ReactNode, useRef, useEffect, useState } from 'react'
1
+ import React, { forwardRef, HTMLAttributes, ReactNode, useRef, useEffect, useState } from 'react'
2
2
  import { createPortal } from 'react-dom'
3
3
  import classNames from 'classnames'
4
4
  import PropTypes from 'prop-types'
5
5
  import { Transition } from 'react-transition-group'
6
6
 
7
- import { usePopper } from '../../hooks'
7
+ import { useForkedRef, 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
  /**
@@ -68,132 +68,141 @@ export interface CPopoverProps extends Omit<HTMLAttributes<HTMLDivElement>, 'tit
68
68
  visible?: boolean
69
69
  }
70
70
 
71
- export const CPopover: FC<CPopoverProps> = ({
72
- children,
73
- animation = true,
74
- className,
75
- content,
76
- delay = 0,
77
- fallbackPlacements = ['top', 'right', 'bottom', 'left'],
78
- offset = [0, 8],
79
- onHide,
80
- onShow,
81
- placement = 'top',
82
- title,
83
- trigger = 'click',
84
- visible,
85
- ...rest
86
- }) => {
87
- const popoverRef = useRef(null)
88
- const togglerRef = useRef(null)
89
- const { initPopper, destroyPopper } = usePopper()
90
- const [_visible, setVisible] = useState(visible)
71
+ export const CPopover = forwardRef<HTMLDivElement, CPopoverProps>(
72
+ (
73
+ {
74
+ children,
75
+ animation = true,
76
+ className,
77
+ content,
78
+ delay = 0,
79
+ fallbackPlacements = ['top', 'right', 'bottom', 'left'],
80
+ offset = [0, 8],
81
+ onHide,
82
+ onShow,
83
+ placement = 'top',
84
+ title,
85
+ trigger = 'click',
86
+ visible,
87
+ ...rest
88
+ },
89
+ ref,
90
+ ) => {
91
+ const popoverRef = useRef(null)
92
+ const togglerRef = useRef(null)
93
+ const forkedRef = useForkedRef(ref, popoverRef)
91
94
 
92
- const _delay = typeof delay === 'number' ? { show: delay, hide: delay } : delay
95
+ const { initPopper, destroyPopper } = usePopper()
96
+ const [_visible, setVisible] = useState(visible)
93
97
 
94
- const popperConfig = {
95
- modifiers: [
96
- {
97
- name: 'arrow',
98
- options: {
99
- element: '.popover-arrow',
98
+ const _delay = typeof delay === 'number' ? { show: delay, hide: delay } : delay
99
+
100
+ const popperConfig = {
101
+ modifiers: [
102
+ {
103
+ name: 'arrow',
104
+ options: {
105
+ element: '.popover-arrow',
106
+ },
100
107
  },
101
- },
102
- {
103
- name: 'flip',
104
- options: {
105
- fallbackPlacements: fallbackPlacements,
108
+ {
109
+ name: 'flip',
110
+ options: {
111
+ fallbackPlacements: fallbackPlacements,
112
+ },
106
113
  },
107
- },
108
- {
109
- name: 'offset',
110
- options: {
111
- offset: offset,
114
+ {
115
+ name: 'offset',
116
+ options: {
117
+ offset: offset,
118
+ },
112
119
  },
113
- },
114
- ],
115
- placement: getRTLPlacement(placement, togglerRef.current),
116
- }
120
+ ],
121
+ placement: getRTLPlacement(placement, togglerRef.current),
122
+ }
117
123
 
118
- useEffect(() => {
119
- setVisible(visible)
120
- }, [visible])
124
+ useEffect(() => {
125
+ setVisible(visible)
126
+ }, [visible])
121
127
 
122
- useEffect(() => {
123
- if (_visible && togglerRef.current && popoverRef.current) {
124
- initPopper(togglerRef.current, popoverRef.current, popperConfig)
125
- }
128
+ useEffect(() => {
129
+ if (_visible && togglerRef.current && popoverRef.current) {
130
+ initPopper(togglerRef.current, popoverRef.current, popperConfig)
131
+ }
126
132
 
127
- return () => {
128
- destroyPopper()
129
- }
130
- }, [_visible])
133
+ return () => {
134
+ destroyPopper()
135
+ }
136
+ }, [_visible])
131
137
 
132
- const toggleVisible = (visible: boolean) => {
133
- if (visible) {
134
- setTimeout(() => setVisible(true), _delay.show)
135
- return
136
- }
138
+ const toggleVisible = (visible: boolean) => {
139
+ if (visible) {
140
+ setTimeout(() => setVisible(true), _delay.show)
141
+ return
142
+ }
137
143
 
138
- setTimeout(() => setVisible(false), _delay.hide)
139
- }
144
+ setTimeout(() => setVisible(false), _delay.hide)
145
+ }
140
146
 
141
- return (
142
- <>
143
- {React.cloneElement(children as React.ReactElement<any>, {
144
- ref: togglerRef,
145
- ...((trigger === 'click' || trigger.includes('click')) && {
146
- onClick: () => toggleVisible(!_visible),
147
- }),
148
- ...((trigger === 'focus' || trigger.includes('focus')) && {
149
- onFocus: () => toggleVisible(true),
150
- onBlur: () => toggleVisible(false),
151
- }),
152
- ...((trigger === 'hover' || trigger.includes('hover')) && {
153
- onMouseEnter: () => toggleVisible(true),
154
- onMouseLeave: () => toggleVisible(false),
155
- }),
156
- })}
157
- {typeof window !== 'undefined' &&
158
- createPortal(
159
- <Transition
160
- in={_visible}
161
- mountOnEnter
162
- nodeRef={popoverRef}
163
- onEnter={onShow}
164
- onExit={onHide}
165
- timeout={{
166
- enter: 0,
167
- exit: 200,
168
- }}
169
- unmountOnExit
170
- >
171
- {(state) => (
172
- <div
173
- className={classNames(
174
- 'popover',
175
- 'bs-popover-auto',
176
- {
177
- fade: animation,
178
- show: state === 'entered',
179
- },
180
- className,
181
- )}
182
- ref={popoverRef}
183
- role="tooltip"
184
- {...rest}
185
- >
186
- <div className="popover-arrow"></div>
187
- <div className="popover-header">{title}</div>
188
- <div className="popover-body">{content}</div>
189
- </div>
190
- )}
191
- </Transition>,
192
- document.body,
193
- )}
194
- </>
195
- )
196
- }
147
+ return (
148
+ <>
149
+ {React.cloneElement(children as React.ReactElement<any>, {
150
+ ref: togglerRef,
151
+ ...((trigger === 'click' || trigger.includes('click')) && {
152
+ onClick: () => toggleVisible(!_visible),
153
+ }),
154
+ ...((trigger === 'focus' || trigger.includes('focus')) && {
155
+ onFocus: () => toggleVisible(true),
156
+ onBlur: () => toggleVisible(false),
157
+ }),
158
+ ...((trigger === 'hover' || trigger.includes('hover')) && {
159
+ onMouseEnter: () => toggleVisible(true),
160
+ onMouseLeave: () => toggleVisible(false),
161
+ }),
162
+ })}
163
+ {typeof window !== 'undefined' &&
164
+ createPortal(
165
+ <Transition
166
+ in={_visible}
167
+ mountOnEnter
168
+ nodeRef={popoverRef}
169
+ onEnter={onShow}
170
+ onExit={onHide}
171
+ timeout={{
172
+ enter: 0,
173
+ exit: popoverRef.current
174
+ ? getTransitionDurationFromElement(popoverRef.current) + 50
175
+ : 200,
176
+ }}
177
+ unmountOnExit
178
+ >
179
+ {(state) => (
180
+ <div
181
+ className={classNames(
182
+ 'popover',
183
+ 'bs-popover-auto',
184
+ {
185
+ fade: animation,
186
+ show: state === 'entered',
187
+ },
188
+ className,
189
+ )}
190
+ ref={forkedRef}
191
+ role="tooltip"
192
+ {...rest}
193
+ >
194
+ <div className="popover-arrow"></div>
195
+ <div className="popover-header">{title}</div>
196
+ <div className="popover-body">{content}</div>
197
+ </div>
198
+ )}
199
+ </Transition>,
200
+ document.body,
201
+ )}
202
+ </>
203
+ )
204
+ },
205
+ )
197
206
 
198
207
  CPopover.propTypes = {
199
208
  animation: PropTypes.bool,
@@ -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/CBackdrop'
6
+ import { CBackdrop } from '../backdrop'
7
7
 
8
8
  import { isInViewport } from '../../utils'
9
9
  import { useForkedRef } from '../../hooks'