Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions packages/react-aria-components/docs/DropZone.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,11 @@ function Example() {
}
```

If a `DropZone` is rendered in a positioned scroll container, focusing the visually hidden drop
button may cause the container to scroll. The `dropButtonStyle` prop can be used to adjust the
position of this internal button wrapper, for example `dropButtonStyle={{position: 'fixed', top: 0,
left: 0}}`.

## Visual feedback

A dropzone displays visual feedback to the user when a drag hovers over the drop target by passing the `getDropOperation` function. If a drop target only supports data of specific types (e.g. images, videos, text, etc.), then it should implement the `getDropOperation` prop and return `cancel` for types that aren't supported. This will prevent visual feedback indicating that the drop target accepts the dragged data when this is not true. [Read more about getDropOperation.](https://react-spectrum.adobe.com/react-aria/useDrop.html#getdropoperation)
Expand Down
10 changes: 8 additions & 2 deletions packages/react-aria-components/src/DropZone.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {getEventTarget, nodeContains} from 'react-aria/private/utils/shadowdom/D
import intlMessages from '../intl/*.json';
import {isFocusable} from 'react-aria/private/utils/isFocusable';
import {mergeProps} from 'react-aria/mergeProps';
import React, {createContext, ForwardedRef, forwardRef, useRef} from 'react';
import React, {createContext, CSSProperties, ForwardedRef, forwardRef, useRef} from 'react';
import {TextContext} from './Text';
import {useButton} from 'react-aria/useButton';
import {useClipboard} from 'react-aria/useClipboard';
Expand Down Expand Up @@ -87,6 +87,11 @@ export interface DropZoneProps
* @default 'react-aria-DropZone'
*/
className?: ClassNameOrFunction<DropZoneRenderProps>;
/**
* The inline style for the visually hidden drop button used for keyboard and screen reader drop
* interactions.
*/
dropButtonStyle?: CSSProperties;
}

export const DropZoneContext = createContext<ContextValue<DropZoneProps, HTMLDivElement>>(null);
Expand All @@ -100,6 +105,7 @@ export const DropZone = forwardRef(function DropZone(
) {
let {isDisabled = false} = props;
[props, ref] = useContextProps(props, ref, DropZoneContext);
let {dropButtonStyle} = props;
let dropzoneRef = useObjectRef(ref);
let buttonRef = useRef<HTMLButtonElement>(null);
let {dropProps, dropButtonProps, isDropTarget} = useDrop({
Expand Down Expand Up @@ -162,7 +168,7 @@ export const DropZone = forwardRef(function DropZone(
data-focus-visible={isFocusVisible || undefined}
data-drop-target={isDropTarget || undefined}
data-disabled={isDisabled || undefined}>
<VisuallyHidden>
<VisuallyHidden style={dropButtonStyle}>
<button
{...mergeProps(buttonProps, focusProps, clipboardProps, labelProps)}
ref={buttonRef}
Expand Down
12 changes: 12 additions & 0 deletions packages/react-aria-components/test/DropZone.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,18 @@ describe('DropZone', () => {
await user.click(button);
expect(document.activeElement).toBe(button);
});

it('should support custom styles on the visually hidden drop button wrapper', () => {
let {getByRole} = render(
<DropZone dropButtonStyle={{position: 'fixed', top: 0, left: 0}} />
);

expect(getByRole('button').parentElement).toHaveStyle({
position: 'fixed',
top: '0px',
left: '0px'
});
});
});

describe('via keyboard', function () {
Expand Down