Skip to content

Commit

Permalink
Merge pull request #23 from Atnic/feature/progress
Browse files Browse the repository at this point in the history
feat: add progress component
  • Loading branch information
muhamien authored Feb 28, 2024
2 parents ce1d6b1 + 7edb97d commit abb103e
Show file tree
Hide file tree
Showing 14 changed files with 716 additions and 21 deletions.
7 changes: 7 additions & 0 deletions packages/components/progress/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# @jala-banyu/progress

## 1.0.0

### Major Changes

- Initial Progress Version
24 changes: 24 additions & 0 deletions packages/components/progress/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# @jala-banyu/progress

A Quick description of the component

> This is an internal utility, not intended for public usage.
## Installation

```sh
yarn add @jala-banyu/progress
# or
npm i @jala-banyu/progress
```

## Contribution

Yes please! See the
[contributing guidelines](https://github.com/Atnic/banyu/blob/master/CONTRIBUTING.md)
for details.

## Licence

This project is licensed under the terms of the
[MIT license](https://github.com/Atnic/banyu/blob/master/LICENSE).
94 changes: 94 additions & 0 deletions packages/components/progress/__tests__/progress.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import * as React from "react";
import {render} from "@testing-library/react";

import {Progress} from "../src";

describe("Progress", () => {
it("should render correctly", () => {
const wrapper = render(<Progress aria-label="progress" />);

expect(() => wrapper.unmount()).not.toThrow();
});

it("ref should be forwarded", () => {
const ref = React.createRef<HTMLDivElement>();

render(<Progress ref={ref} aria-label="progress" />);
expect(ref.current).not.toBeNull();
});

it("should contain progress aria attributes", () => {
const {container} = render(<Progress aria-label="progress" />);
const div = container.querySelector("div");

expect(div).toHaveAttribute("role", "progressbar");

expect(div).toHaveAttribute("aria-valuemin", "0");
expect(div).toHaveAttribute("aria-valuemax", "100");
expect(div).toHaveAttribute("aria-valuenow", "0");
expect(div).toHaveAttribute("aria-valuetext", "0%");
});

it("should display the correct value", () => {
const {container} = render(<Progress aria-label="progress" value={55} />);

// get the "aria-valuenow" attribute
const value = container.querySelector("div")?.getAttribute("aria-valuenow");

expect(value).toBe("55");
});

it("should support label value formatting", () => {
const {container} = render(
<Progress
aria-label="progress"
formatOptions={{style: "currency", currency: "ARS"}}
value={55}
/>,
);

// get the "aria-valuetext" attribute
const value = container.querySelector("div")?.getAttribute("aria-valuetext");

expect(value).toBe("ARS 55.00");
});

it("should ignore a value under the minimum", () => {
const {container} = render(<Progress aria-label="progress" value={-1} />);

// get the "aria-valuenow" attribute
const value = container.querySelector("div")?.getAttribute("aria-valuenow");

expect(value).toBe("0");
});

it("should ignore a value over the maximum", () => {
const {container} = render(<Progress aria-label="progress" value={101} />);

// get the "aria-valuenow" attribute
const value = container.querySelector("div")?.getAttribute("aria-valuenow");

expect(value).toBe("100");
});

it("should render a label", () => {
const {container} = render(<Progress aria-label="progress" label="Loading..." />);

expect(container.querySelector("span")).not.toBeNull();
});

it("should render a value label", () => {
const {container} = render(<Progress showValueLabel aria-label="progress" value={55} />);

expect(container.querySelector("span")).not.toBeNull();
});

it("the aria-valuenow should not be set if isIndeterminate is true", () => {
const {container} = render(<Progress isIndeterminate aria-label="progress" />);

// get the "aria-valuenow" attribute
const value = container.querySelector("div")?.getAttribute("aria-valuenow");

expect(value).toBeNull();
});
});
61 changes: 61 additions & 0 deletions packages/components/progress/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"name": "@jala-banyu/progress",
"version": "1.0.0",
"description": "Progress bars show either determinate or indeterminate progress of an operation over time.",
"keywords": [
"progress"
],
"author": "Dika Mahendra <[email protected]>",
"homepage": "#",
"license": "MIT",
"main": "src/index.ts",
"sideEffects": false,
"files": [
"dist"
],
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/Atnic/banyu.git",
"directory": "packages/components/progress"
},
"bugs": {
"url": "https://github.com/Atnic/banyu/issues"
},
"scripts": {
"build": "tsup src --dts",
"build:fast": "tsup src",
"dev": "yarn build:fast -- --watch",
"clean": "rimraf dist .turbo",
"typecheck": "tsc --noEmit",
"prepack": "clean-package",
"postpack": "clean-package restore"
},
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"@jala-banyu/theme": ">=1.0.0",
"@jala-banyu/system": ">=1.0.0"
},
"dependencies": {
"@jala-banyu/shared-utils": "workspace: *",
"@jala-banyu/react-utils": "workspace: *",
"@jala-banyu/use-is-mounted": "workspace:*",
"@react-aria/i18n": "^3.8.4",
"@react-aria/progress": "^3.4.7",
"@react-aria/utils": "^3.21.1",
"@react-types/progress": "^3.5.0"
},
"devDependencies": {
"@jala-banyu/theme": "workspace: *",
"@jala-banyu/system": "workspace: *",
"@jala-banyu/card": "workspace:*",
"@jala-banyu/chip": "workspace:*",
"clean-package": "2.2.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"clean-package": "../../../clean-package.config.json"
}
10 changes: 10 additions & 0 deletions packages/components/progress/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Progress from "./progress";

// export types
export type {ProgressProps} from "./progress";

// export hooks
export {useProgress} from "./use-progress";

// export component
export {Progress};
68 changes: 68 additions & 0 deletions packages/components/progress/src/progress.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import {forwardRef} from "@jala-banyu/system";
import {Chip} from "@jala-banyu/chip";

import {UseProgressProps, useProgress} from "./use-progress";

export interface ProgressProps extends UseProgressProps {}

const Progress = forwardRef<"div", ProgressProps>((props, ref) => {
const {
Component,
slots,
classNames,
label,
percentage,
showValueLabel,
getProgressBarProps,
getLabelProps,
getChipProps,
} = useProgress({...props, ref});

const progressBarProps = getProgressBarProps();
const shouldShowLabelWrapper = label || showValueLabel;
let floatingLabelMargin = `calc(${progressBarProps["aria-valuetext"]} - 1.5rem)`;

switch (progressBarProps["aria-valuetext"]) {
case "0%":
floatingLabelMargin = "0";
break;
case "100%":
floatingLabelMargin = "calc(100% - 3.1rem)";
break;
}

return (
<Component {...progressBarProps}>
{shouldShowLabelWrapper ? (
<div className={slots.labelWrapper({class: classNames?.labelWrapper})}>
{label && <span {...getLabelProps()}>{label}</span>}
{showValueLabel && (
<span className={slots.value({class: classNames?.value})}>
{progressBarProps["aria-valuetext"]}
</span>
)}
</div>
) : null}
<div className={slots.progressBarWrapper({class: classNames?.progressBarWrapper})}>
<div
className={slots.floatingLabelWrapper({class: classNames?.floatingLabelWrapper})}
style={{marginInlineStart: floatingLabelMargin}}
>
<Chip {...getChipProps()}>{progressBarProps["aria-valuetext"]}</Chip>
</div>
<div className={slots.track({class: classNames?.track})}>
<div
className={slots.indicator({class: classNames?.indicator})}
style={{
transform: `translateX(-${100 - (percentage || 0)}%)`,
}}
/>
</div>
</div>
</Component>
);
});

Progress.displayName = "Banyu.Progress";

export default Progress;
Loading

0 comments on commit abb103e

Please sign in to comment.