Skip to content

Commit a3d77ab

Browse files
ryo-manbayihuiliaosnowystingerreidbarber
authored
Add directory support for FileTrigger (#5444)
* Add directory support for FileTrigger * docs: Added description of UNSAFE_directory prop * refac: Remove unsafe prefix * Add story * Update FileTrigger.mdx Updated section title to match formatting of others --------- Co-authored-by: Yihui Liao <44729383+yihuiliao@users.noreply.github.com> Co-authored-by: Rob Snow <rsnow@adobe.com> Co-authored-by: Reid Barber <reid@reidbarber.com>
1 parent efaf9ed commit a3d77ab

File tree

4 files changed

+44
-4
lines changed

4 files changed

+44
-4
lines changed

packages/react-aria-components/docs/FileTrigger.mdx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,18 @@ A file trigger can accept multiple files by passsing the `allowsMultiple` proper
120120
</FileTrigger>
121121
```
122122

123+
## Directory selection
124+
125+
To enable selecting directories instead of files, use the `directory` property.
126+
127+
This reflects the [webkitdirectory](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/webkitdirectory) HTML attribute and allows users to select directories and their contents.
128+
129+
```tsx example
130+
<FileTrigger directory>
131+
<Button>Select a directory</Button>
132+
</FileTrigger>
133+
```
134+
123135
## Media capture
124136

125137
To specify the media capture mechanism to capture media on the spot, pass `user` for the user-facing camera or `environment` for the outward-facing camera via the `defaultCamera` prop.

packages/react-aria-components/src/FileTrigger.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,21 @@ export interface FileTriggerProps {
3535
/**
3636
* The children of the component.
3737
*/
38-
children?: ReactNode
38+
children?: ReactNode,
39+
/**
40+
* Enables the selection of directories instead of individual files.
41+
*/
42+
directory?: boolean
3943
}
4044

4145
function FileTrigger(props: FileTriggerProps, ref: ForwardedRef<HTMLInputElement>) {
42-
let {onSelect, acceptedFileTypes, allowsMultiple, defaultCamera, children, ...rest} = props;
46+
let {onSelect, acceptedFileTypes, allowsMultiple, defaultCamera, children, directory, ...rest} = props;
4347
let inputRef = useObjectRef(ref);
4448
let domProps = filterDOMProps(rest);
4549

4650
return (
4751
<>
48-
<PressResponder
52+
<PressResponder
4953
onPress={() => {
5054
if (inputRef.current.value) {
5155
inputRef.current.value = '';
@@ -62,7 +66,9 @@ function FileTrigger(props: FileTriggerProps, ref: ForwardedRef<HTMLInputElement
6266
accept={acceptedFileTypes?.toString()}
6367
onChange={(e) => onSelect?.(e.target.files)}
6468
capture={defaultCamera}
65-
multiple={allowsMultiple} />
69+
multiple={allowsMultiple}
70+
// @ts-expect-error
71+
webkitdirectory={directory ? '' : undefined} />
6672
</>
6773
);
6874
}

packages/react-aria-components/stories/index.stories.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1166,6 +1166,16 @@ export const FileTriggerButton = (props) => (
11661166
</FileTrigger>
11671167
);
11681168

1169+
export const FileTriggerDirectories = (props) => (
1170+
<FileTrigger
1171+
directory
1172+
onSelect={action('onSelect')}
1173+
data-testid="filetrigger-example"
1174+
{...props} >
1175+
<Button>Upload</Button>
1176+
</FileTrigger>
1177+
);
1178+
11691179
export const FileTriggerLinkAllowsMultiple = (props) => (
11701180
<FileTrigger
11711181
{...props}

packages/react-aria-components/test/FileTrigger.test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,16 @@ describe('FileTrigger', () => {
8888
let input = getByTestId('foo');
8989
expect(ref.current).toBe(input);
9090
});
91+
92+
it('should allow directory uploads when directory is true', () => {
93+
render(
94+
<FileTrigger directory>
95+
<Button>Upload Directory</Button>
96+
</FileTrigger>
97+
);
98+
99+
let input = document.querySelector('input[type="file"]');
100+
expect(input).toHaveAttribute('webkitdirectory');
101+
});
102+
91103
});

0 commit comments

Comments
 (0)