-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'develop' into focus-trap-hook
- Loading branch information
Showing
24 changed files
with
951 additions
and
191 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
--- | ||
title: AnchoredOverlay | ||
description: A component that displays an anchored layered element relative to a target element. | ||
source: https://github.com/dequelabs/cauldron/tree/develop/packages/react/src/components/AnchoredOverlay/index.tsx | ||
--- | ||
|
||
import { useRef, useState } from 'react' | ||
import { Select, Button, AnchoredOverlay } from '@deque/cauldron-react' | ||
export const placements = [ | ||
'top', | ||
'top-start', | ||
'top-end', | ||
'right', | ||
'right-start', | ||
'right-end', | ||
'bottom', | ||
'bottom-start', | ||
'bottom-end', | ||
'left', | ||
'left-start', | ||
'left-end', | ||
'auto', | ||
'auto-start', | ||
'auto-end' | ||
] | ||
|
||
```jsx | ||
import { AnchoredOverlay } from '@deque/cauldron-react' | ||
``` | ||
|
||
Under the hood, `AnchoredOverlay` uses [floating-ui](https://floating-ui.com/) to dynamically position an overlay element relative to a target element. It is intentionally un-styled to be composed with other components, such as [Tooltip]('./Tooltip'), [Popover](./Popover), or via more complex overlay components. | ||
|
||
<Note> | ||
`AnchoredOverlay` is a positioning component and does not include built-in accessibility features like ARIA attributes, focus management, or keyboard interactions that would be needed for components like tooltips, dialogs, or popovers. When using `AnchoredOverlay`, you'll need to implement these accessibility patterns yourself based on your specific use case. | ||
</Note> | ||
|
||
## Examples | ||
|
||
### Placement | ||
|
||
By default, initial placement is set to `auto` when it is not set via props. However the placement can [dynamically change](https://floating-ui.com/docs/autoplacement) when using `auto` or [flip](https://floating-ui.com/docs/flip) when using positional placement. | ||
|
||
If there are presentation elements that are dependent on the position of the `AnchoredOverlay`, you should use `onPlacementChange` to keep these presentation elements in sync with any updated placements. | ||
|
||
```jsx example | ||
function AnchoredOverlayExample() { | ||
const [placement, setPlacement] = useState('top') | ||
const [open, setOpen] = useState(false) | ||
const targetRef = useRef() | ||
const handlePlacementChange = ({ target }) => setPlacement(target.value); | ||
const toggleOpen = () => setOpen(!open) | ||
const handleClose = () => setOpen(false) | ||
|
||
return ( | ||
<> | ||
<Select | ||
label="Placement" | ||
options={placements.map(placement => ({ value: placement }))} | ||
onChange={handlePlacementChange} | ||
/> | ||
<Button | ||
ref={targetRef} | ||
onFocus={toggleOpen} | ||
onBlur={handleClose} | ||
aria-describedby="anchored-overlay" | ||
> | ||
Anchor Element | ||
</Button> | ||
<AnchoredOverlay | ||
id="anchored-overlay" | ||
target={targetRef} | ||
open={open} | ||
placement={placement} | ||
onOpenChange={openState => setOpen(openState)} | ||
style={{ | ||
padding: 'var(--space-small)', | ||
backgroundColor: 'var(--panel-background-color)', | ||
display: open ? 'block' : 'none' | ||
}} | ||
> | ||
Anchored Overlay Element with placement {placement} | ||
</AnchoredOverlay> | ||
</> | ||
) | ||
} | ||
``` | ||
|
||
### Offset | ||
|
||
Optionally, an `offset` value can be set which will offset the aligning edge of the overlay element relative to its anchor. | ||
|
||
```jsx example | ||
function AnchoredOverlayWithOffsetExample() { | ||
const [placement, setPlacement] = useState('top') | ||
const [open, setOpen] = useState(false) | ||
const targetRef = useRef() | ||
const handlePlacementChange = ({ target }) => setPlacement(target.value); | ||
const toggleOpen = () => setOpen(!open) | ||
const handleClose = () => setOpen(false) | ||
|
||
return ( | ||
<> | ||
<Select | ||
label="Placement" | ||
options={placements.map(placement => ({ value: placement }))} | ||
onChange={handlePlacementChange} | ||
/> | ||
<Button | ||
ref={targetRef} | ||
onFocus={toggleOpen} | ||
onBlur={handleClose} | ||
aria-describedby="anchored-overlay-offset" | ||
> | ||
Anchor Element | ||
</Button> | ||
<AnchoredOverlay | ||
id="anchored-overlay-offset" | ||
target={targetRef} | ||
open={open} | ||
placement={placement} | ||
onOpenChange={openState => setOpen(openState)} | ||
offset={20} | ||
style={{ | ||
padding: 'var(--space-small)', | ||
backgroundColor: 'var(--panel-background-color)', | ||
display: open ? 'block' : 'none' | ||
}} | ||
> | ||
Anchored Overlay Element with offset placement {placement} | ||
</AnchoredOverlay> | ||
</> | ||
) | ||
} | ||
``` | ||
|
||
## Props | ||
|
||
<ComponentProps | ||
children={true} | ||
className={true} | ||
refType="HTMLElement" | ||
props={[ | ||
{ | ||
name: 'target', | ||
type: ['HTMLElement', 'React.MutableRefObject<HTMLElement>', 'React.RefObject<HTMLElement>'], | ||
required: true, | ||
description: 'A target element or ref to attach the overlay anchor element.' | ||
}, | ||
{ | ||
name: 'placement', | ||
type: 'string', | ||
defaultValue: 'auto', | ||
description: 'Positional placement value to anchor the overlay element relative to its anchored target.' | ||
}, | ||
{ | ||
name: 'open', | ||
type: 'boolean', | ||
defaultValue: 'false', | ||
description: 'Determines if the overlay anchor is currently visible.' | ||
}, | ||
{ | ||
name: 'onOpenChange', | ||
type: '(open: boolean) => void', | ||
description: 'A callback function that is called when the overlay state changes.' | ||
}, | ||
{ | ||
name: 'onPlacementChange', | ||
type: '(placement: Placement) => void', | ||
description: 'A callback function that is called when the placement of the overlay changes.' | ||
}, | ||
{ | ||
name: 'offset', | ||
type: 'number', | ||
description: 'An optional offset number to position the anchor element from its anchored target.' | ||
}, | ||
{ | ||
name: 'as', | ||
type: 'React.ElementType', | ||
defaultValue: 'div', | ||
description: 'The element type to render as.' | ||
} | ||
]} | ||
/> | ||
|
||
## Related Components | ||
|
||
- [Tooltip](./Tooltip) | ||
- [Popover](./Popover) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.