Skip to content
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

feat: Make file dropzone public #2973

Closed
wants to merge 8 commits into from
Closed
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
120 changes: 120 additions & 0 deletions pages/file-dropzone/container.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useContext, useState } from 'react';

import { Box, Button, Checkbox, Container, Header, SpaceBetween, Table } from '~components';
import FileDropzone, { useFilesDragging } from '~components/file-dropzone';

import AppContext, { AppContextType } from '../app/app-context';

type DemoContext = React.Context<
AppContextType<{
onlyVisibleOnDrag: boolean;
}>
>;

export default function FileDropzoneContainer() {
const [files, setFiles] = useState<File[]>([]);

const [selectedItems, setSelectedItems] = useState<any>([]);
const { urlParams, setUrlParams } = useContext(AppContext as DemoContext);
const { onlyVisibleOnDrag } = urlParams;

const handleFilesChange = (newFiles: File[]) => {
const newValue = [...files, ...newFiles];
setFiles(newValue);
};

const removeFiles = () => {
const newValue = files.filter(file => !selectedItems.map((item: any) => item.name).includes(file.name));
setFiles(newValue);

setSelectedItems([]);
};

const { areFilesDragging } = useFilesDragging();

return (
<Box margin="xl">
<SpaceBetween size="xl">
<Header variant="h1">File dropzone: in container</Header>
<Checkbox checked={onlyVisibleOnDrag} onChange={() => setUrlParams({ onlyVisibleOnDrag: !onlyVisibleOnDrag })}>
Only visible on file drag
</Checkbox>
<Container
header={
<Header
actions={
<Button disabled={selectedItems.length === 0} onClick={removeFiles}>
{selectedItems.length > 1 ? 'Remove files' : 'Remove file'}
</Button>
}
>
Attachments
</Header>
}
>
<SpaceBetween size="l">
{/* {!onlyVisibleOnDrag && (
<FileDropzone onChange={(event: any) => handleFilesChange(event.detail.value)}>
<Box fontWeight="bold" color="inherit">
Drop files here
</Box>
</FileDropzone>
)} */}
{areFilesDragging && onlyVisibleOnDrag ? (
<FileDropzone onChange={(event: any) => handleFilesChange(event.detail.value)}>
<Box fontWeight="bold" color="inherit">
Drop files here
</Box>
</FileDropzone>
) : (
<Table
variant="embedded"
empty={'No files uploaded'}
selectionType={'multi'}
onSelectionChange={({ detail }) => setSelectedItems(detail.selectedItems)}
selectedItems={selectedItems}
trackBy="name"
columnDefinitions={[
{
id: 'file-name',
header: 'File name',
cell: item => item.name || '-',
sortingField: 'name',
isRowHeader: true,
},
{
id: 'file-type',
header: 'File type',
cell: item => item.type || '-',
sortingField: 'alt',
},
{
id: 'file-size',
header: 'File size',
cell: item => item.size || '-',
},
]}
enableKeyboardNavigation={true}
ariaLabels={{
selectionGroupLabel: 'group label',
allItemsSelectionLabel: ({ selectedItems }) => `${selectedItems.length} item selected`,
itemSelectionLabel: ({ selectedItems }, item) =>
`${item.name} is ${selectedItems.indexOf(item) < 0 ? 'not ' : ''}selected`,
}}
items={files.map(file => ({
name: file.name,
type: file.type,
size: file.size,
}))}
loadingText="Loading resources"
sortingDisabled={true}
/>
)}
</SpaceBetween>
</Container>
</SpaceBetween>
</Box>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7361,6 +7361,59 @@ use the \`id\` attribute, consider setting it on a parent element instead.",
}
`;

exports[`Documenter definition for file-dropzone matches the snapshot: file-dropzone 1`] = `
{
"events": [
{
"cancelable": false,
"description": "Called when the user selects new file(s), or removes a file.
The event \`detail\` contains the current value of the component.",
"detailInlineType": {
"name": "FileDropzoneProps.ChangeDetail",
"properties": [
{
"name": "value",
"optional": false,
"type": "Array<File>",
},
],
"type": "object",
},
"detailType": "FileDropzoneProps.ChangeDetail",
"name": "onChange",
},
],
"functions": [],
"name": "FileDropzone",
"properties": [
{
"deprecatedTag": "Custom CSS is not supported. For testing and other use cases, use [data attributes](https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes).",
"description": "Adds the specified classes to the root element of the component.",
"name": "className",
"optional": true,
"type": "string",
},
{
"deprecatedTag": "The usage of the \`id\` attribute is reserved for internal use cases. For testing and other use cases,
use [data attributes](https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes). If you must
use the \`id\` attribute, consider setting it on a parent element instead.",
"description": "Adds the specified ID to the root element of the component.",
"name": "id",
"optional": true,
"type": "string",
},
],
"regions": [
{
"description": "Children of the Dropzone.",
"isDefault": true,
"name": "children",
},
],
"releaseStatus": "stable",
}
`;

exports[`Documenter definition for file-upload matches the snapshot: file-upload 1`] = `
{
"events": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,10 @@ exports[`test-utils selectors 1`] = `
"awsui_icon-container_gwq0h",
"awsui_root_gwq0h",
],
"file-dropzone": [
"awsui_content_ptw8i",
"awsui_root_ptw8i",
],
"file-upload": [
"awsui_hints_1ubbm",
"awsui_root_1ubbm",
Expand Down Expand Up @@ -327,7 +331,6 @@ exports[`test-utils selectors 1`] = `
"awsui_button-trigger_18eso",
"awsui_button_m5h9f",
"awsui_chart-filter_1px7g",
"awsui_content_1tk3k",
"awsui_control_1wepg",
"awsui_description_1p2cx",
"awsui_description_1wepg",
Expand Down Expand Up @@ -364,7 +367,6 @@ exports[`test-utils selectors 1`] = `
"awsui_root_1kjc7",
"awsui_root_1qprf",
"awsui_root_1t44z",
"awsui_root_1tk3k",
"awsui_root_9f1dn",
"awsui_root_qwoo0",
"awsui_root_vrgzu",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ export { ElementWrapper };
export { ExpandableSectionWrapper };


import FileDropzoneWrapper from './file-dropzone';
export { FileDropzoneWrapper };


import FileUploadWrapper from './file-upload';
export { FileUploadWrapper };

Expand Down Expand Up @@ -338,6 +342,7 @@ findDatePicker(selector?: string): DatePickerWrapper | null;
findDateRangePicker(selector?: string): DateRangePickerWrapper | null;
findDrawer(selector?: string): DrawerWrapper | null;
findExpandableSection(selector?: string): ExpandableSectionWrapper | null;
findFileDropzone(selector?: string): FileDropzoneWrapper | null;
findFileUpload(selector?: string): FileUploadWrapper | null;
findFlashbar(selector?: string): FlashbarWrapper | null;
findForm(selector?: string): FormWrapper | null;
Expand Down Expand Up @@ -556,6 +561,12 @@ ElementWrapper.prototype.findExpandableSection = function(selector) {
// https://github.com/microsoft/TypeScript/issues/29132
return (this as any).findComponent(selector ? appendSelector(selector, rootSelector) : rootSelector, ExpandableSectionWrapper);
};
ElementWrapper.prototype.findFileDropzone = function(selector) {
const rootSelector = \`.\${FileDropzoneWrapper.rootSelector}\`;
// casting to 'any' is needed to avoid this issue with generics
// https://github.com/microsoft/TypeScript/issues/29132
return (this as any).findComponent(selector ? appendSelector(selector, rootSelector) : rootSelector, FileDropzoneWrapper);
};
ElementWrapper.prototype.findFileUpload = function(selector) {
const rootSelector = \`.\${FileUploadWrapper.rootSelector}\`;
// casting to 'any' is needed to avoid this issue with generics
Expand Down Expand Up @@ -964,6 +975,10 @@ export { ElementWrapper };
export { ExpandableSectionWrapper };


import FileDropzoneWrapper from './file-dropzone';
export { FileDropzoneWrapper };


import FileUploadWrapper from './file-upload';
export { FileUploadWrapper };

Expand Down Expand Up @@ -1185,6 +1200,7 @@ findDatePicker(selector?: string): DatePickerWrapper;
findDateRangePicker(selector?: string): DateRangePickerWrapper;
findDrawer(selector?: string): DrawerWrapper;
findExpandableSection(selector?: string): ExpandableSectionWrapper;
findFileDropzone(selector?: string): FileDropzoneWrapper;
findFileUpload(selector?: string): FileUploadWrapper;
findFlashbar(selector?: string): FlashbarWrapper;
findForm(selector?: string): FormWrapper;
Expand Down Expand Up @@ -1403,6 +1419,12 @@ ElementWrapper.prototype.findExpandableSection = function(selector) {
// https://github.com/microsoft/TypeScript/issues/29132
return (this as any).findComponent(selector ? appendSelector(selector, rootSelector) : rootSelector, ExpandableSectionWrapper);
};
ElementWrapper.prototype.findFileDropzone = function(selector) {
const rootSelector = \`.\${FileDropzoneWrapper.rootSelector}\`;
// casting to 'any' is needed to avoid this issue with generics
// https://github.com/microsoft/TypeScript/issues/29132
return (this as any).findComponent(selector ? appendSelector(selector, rootSelector) : rootSelector, FileDropzoneWrapper);
};
ElementWrapper.prototype.findFileUpload = function(selector) {
const rootSelector = \`.\${FileUploadWrapper.rootSelector}\`;
// casting to 'any' is needed to avoid this issue with generics
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,11 @@
import React from 'react';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';

import Button from '../../../../../lib/components/button';
import InternalFileDropzone, {
FileDropzoneProps,
useFilesDragging,
} from '../../../../../lib/components/internal/components/file-dropzone';
import createWrapper from '../../../../../lib/components/test-utils/dom';
import FileDropzoneWrapper from '../../../../../lib/components/test-utils/dom/internal/file-dropzone';
import Button from '../../../lib/components/button';
import FileDropzone, { FileDropzoneProps, useFilesDragging } from '../../../lib/components/file-dropzone';
import createWrapper from '../../../lib/components/test-utils/dom';

import selectors from '../../../../../lib/components/internal/components/file-dropzone/styles.selectors.js';
import selectors from '../../../lib/components/file-dropzone/styles.selectors.js';

const file1 = new File([new Blob(['Test content 1'], { type: 'text/plain' })], 'test-file-1.txt', {
type: 'text/plain',
Expand All @@ -25,9 +21,8 @@ const file2 = new File([new Blob(['Test content 2'], { type: 'text/plain' })], '
const onChange = jest.fn();

function renderFileDropzone(props: Partial<FileDropzoneProps>) {
render(<InternalFileDropzone onChange={onChange}>{props.children}</InternalFileDropzone>);
const element = createWrapper().findByClassName(FileDropzoneWrapper.rootSelector)!.getElement();
return new FileDropzoneWrapper(element);
const { container } = render(<FileDropzone onChange={onChange}>{props.children}</FileDropzone>);
return createWrapper(container).findFileDropzone()!;
}

function createDragEvent(type: string, files = [file1, file2]) {
Expand Down
18 changes: 18 additions & 0 deletions src/file-dropzone/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React from 'react';

import useBaseComponent from '../internal/hooks/use-base-component';
import { applyDisplayName } from '../internal/utils/apply-display-name';
import { FileDropzoneProps } from './interfaces';
import InternalFileDropzone from './internal';
import { useFilesDragging } from './use-files-dragging';

export { FileDropzoneProps, useFilesDragging };

export default function FileDropzone(props: FileDropzoneProps) {
const baseComponentProps = useBaseComponent('FileDropzone');
return <InternalFileDropzone {...baseComponentProps} {...props} />;
}

applyDisplayName(FileDropzone, 'FileDropzone');
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { BaseComponentProps } from '../../base-component';
import { NonCancelableEventHandler } from '../../events';
import { BaseComponentProps } from '../internal/base-component';
import { NonCancelableEventHandler } from '../internal/events';

export interface FileDropzoneProps extends BaseComponentProps {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,21 @@
import React, { useState } from 'react';
import clsx from 'clsx';

import { fireNonCancelableEvent } from '../../events';
import { getBaseProps } from '../internal/base-component';
import { fireNonCancelableEvent } from '../internal/events';
import { InternalBaseComponentProps } from '../internal/hooks/use-base-component/index.js';
import { FileDropzoneProps } from './interfaces';
import { useFilesDragging } from './use-files-dragging';

import styles from './styles.css.js';

export { FileDropzoneProps, useFilesDragging };

export default function InternalFileDropzone({ onChange, children }: FileDropzoneProps) {
export default function InternalFileDropzone({
onChange,
children,
__internalRootRef = null,
...restProps
}: FileDropzoneProps & InternalBaseComponentProps) {
const [isDropzoneHovered, setDropzoneHovered] = useState(false);
const baseProps = getBaseProps(restProps);

const onDragOver = (event: React.DragEvent) => {
event.preventDefault();
Expand Down Expand Up @@ -41,7 +46,11 @@ export default function InternalFileDropzone({ onChange, children }: FileDropzon

return (
<div
className={clsx(styles.root, isDropzoneHovered && styles.hovered)}
{...baseProps}
ref={__internalRootRef}
className={clsx(baseProps.className, styles.root, {
[styles.hovered]: isDropzoneHovered,
})}
onDragOver={onDragOver}
onDragLeave={onDragLeave}
onDrop={onDrop}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
SPDX-License-Identifier: Apache-2.0
*/

@use '../../styles/tokens' as awsui;
@use '../../styles' as styles;
@use '../internal/styles/tokens' as awsui;
@use '../internal/styles' as styles;

.root {
display: flex;
Expand Down
2 changes: 1 addition & 1 deletion src/file-upload/__tests__/file-upload.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { warnOnce } from '@cloudscape-design/component-toolkit/internal';
import '../../__a11y__/to-validate-a11y';
import FileUpload, { FileUploadProps } from '../../../lib/components/file-upload';
import createWrapper from '../../../lib/components/test-utils/dom';
import FileDropzoneWrapper from '../../../lib/components/test-utils/dom/internal/file-dropzone';
import FileDropzoneWrapper from '../../../lib/components/test-utils/dom/file-dropzone';

jest.mock('@cloudscape-design/component-toolkit/internal', () => ({
...jest.requireActual('@cloudscape-design/component-toolkit/internal'),
Expand Down
Loading
Loading