Skip to content

[pull] main from coreui:main #19

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 63 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
746377d
docs: improve internal linking
mrholek Dec 29, 2024
72ec01f
feat(CSidebar): add 'as' prop to CSidebar
Dec 30, 2024
caa1007
Merge pull request #421 from matt-jb/add-as-prop-to-sidebar
mrholek Dec 31, 2024
8d2d46b
docs: update `@coreui/react` library imports
mrholek Jan 2, 2025
b14949c
Merge pull request #422 from mrholek/main
mrholek Jan 2, 2025
c54a0ab
chore: update dependencies and devDependencies
mrholek Jan 2, 2025
36814f6
chore: update dependencies and devDependencies
mrholek Jan 2, 2025
c2d2e7d
fix: lock the version of `@types/prop-types` to prevent `children` pr…
mrholek Jan 2, 2025
b1ede20
tests: update tests
mrholek Jan 3, 2025
e457ffe
fix(CModal): disable emitting the `onClose` event twice
mrholek Jan 3, 2025
454be70
Merge pull request #423 from mrholek/main
mrholek Jan 3, 2025
cdb4712
chore: clean-up
mrholek Jan 3, 2025
3f03770
refactor(useColorModes): replace `window` with `globalThis`
mrholek Jan 3, 2025
4bfeee2
Merge pull request #424 from mrholek/main
mrholek Jan 3, 2025
d5b9a4d
chore: clean-up
mrholek Jan 3, 2025
acceb01
build: update ESLint to v9.x
mrholek Jan 8, 2025
3a57192
build: migrate `.prettierrc.js` to `eslint.config.mjs`
mrholek Jan 8, 2025
cb1ef1f
Merge pull request #429 from mrholek/main
mrholek Jan 8, 2025
7c91c99
feat(CDropdown, CPopover, CTooltip): allow passing custom popper conf…
mrholek Jan 28, 2025
161bbd1
fix(CAccordion): add a missing ID attribute to the accordion collapse…
mrholek Jan 28, 2025
35276cb
docs: update API documentation
mrholek Feb 6, 2025
58ace1b
fix(useColorModes): replace `globalThis` with `window` for SSR support
mrholek Feb 6, 2025
d2ca48d
chore: update dependencies and devDependencies
mrholek Feb 6, 2025
92609b2
refactor(CDropdown): remove `aria-hidden` to improve component access…
mrholek Feb 6, 2025
9f24e2f
chore: update the current year to 2025
mrholek Feb 7, 2025
be8ae22
release: v5.5.0
mrholek Feb 7, 2025
ef0e750
docs: update content
mrholek Feb 16, 2025
e53f0fe
chore: update dependencies and devDependencies
mrholek Feb 16, 2025
9d74c9c
refactor: migrate to Sass modules
mrholek Feb 16, 2025
d260367
docs: remove double # in links
mrholek Apr 16, 2025
bb614f2
docs: update link to features
mrholek Apr 16, 2025
25e8ff4
fix(CDropdown): incorrect menu positioning when the toggler is re-ren…
mrholek Apr 29, 2025
46c4007
chore: update dependencies and devDependencies
mrholek Apr 29, 2025
57b0f90
tests: update tests
mrholek Apr 29, 2025
f451d62
refactor: improve typings
mrholek Apr 29, 2025
e0f155f
refactor(CTabs): fully implement a controlled/uncontrolled pattern
mrholek Apr 29, 2025
d8fd24a
chore: clean-up
mrholek Apr 29, 2025
adc116d
refactor(CAccordion): move the context outside the component
mrholek Apr 30, 2025
c719c6e
refactor(CToast): move the context outside the component
mrholek Apr 30, 2025
b6dc072
refactor(CSidebarNav): move the context outside the component
mrholek Apr 30, 2025
ad0ef5e
refactor(CProgress): move the context outside the component
mrholek Apr 30, 2025
de2290b
refactor(CCarousel): move the context outside the component
mrholek Apr 30, 2025
56e615d
refactor(CModal): move the context outside the component
mrholek Apr 30, 2025
08dde3d
refactor(CModal): move the context outside the component
mrholek Apr 30, 2025
cb15c39
docs: upadte API documentation
mrholek Apr 30, 2025
e1ab484
docs: add "use with Bootstrap"
mrholek May 1, 2025
4f128a0
docs: update bootstrap styles
mrholek May 1, 2025
f80bc4a
release: v5.6.0
mrholek May 1, 2025
fd9f2a8
docs: add withPrefix to urls
mrholek May 15, 2025
07027d1
docs: update links to API
mrholek May 15, 2025
0b7cbd8
feat(CButton): add support for unthemed outline and ghost buttons
mrholek May 19, 2025
1ad29c6
feat(CNav): add enclosed variants
mrholek May 19, 2025
bee8617
feat(CTabs): add enclosed variants
mrholek May 19, 2025
3b37bd9
chore: update dependencies and devDependencies
mrholek May 19, 2025
932d00f
release: v5.7.0
mrholek May 19, 2025
c727396
refactor(CButton): improve variants handling
mrholek May 29, 2025
38fc15a
docs: update content
mrholek Jun 8, 2025
90d8100
refactor: update tabs component
mrholek Jun 12, 2025
a2d3eb5
fix(CDropdown): prevent unnecessary re-rendering
mrholek Jul 6, 2025
5688b61
refactor(CDropdown): optimize menu visibility toggling
mrholek Jul 12, 2025
a6d3bb5
chore: update dependencies and devDependencies
mrholek Jul 12, 2025
1969a64
release: v5.7.1
mrholek Jul 13, 2025
44a6c98
docs: update schema markup
mrholek Jul 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat(CDropdown, CPopover, CTooltip): allow passing custom popper conf…
…iguration
  • Loading branch information
mrholek committed Jan 28, 2025
commit 7c91c99df3c4e48be55e342489de353bb4f71cc7
132 changes: 106 additions & 26 deletions packages/coreui-react/src/components/dropdown/CDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import React, {
} from 'react'
import PropTypes from 'prop-types'
import classNames from 'classnames'
import type { Options } from '@popperjs/core'

import { PolymorphicRefForwardingComponent } from '../../helpers'
import { useForkedRef, usePopper } from '../../hooks'
Expand All @@ -22,77 +23,148 @@ import { getPlacement } from './utils'

export interface CDropdownProps extends HTMLAttributes<HTMLDivElement | HTMLLIElement> {
/**
* Set aligment of dropdown menu.
* Specifies the alignment of the React Dropdown Menu within this React Dropdown.
*
* @example
* // Align dropdown menu to the end on large devices, otherwise start
* <CDropdown alignment={{ lg: 'end', xs: 'start' }}>
* <CDropdownToggle>Toggle dropdown</CDropdownToggle>
* <CDropdownMenu>
* <CDropdownItem>Action</CDropdownItem>
* <CDropdownItem>Another Action</CDropdownItem>
* </CDropdownMenu>
* </CDropdown>
*
* @type 'start' | 'end' | { xs: 'start' | 'end' } | { sm: 'start' | 'end' } | { md: 'start' | 'end' } | { lg: 'start' | 'end' } | { xl: 'start' | 'end'} | { xxl: 'start' | 'end'}
*/
alignment?: Alignments

/**
* Component used for the root node. Either a string to use a HTML element or a component.
* Determines the root node component (native HTML element or a custom React component) for the React Dropdown.
*/
as?: ElementType

/**
* Configure the auto close behavior of the dropdown:
* - `true` - the dropdown will be closed by clicking outside or inside the dropdown menu.
* - `false` - the dropdown will be closed by clicking the toggle button and manually calling hide or toggle method. (Also will not be closed by pressing esc key)
* - `'inside'` - the dropdown will be closed (only) by clicking inside the dropdown menu.
* - `'outside'` - the dropdown will be closed (only) by clicking outside the dropdown menu.
* Configures automatic closing behavior for the React Dropdown:
* - `true` - Close on clicks inside or outside of the React Dropdown Menu.
* - `false` - Disable auto-close; manually call `hide` or `toggle` (also not closed by `Escape`).
* - `'inside'` - Close only when clicking inside the React Dropdown Menu.
* - `'outside'` - Close only when clicking outside the React Dropdown Menu.
*
* @example
* // Close only when user clicks outside of the menu
* <CDropdown autoClose="outside" />
*/
autoClose?: 'inside' | 'outside' | boolean

/**
* A string of all className you want applied to the base component.
* Adds custom classes to the React Dropdown root element.
*/
className?: string

/**
* 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`.
* Appends the React Dropdown Menu to a specific element. You can pass an HTML element or a function returning an element. Defaults to `document.body`.
*
* @example
* // Append the menu to a custom container
* const myContainer = document.getElementById('my-container')
*
* <CDropdown container={myContainer} />
*
* @since 4.11.0
*/
container?: DocumentFragment | Element | (() => DocumentFragment | Element | null) | null

/**
* Sets a darker color scheme to match a dark navbar.
* Applies a darker color scheme to the React Dropdown Menu, often used within dark navbars.
*/
dark?: boolean

/**
* Sets a specified direction and ___location of the dropdown menu.
* Specifies the direction of the React Dropdown.
*/
direction?: 'center' | 'dropup' | 'dropup-center' | 'dropend' | 'dropstart'

/**
* Offset of the dropdown menu relative to its target.
* Defines x and y offsets ([x, y]) for the React Dropdown Menu relative to its target.
*
* @example
* // Offset the menu 10px in X and 5px in Y direction
* <CDropdown offset={[10, 5]}>
* ...
* </CDropdown>
*/
offset?: [number, number]

/**
* Callback fired when the component requests to be hidden.
* Callback fired right before the React Dropdown becomes hidden.
*
* @since 4.9.0
*/
onHide?: () => void

/**
* Callback fired when the component requests to be shown.
* Callback fired immediately after the React Dropdown is displayed.
*/
onShow?: () => void

/**
* Describes the placement of your component after Popper.js has applied all the modifiers that may have flipped or altered the originally provided placement property.
* Determines the placement of the React Dropdown Menu after Popper.js modifiers.
*
* @type 'auto' | 'top-end' | 'top' | 'top-start' | 'bottom-end' | 'bottom' | 'bottom-start' | 'right-start' | 'right' | 'right-end' | 'left-start' | 'left' | 'left-end'
* @type 'auto' | 'auto-start' | 'auto-end' | 'top-end' | 'top' | 'top-start' | 'bottom-end' | 'bottom' | 'bottom-start' | 'right-start' | 'right' | 'right-end' | 'left-start' | 'left' | 'left-end'
*/
placement?: Placements

/**
* If you want to disable dynamic positioning set this property to `true`.
* Enables or disables dynamic positioning via Popper.js for the React Dropdown Menu.
*/
popper?: boolean

/**
* Provides a custom Popper.js configuration or a function that returns a modified Popper.js configuration for advanced positioning of the React Dropdown Menu. [Read more](https://popper.js.org/docs/v2/constructors/#options)
*
* @example
* // Providing a custom popper config
* <CDropdown
* popperConfig={{
* modifiers: [
* {
* name: 'flip',
* options: { fallbackPlacements: ['bottom', 'top'] },
* },
* ],
* }}
* >...</CDropdown>
*
* @since 5.5.0
*/
popperConfig?: Partial<Options> | ((defaultPopperConfig: Partial<Options>) => Partial<Options>)

/**
* Generates dropdown menu using createPortal.
* Renders the React Dropdown Menu using a React Portal, allowing it to escape the DOM hierarchy for improved positioning.
*
* @since 4.8.0
*/
portal?: boolean

/**
* Set the dropdown variant to an btn-group, dropdown, input-group, and nav-item.
* Defines the visual variant of the React Dropdown
*/
variant?: 'btn-group' | 'dropdown' | 'input-group' | 'nav-item'

/**
* Toggle the visibility of dropdown menu component.
* Controls the visibility of the React Dropdown Menu:
* - `true` - Visible
* - `false` - Hidden
*
* @example
* // Programmatically manage the dropdown visibility
* const [visible, setVisible] = useState(false)
*
* <CDropdown visible={visible}>
* ...
* </CDropdown>
*
*/
visible?: boolean
}
Expand Down Expand Up @@ -126,12 +198,13 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
onShow,
placement = 'bottom-start',
popper = true,
popperConfig,
portal = false,
variant = 'btn-group',
visible = false,
...rest
},
ref,
ref
) => {
const dropdownRef = useRef<HTMLDivElement>(null)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down Expand Up @@ -161,7 +234,7 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
setVisible,
}

const popperConfig = {
const defaultPopperConfig = {
modifiers: [
{
name: 'offset',
Expand All @@ -173,14 +246,20 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
placement: getPlacement(placement, direction, alignment, isRTL(dropdownMenuRef.current)),
}

const computedPopperConfig: Partial<Options> = {
...defaultPopperConfig,
...(typeof popperConfig === 'function' ? popperConfig(defaultPopperConfig) : popperConfig),
}

useEffect(() => {
setVisible(visible)
}, [visible])

useEffect(() => {
if (_visible && dropdownToggleRef.current && dropdownMenuRef.current) {
dropdownToggleRef.current.focus()
popper && initPopper(dropdownToggleRef.current, dropdownMenuRef.current, popperConfig)
popper &&
initPopper(dropdownToggleRef.current, dropdownMenuRef.current, computedPopperConfig)
window.addEventListener('mouseup', handleMouseUp)
window.addEventListener('keyup', handleKeyup)
dropdownToggleRef.current.addEventListener('keydown', handleKeydown)
Expand Down Expand Up @@ -209,7 +288,7 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
event.preventDefault()
const target = event.target as HTMLElement
const items: HTMLElement[] = Array.from(
dropdownMenuRef.current.querySelectorAll('.dropdown-item:not(.disabled):not(:disabled)'),
dropdownMenuRef.current.querySelectorAll('.dropdown-item:not(.disabled):not(:disabled)')
)
getNextActiveElement(items, target, event.key === 'ArrowDown', true).focus()
}
Expand Down Expand Up @@ -258,7 +337,7 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
[`${direction}`]:
direction && direction !== 'center' && direction !== 'dropup-center',
},
className,
className
)}
{...rest}
ref={forkedRef}
Expand All @@ -268,7 +347,7 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
)}
</CDropdownContext.Provider>
)
},
}
)

const alignmentDirection = PropTypes.oneOf<Directions>(['start', 'end'])
Expand Down Expand Up @@ -297,6 +376,7 @@ CDropdown.propTypes = {
onShow: PropTypes.func,
placement: placementPropType,
popper: PropTypes.bool,
popperConfig: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
portal: PropTypes.bool,
variant: PropTypes.oneOf(['btn-group', 'dropdown', 'input-group', 'nav-item']),
visible: PropTypes.bool,
Expand Down
Loading