Skip to content

Commit

Permalink
Add Progress hooks and components
Browse files Browse the repository at this point in the history
  • Loading branch information
mj12albert committed Jul 9, 2024
1 parent 2a9ebe1 commit 89fe34f
Show file tree
Hide file tree
Showing 36 changed files with 1,676 additions and 1 deletion.
85 changes: 85 additions & 0 deletions docs/data/base/components/progress/UnstyledProgressIntroduction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import * as React from 'react';
import { useTheme } from '@mui/system';
import * as Progress from '@base_ui/react/Progress';

export default function UnstyledProgressIntroduction() {
return (
<div className="App">
<Progress.Root className="Progress" value={50} aria-labelledby="ProgressLabel">
<span className="Progress-label" id="ProgressLabel">
Uploading files
</span>
<Progress.Track className="Progress-track">
<Progress.Indicator className="Progress-indicator" />
</Progress.Track>
</Progress.Root>
<Styles />
</div>
);
}

function useIsDarkMode() {
const theme = useTheme();
return theme.palette.mode === 'dark';
}

export function Styles() {
const isDarkMode = useIsDarkMode();
return (
<style suppressHydrationWarning>{`
.App {
font-family: system-ui, sans-serif;
width: 20rem;
padding: 1rem;
}
.Progress {
display: flex;
flex-flow: column nowrap;
gap: 1rem;
}
.Progress-track {
position: relative;
width: 100%;
height: 4px;
border-radius: 9999px;
background-color: ${grey[400]};
display: flex;
overflow: hidden;
}
.Progress-indicator {
background-color: ${isDarkMode ? BLUE400 : BLUE500};
border-radius: inherit;
}
.Progress-indicator[data-state='indeterminate'] {
width: 25%;
animation: indeterminateLoading 1.5s infinite ease-in-out;
will-change: transform;
}
.Progress-label {
cursor: unset;
font-weight: bold;
}
`}</style>
);
}

const grey = {
50: '#F3F6F9',
100: '#E5EAF2',
200: '#DAE2ED',
300: '#C7D0DD',
400: '#B0B8C4',
500: '#9DA8B7',
600: '#6B7A90',
700: '#434D5B',
800: '#303740',
900: '#1C2025',
};

const BLUE400 = '#3399FF';
const BLUE500 = '#007FFF';
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import * as React from 'react';
import { useTheme } from '@mui/system';
import * as Progress from '@base_ui/react/Progress';

export default function UnstyledProgressIntroduction() {
return (
<div className="App">
<Progress.Root className="Progress" value={50} aria-labelledby="ProgressLabel">
<span className="Progress-label" id="ProgressLabel">
Uploading files
</span>
<Progress.Track className="Progress-track">
<Progress.Indicator className="Progress-indicator" />
</Progress.Track>
</Progress.Root>
<Styles />
</div>
);
}

function useIsDarkMode() {
const theme = useTheme();
return theme.palette.mode === 'dark';
}

export function Styles() {
const isDarkMode = useIsDarkMode();
return (
<style suppressHydrationWarning>{`
.App {
font-family: system-ui, sans-serif;
width: 20rem;
padding: 1rem;
}
.Progress {
display: flex;
flex-flow: column nowrap;
gap: 1rem;
}
.Progress-track {
position: relative;
width: 100%;
height: 4px;
border-radius: 9999px;
background-color: ${grey[400]};
display: flex;
overflow: hidden;
}
.Progress-indicator {
background-color: ${isDarkMode ? BLUE400 : BLUE500};
border-radius: inherit;
}
.Progress-indicator[data-state='indeterminate'] {
width: 25%;
animation: indeterminateLoading 1.5s infinite ease-in-out;
will-change: transform;
}
.Progress-label {
cursor: unset;
font-weight: bold;
}
`}</style>
);
}

const grey = {
50: '#F3F6F9',
100: '#E5EAF2',
200: '#DAE2ED',
300: '#C7D0DD',
400: '#B0B8C4',
500: '#9DA8B7',
600: '#6B7A90',
700: '#434D5B',
800: '#303740',
900: '#1C2025',
};

const BLUE400 = '#3399FF';
const BLUE500 = '#007FFF';
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Progress.Root className="Progress" value={50} aria-labelledby="ProgressLabel">
<span className="Progress-label" id="ProgressLabel">
Uploading files
</span>
<Progress.Track className="Progress-track">
<Progress.Indicator className="Progress-indicator" />
</Progress.Track>
</Progress.Root>
<Styles />
137 changes: 137 additions & 0 deletions docs/data/base/components/progress/progress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
---
productId: base-ui
title: React Progress components
components: ProgressRoot, ProgressTrack, ProgressIndicator
hooks: useProgressRoot, useProgressIndicator
githubLabel: 'component: progress'
waiAria: https://www.w3.org/TR/wai-aria-1.2/#progressbar
packageName: '@base_ui/react'
---

# Progress

<p class="description">The Progress component displays the status of a task or operation over time.</p>

{{"component": "@mui/docs/ComponentLinkHeader", "design": false}}

{{"component": "modules/components/ComponentPageTabs.js"}}

{{"demo": "UnstyledProgressIntroduction.js", "defaultCodeOpen": false, "bg": "gradient"}}

## Installation

Base UI components are all available as a single package.

<codeblock storageKey="package-manager">

```bash npm
npm install @base_ui/react
```

```bash yarn
yarn add @base_ui/react
```

```bash pnpm
pnpm add @base_ui/react
```

</codeblock>

Once you have the package installed, import the component.

```jsx
import * as Progress from '@base_ui/react/Progress';
```

### Anatomy

Progress

- `<Progress.Root />` is a top-level component that wraps the other components.
- `<Progress.Track />` renders the rail that represents the total length or duration of progress.
- `<Progress.Indicator />` renders the filled portion of the track.

```tsx
<Progress.Root>
<Progress.Track>
<Progress.Indicator />
</Progress.Track>
</Progress.Root>
```

## Value

### Determinate

The `value` prop represents the percentage value of the Progress component. The default minimum and maximum values are `0` and `100`, and can be changed with the `min` and `max` props.

```tsx
function App() {
const [progressValue] = React.useState(25);
return (
<Progress.Root value={progressValue} min={0} max={100}>
<Progress.Track>
<Progress.Indicator />
</Progress.Track>
</Progress.Root>
);
}
```

### Indeterminate

Set `value` to `null` to configure an indeterminate progress bar.

```tsx
<Progress.Root value={null}>
<Progress.Track>
<Progress.Indicator />
</Progress.Track>
</Progress.Root>
```

<!-- TODO: indeterminate demo -->

## RTL

Set the `direction` prop to `'rtl'` to change the direction that the `Indicator` fills towards for right-to-left languages:

```jsx
<Progress.Root direction="rtl">{/* Subcomponents */}</Progress.Root>
```

<!-- TODO: RTL demo -->

## Overriding default components

Use the `render` prop to override the rendered element for all subcomponents:

```jsx
<Progress.Indicator render={<MyCustomIndicator />} />
// or
<Progress.Indicator render={(props) => <MyCustomIndicator {...props} />} />
```

## Accessibility

The Progress component implements the [ARIA progressbar specification](https://www.w3.org/TR/wai-aria-1.2/#progressbar).

When using Progress, ensure that it has a human-readable text label by using either the `aria-label`, `aria-labelledby`, or `getAriaLabel` prop:

```tsx
<Progress.Root aria-labelledby="MyCustomLabel">
<MyCustomLabel id="MyCustomLabel">Loading progress<MyCustomLabel/>
<Progress.Track>
<Progress.Indicator />
</Progress.Track>
</Progress.Root>

// or

<Progress.Root aria-label="Loading progress">
<Progress.Track>
<Progress.Indicator />
</Progress.Track>
</Progress.Root>
```
2 changes: 1 addition & 1 deletion docs/data/base/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const pages: readonly MuiPage[] = [
children: [
{ pathname: '/base-ui/react-alert-dialog', title: 'Alert Dialog' },
{ pathname: '/base-ui/react-dialog', title: 'Dialog' },
// { pathname: '/base-ui/react-snackbar', title: 'Snackbar' },
{ pathname: '/base-ui/react-progress', title: 'Progress' },
],
},
// {
Expand Down
20 changes: 20 additions & 0 deletions docs/data/base/pagesApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,18 @@ module.exports = [
{ pathname: '/base-ui/react-popper/components-api/#popper', title: 'Popper' },
{ pathname: '/base-ui/react-popup/components-api/#popup', title: 'Popup' },
{ pathname: '/base-ui/react-portal/components-api/#portal', title: 'Portal' },
{
pathname: '/base-ui/react-progress/components-api/#progress-indicator',
title: 'ProgressIndicator',
},
{
pathname: '/base-ui/react-progress/components-api/#progress-root',
title: 'ProgressRoot',
},
{
pathname: '/base-ui/react-progress/components-api/#progress-track',
title: 'ProgressTrack',
},
{ pathname: '/base-ui/react-select/components-api/#select', title: 'Select' },
{
pathname: '/base-ui/react-slider/components-api/#slider-control',
Expand Down Expand Up @@ -298,6 +310,14 @@ module.exports = [
pathname: '/base-ui/react-select/hooks-api/#use-option-context-stabilizer',
title: 'useOptionContextStabilizer',
},
{
pathname: '/base-ui/react-progress/hooks-api/#use-progress-indicator',
title: 'useProgressIndicator',
},
{
pathname: '/base-ui/react-progress/hooks-api/#use-progress-root',
title: 'useProgressRoot',
},
{ pathname: '/base-ui/react-select/hooks-api/#use-select', title: 'useSelect' },
{
pathname: '/base-ui/react-slider/hooks-api/#use-slider-control',
Expand Down
19 changes: 19 additions & 0 deletions docs/pages/base-ui/api/progress-indicator.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"props": {
"className": { "type": { "name": "union", "description": "func<br>&#124;&nbsp;string" } },
"render": { "type": { "name": "union", "description": "element<br>&#124;&nbsp;func" } }
},
"name": "ProgressIndicator",
"imports": [
"import * as Progress from '@base_ui/react/Progress';\nconst ProgressIndicator = Progress.Indicator;"
],
"classes": [],
"spread": true,
"themeDefaultProps": true,
"muiName": "ProgressIndicator",
"forwardsRefTo": "HTMLSpanElement",
"filename": "/packages/mui-base/src/Progress/Indicator/ProgressIndicator.tsx",
"inheritance": null,
"demos": "<ul><li><a href=\"/base-ui/react-progress/\">Progress</a></li></ul>",
"cssComponent": false
}
Loading

0 comments on commit 89fe34f

Please sign in to comment.