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: add new file-input component #6355

Merged
merged 13 commits into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from 10 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
18 changes: 18 additions & 0 deletions playwright/components/file-input/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Page } from "playwright-core";
import { LABEL, FILE_INPUT } from "./locators";

export const hiddenInput = (page: Page, label: string) => {
return page.getByLabel(label);
};

export const selectFileButton = (page: Page, buttonText = "Select file") => {
return page.getByRole("button", { name: buttonText });
};

export const label = (page: Page) => {
return page.locator(LABEL);
};

export const fileInput = (page: Page) => {
return page.locator(FILE_INPUT);
};
2 changes: 2 additions & 0 deletions playwright/components/file-input/locators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const LABEL = "label";
export const FILE_INPUT = '[data-component="file-input"]';
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ const rootTagTest = (
};

const rootTagTestRtl = (
edleeks87 marked this conversation as resolved.
Show resolved Hide resolved
element: HTMLElement,
rootNode: HTMLElement,
comp: string,
elem?: string,
role?: string
) => {
expect(element.getAttribute("data-component")).toBe(comp);
expect(element.getAttribute("data-element")).toBe(elem);
expect(element.getAttribute("data-role")).toBe(role);
expect(rootNode).toHaveAttribute("data-component", comp);
expect(rootNode).toHaveAttribute("data-element", elem);
expect(rootNode).toHaveAttribute("data-role", role);
};

// eslint-disable-next-line jest/no-export
export { elementsTagTest, rootTagTest, rootTagTestRtl };
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import React from "react";
import Link, { LinkProps } from "../../../link";
import ButtonMinor from "../../../button-minor";
import StyledTypography from "../../../typography/typography.style";
import ProgressTracker from "../../../progress-tracker";
import LoaderBar from "../../../loader-bar";
import Icon, { IconType } from "../../../icon";
import {
StyledFileUploadStatus,
StyledFileUploadStatusRow,
StyledFileLinkContainer,
} from "./file-upload-status.style";
import useLocale from "../../../../hooks/__internal__/useLocale";

interface StatusUploadingProps {
/** the status of the upload */
status: "uploading";
/** a number from 0-100 giving the current upload progress as a percentage. Only used for the `uploading` status.
* If the progress prop is not specified in the `uploading` status, a loading animation will be shown instead
* (or text equivalent for users with a reduced-motion operating system preference).
*/
progress?: number;
}

interface StatusDoneProps extends LinkProps {
/** the status of the upload */
status: "completed" | "previously";
/** the URL opened by the file link. Must be provided for only the `completed` and `previously` statuses. */
href: string;
}

interface StatusErrorProps {
/** the status of the upload */
status: "error";
}

interface MandatoryStatusProps {
/** the name of the file */
filename: string;
/** a function to be executed when the user clicks the appropriate action button (Clear/Delete File/Cancel Upload) */
onAction: () => void;
/** The status message. Used to display the current upload progress, including error messages where appropriate. Not used for the `previously` status. */
message?: string;
/** The icon to use for the file during or after upload */
iconType?: IconType;
}

export type FileUploadStatusProps = MandatoryStatusProps &
(StatusUploadingProps | StatusErrorProps | StatusDoneProps);

export const FileUploadStatus = ({
status,
filename,
message,
onAction,
iconType = "file_generic",
...statusProps
}: FileUploadStatusProps) => {
const locale = useLocale();
const statusMessage = message || locale.fileInput.fileUploadStatus();

let buttonText;
let linkProps;
let progressBar = null;
switch (status) {
case "uploading":
buttonText = locale.fileInput.actions.cancel();
progressBar =
(statusProps as StatusUploadingProps).progress === undefined ? (
<LoaderBar size="small" />
) : (
<ProgressTracker
size="small"
progress={(statusProps as StatusUploadingProps).progress}
length="100%"
/>
);
break;
case "previously":
case "completed":
buttonText = locale.fileInput.actions.delete();
linkProps = { ...statusProps, icon: iconType };
break;
case "error":
buttonText = locale.fileInput.actions.clear();
break;
// istanbul ignore next
default:
// no other cases if consumers are using TS, but ESLint still insists on it
break;
}
const actionButton = (
<ButtonMinor onClick={onAction} buttonType="tertiary">
{buttonText}
</ButtonMinor>
);
const fileLink = linkProps ? (
<Link {...linkProps}>{filename}</Link>
) : (
<>
<Icon type={iconType} />
<span>{filename}</span>
</>
);
const mainRow =
status !== "previously" ? (
<StyledFileUploadStatusRow>
<StyledTypography as="p" mb={0} aria-live="polite">
edleeks87 marked this conversation as resolved.
Show resolved Hide resolved
{statusMessage}
</StyledTypography>
{actionButton}
</StyledFileUploadStatusRow>
) : (
<StyledFileUploadStatusRow onlyRow>
<StyledFileLinkContainer>{fileLink}</StyledFileLinkContainer>
{actionButton}
</StyledFileUploadStatusRow>
);
const secondRow =
status !== "previously" ? (
<StyledFileUploadStatusRow upperPadding lowerPadding>
<StyledFileLinkContainer>{fileLink}</StyledFileLinkContainer>
</StyledFileUploadStatusRow>
) : null;
return (
<StyledFileUploadStatus hasError={status === "error"}>
{mainRow}
{secondRow}
{progressBar}
</StyledFileUploadStatus>
);
};

export default FileUploadStatus;
Loading
Loading