diff --git a/.changeset/full-mails-follow.md b/.changeset/full-mails-follow.md new file mode 100644 index 000000000000..3fdb0f7531b6 --- /dev/null +++ b/.changeset/full-mails-follow.md @@ -0,0 +1,5 @@ +--- +"@stratakit/mui": patch +--- + +Removed the following values from the `color` prop of `LinearProgress`: `"info"`, and `"inherit"`. diff --git a/.changeset/sweet-months-cross.md b/.changeset/sweet-months-cross.md new file mode 100644 index 000000000000..036d64414585 --- /dev/null +++ b/.changeset/sweet-months-cross.md @@ -0,0 +1,5 @@ +--- +"@stratakit/mui": patch +--- + +Styled `LinearProgress` to match the Strata visual design language. diff --git a/.changeset/thirty-trains-cross.md b/.changeset/thirty-trains-cross.md new file mode 100644 index 000000000000..c8ee1d417b9c --- /dev/null +++ b/.changeset/thirty-trains-cross.md @@ -0,0 +1,5 @@ +--- +"@stratakit/mui": patch +--- + +Styled `CircularProgress` to match the Strata visual design language. diff --git a/apps/test-app/app/mui/CircularProgress.showcase.tsx b/apps/test-app/app/mui/CircularProgress.showcase.tsx index 4be032016f02..cf949976215e 100644 --- a/apps/test-app/app/mui/CircularProgress.showcase.tsx +++ b/apps/test-app/app/mui/CircularProgress.showcase.tsx @@ -2,20 +2,16 @@ * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ -import Stack from "@mui/material/Stack"; -import CircularProgressColors_ from "examples/mui/CircularProgress._colors.tsx"; +import CircularProgressColors from "examples/mui/CircularProgress.colors.tsx"; import CircularProgressDefault from "examples/mui/CircularProgress.default.tsx"; -import { isProduction } from "~/~utils.tsx"; +import CircularProgressDeterminate from "examples/mui/CircularProgress.determinate.tsx"; export default function CircularProgressExamples() { return ( <> - {!isProduction && ( - - - - )} + + ); } diff --git a/apps/test-app/app/mui/LinearProgress.showcase.tsx b/apps/test-app/app/mui/LinearProgress.showcase.tsx index f2a15327e501..0c2967490449 100644 --- a/apps/test-app/app/mui/LinearProgress.showcase.tsx +++ b/apps/test-app/app/mui/LinearProgress.showcase.tsx @@ -3,15 +3,18 @@ * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ import Stack from "@mui/material/Stack"; -import LinearProgressColors_ from "examples/mui/LinearProgress._colors.tsx"; +import LinearProgressBuffer from "examples/mui/LinearProgress.buffer.tsx"; +import LinearProgressColors from "examples/mui/LinearProgress.colors.tsx"; import LinearProgressDefault from "examples/mui/LinearProgress.default.tsx"; -import { isProduction } from "~/~utils.tsx"; +import LinearProgressDeterminate from "examples/mui/LinearProgress.determinate.tsx"; export default function LinearProgressExamples() { return ( - {!isProduction && } + + + ); } diff --git a/apps/website/src/content/docs/components/mui/CircularProgress.md b/apps/website/src/content/docs/components/mui/CircularProgress.md new file mode 100644 index 000000000000..f2a327322f4a --- /dev/null +++ b/apps/website/src/content/docs/components/mui/CircularProgress.md @@ -0,0 +1,30 @@ +--- +title: CircularProgress +description: Progress indicators are used to display a loading state or visualize the progress of an operation. +links: + muiDocs: https://mui.com/material-ui/react-progress/ + apiReference: https://mui.com/material-ui/api/circular-progress/ +--- + +::example{src="mui/CircularProgress.default"} + +## StrataKit MUI modifications + +- The `enableTrackSlot` prop defaults to true. +- Restyled using StrataKit's visual language. +- Includes full `forced-colors` support. + +## Examples + +### Colors + +- **Primary:** The default. Use when indicating the primary loading state on a page. +- **Secondary:** Use when indicating a secondary loading state or when multiple loading states are shown at once. + +::example{src="mui/CircularProgress.colors"} + +### Determinate + +Set the `variant` prop to `"determinate"` when the completion percentage is known. + +::example{src="mui/CircularProgress.determinate"} diff --git a/apps/website/src/content/docs/components/mui/LinearProgress.md b/apps/website/src/content/docs/components/mui/LinearProgress.md new file mode 100644 index 000000000000..d3e4f8763bce --- /dev/null +++ b/apps/website/src/content/docs/components/mui/LinearProgress.md @@ -0,0 +1,37 @@ +--- +title: LinearProgress +description: Progress indicators are used to display a loading state or visualize the progress of an operation. +links: + muiDocs: https://mui.com/material-ui/react-progress/ + apiReference: https://mui.com/material-ui/api/linear-progress/ +--- + +::example{src="mui/LinearProgress.default" min-width="300px"} + +## StrataKit MUI modifications + +- The `color` prop does not support `"inherit"` or `"info"`. +- Added an end marker when the `variant` prop is set to `"determinate"` or `"buffer"`. +- Restyled using StrataKit's visual language. +- Includes full `forced-colors` support. + +## Examples + +### Colors + +- **Primary:** The default. Use when indicating the primary loading state on a page. +- **Secondary:** Use when indicating a secondary loading state or when multiple loading states are shown at once. + +::example{src="mui/LinearProgress.colors" min-width="300px"} + +### Determinate + +Set the `variant` prop to `"determinate"` when the completion percentage is known. + +::example{src="mui/LinearProgress.determinate" min-width="300px"} + +### Buffer + +Set the `variant` prop to `"buffer"` when progress and buffered work are tracked separately. + +::example{src="mui/LinearProgress.buffer" min-width="300px"} diff --git a/apps/website/src/content/docs/components/mui/Progress.md b/apps/website/src/content/docs/components/mui/Progress.md deleted file mode 100644 index a1c53a70cc02..000000000000 --- a/apps/website/src/content/docs/components/mui/Progress.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: Progress -description: Progress indicators are used to display a loading state or visualize the progress of an operation. -links: - muiDocs: https://mui.com/material-ui/react-progress/ - apiReference: https://mui.com/material-ui/api/circular-progress/ ---- - -::example{src="mui/CircularProgress.default"} - -## Examples - -### Linear - -::example{src="mui/LinearProgress.default"} diff --git a/apps/website/src/content/docs/components/mui/Skeleton.md b/apps/website/src/content/docs/components/mui/Skeleton.md index 4889409882eb..0662e41ba541 100644 --- a/apps/website/src/content/docs/components/mui/Skeleton.md +++ b/apps/website/src/content/docs/components/mui/Skeleton.md @@ -12,11 +12,11 @@ links: Make sure the **Skeleton** is suitable for your use case. There may be other, more appropriate components available. -| Use case | [Progress](/components/progress) | [Skeleton](/components/skeleton) | -| ----------------------------------------------------------------------- | -------------------------------- | -------------------------------- | -| Showing a loading (or other) process where the progress is determinable | ✅ | ❌ | -| Showing an indeterminable loading progress | ✅ | ✅ | -| Showing a process other than loading, such as a calculation | ✅ | ❌ | +| Use case | [CircularProgress](/components/circularprogress) & [LinearProgress](/components/linearprogress) | [Skeleton](/components/skeleton) | +| ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | -------------------------------- | +| Showing a loading (or other) process where the progress is determinable | ✅ | ❌ | +| Showing an indeterminable loading progress | ✅ | ✅ | +| Showing a process other than loading, such as a calculation | ✅ | ❌ | ### Variants @@ -42,4 +42,4 @@ Accurately representing the shape and structure of a loading interface is a case ## 🚫 Don't - Don't use **Skeleton** where the size and shape of the content and functionality being loaded is not known. -- Don't use **Skeleton** to indicate the progress of any process except loading. For indicating the progress of calculations and other processes within a loaded interface, use [**Progress**](/components/progress). +- Don't use **Skeleton** to indicate the progress of any process except loading. For indicating the progress of calculations and other processes within a loaded interface, use [**CircularProgress**](/components/circularprogress) or [**LinearProgress**](/components/linearprogress). diff --git a/apps/website/src/content/docs/getting-started/migration-from-legacy-stratakit.mdx b/apps/website/src/content/docs/getting-started/migration-from-legacy-stratakit.mdx index 0fbf039c4797..4aee97d980cc 100644 --- a/apps/website/src/content/docs/getting-started/migration-from-legacy-stratakit.mdx +++ b/apps/website/src/content/docs/getting-started/migration-from-legacy-stratakit.mdx @@ -256,7 +256,7 @@ Read additional [StrataKit MUI component documentation](/components/overview/) f ### ProgressBar -- Replace the `ProgressBar` component from `@stratakit/bricks` with the `LinearProgress` component from `@mui/material`. See [Progress examples](/components/progress/) for reference. +- Replace the `ProgressBar` component from `@stratakit/bricks` with the `LinearProgress` component from `@mui/material`. See [LinearProgress examples](/components/linearprogress) for reference. - Remove unsupported [`size`](/reference/bricks/Progress#Progress.ProgressBar.size) prop. - Change [`tone`](/reference/bricks/Progress#Progress.ProgressBar.tone) prop to [`color`](https://mui.com/material-ui/api/linear-progress/#linear-progress-prop-color) prop. @@ -290,7 +290,7 @@ Read additional [StrataKit MUI component documentation](/components/overview/) f ### Spinner -- Replace the `Spinner` component from `@stratakit/bricks` with the `CircularProgress` component from `@mui/material`. See [Progress examples](/components/progress/) for reference. +- Replace the `Spinner` component from `@stratakit/bricks` with the `CircularProgress` component from `@mui/material`. See [CircularProgress examples](/components/circularprogress) for reference. - Change the value of [`size`](/reference/bricks/Spinner#Spinner.size) prop. MUI [`size`](https://mui.com/material-ui/api/circular-progress/#circular-progress-prop-size) prop uses pixel values or custom units when a string is provided. - Change [`tone`](/reference/bricks/Spinner#Spinner.tone) prop to [`color`](https://mui.com/material-ui/api/circular-progress/#circular-progress-prop-color) prop. diff --git a/examples/mui/CircularProgress.colors.tsx b/examples/mui/CircularProgress.colors.tsx new file mode 100644 index 000000000000..b0050fd09bdb --- /dev/null +++ b/examples/mui/CircularProgress.colors.tsx @@ -0,0 +1,19 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ + +import * as React from "react"; +import CircularProgress from "@mui/material/CircularProgress"; +import Typography from "@mui/material/Typography"; + +export default () => { + const labelId = React.useId(); + + return ( + <> + + Analyzing results… + + ); +}; diff --git a/examples/mui/CircularProgress.determinate.module.css b/examples/mui/CircularProgress.determinate.module.css new file mode 100644 index 000000000000..50afa7175e9a --- /dev/null +++ b/examples/mui/CircularProgress.determinate.module.css @@ -0,0 +1,17 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ + +.container { + display: inline-flex; + position: relative; +} + +.percentage { + align-items: center; + display: flex; + inset: 0; + justify-content: center; + position: absolute; +} diff --git a/examples/mui/CircularProgress._colors.tsx b/examples/mui/CircularProgress.determinate.tsx similarity index 52% rename from examples/mui/CircularProgress._colors.tsx rename to examples/mui/CircularProgress.determinate.tsx index bfffcb43f15c..3a00676e5b7a 100644 --- a/examples/mui/CircularProgress._colors.tsx +++ b/examples/mui/CircularProgress.determinate.tsx @@ -4,28 +4,29 @@ *--------------------------------------------------------------------------------------------*/ import * as React from "react"; +import Box from "@mui/material/Box"; import CircularProgress from "@mui/material/CircularProgress"; import Typography from "@mui/material/Typography"; -type CircularProgressProps = React.ComponentProps; -const colors = [ - "secondary", - "primary", -] as const satisfies CircularProgressProps["color"][]; +import styles from "./CircularProgress.determinate.module.css"; export default () => { - const exampleId = React.useId(); + const labelId = React.useId(); + const progress = 50; - return colors.map((color) => { - const labelId = `${exampleId}-${color}`; - return ( -
- - - {color.charAt(0).toUpperCase()} - {color.slice(1)}… + return ( + <> + + + + {progress}% -
- ); - }); + + Uploading… + + ); }; diff --git a/examples/mui/LinearProgress._colors.tsx b/examples/mui/LinearProgress._colors.tsx deleted file mode 100644 index 9b40ee86c9b7..000000000000 --- a/examples/mui/LinearProgress._colors.tsx +++ /dev/null @@ -1,31 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Bentley Systems, Incorporated. All rights reserved. - * See LICENSE.md in the project root for license terms and full copyright notice. - *--------------------------------------------------------------------------------------------*/ - -import * as React from "react"; -import LinearProgress from "@mui/material/LinearProgress"; -import Typography from "@mui/material/Typography"; - -type LinearProgressProps = React.ComponentProps; -const colors = [ - "secondary", - "primary", -] as const satisfies LinearProgressProps["color"][]; - -export default () => { - const exampleId = React.useId(); - - return colors.map((color) => { - const labelId = `${exampleId}-${color}`; - return ( - - - - {color.charAt(0).toUpperCase()} - {color.slice(1)}… - - - ); - }); -}; diff --git a/examples/mui/LinearProgress.buffer.tsx b/examples/mui/LinearProgress.buffer.tsx new file mode 100644 index 000000000000..8965b9ab0796 --- /dev/null +++ b/examples/mui/LinearProgress.buffer.tsx @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ + +import * as React from "react"; +import LinearProgress from "@mui/material/LinearProgress"; +import Typography from "@mui/material/Typography"; + +export default () => { + const labelId = React.useId(); + + return ( + <> + + Buffering results… + + ); +}; diff --git a/examples/mui/LinearProgress.colors.tsx b/examples/mui/LinearProgress.colors.tsx new file mode 100644 index 000000000000..906cc2c3c63c --- /dev/null +++ b/examples/mui/LinearProgress.colors.tsx @@ -0,0 +1,19 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ + +import * as React from "react"; +import LinearProgress from "@mui/material/LinearProgress"; +import Typography from "@mui/material/Typography"; + +export default () => { + const labelId = React.useId(); + + return ( + <> + + Analyzing results… + + ); +}; diff --git a/examples/mui/LinearProgress.determinate.tsx b/examples/mui/LinearProgress.determinate.tsx new file mode 100644 index 000000000000..5841959ae60b --- /dev/null +++ b/examples/mui/LinearProgress.determinate.tsx @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ + +import * as React from "react"; +import LinearProgress from "@mui/material/LinearProgress"; +import Stack from "@mui/material/Stack"; +import Typography from "@mui/material/Typography"; + +export default () => { + const labelId = React.useId(); + const progress = 50; + + return ( + <> + + + Uploading… + {progress}% + + + ); +}; diff --git a/packages/mui/src/types.ts b/packages/mui/src/types.ts index 4b04dd1d6498..abbbcc998ed2 100644 --- a/packages/mui/src/types.ts +++ b/packages/mui/src/types.ts @@ -255,6 +255,31 @@ declare module "@mui/material/Chip" { } } +declare module "@mui/material/LinearProgress" { + interface LinearProgressPropsColorOverrides { + inherit: false; + info: false; + } +} + +declare module "@mui/material/CircularProgress" { + interface CircularProgressOwnProps { + /** + * The default value with `@stratakit/mui` is `true`. + * + * @default true + */ + enableTrackSlot?: boolean; + + /** + * The default thickness with `@stratakit/mui` is `5`. + * + * @default 5 + */ + thickness?: number; + } +} + declare module "@mui/material/Dialog" { interface DialogProps extends Pick { /** @deprecated Use `render` prop instead. */ diff --git a/packages/mui/src/~components.css b/packages/mui/src/~components.css index 416adc5e1728..50548fd3934d 100644 --- a/packages/mui/src/~components.css +++ b/packages/mui/src/~components.css @@ -17,11 +17,13 @@ @import "./~components/MuiCard.css"; @import "./~components/MuiCheckbox.css"; @import "./~components/MuiChip.css"; +@import "./~components/MuiCircularProgress.css"; @import "./~components/MuiDialog.css"; @import "./~components/MuiDivider.css"; @import "./~components/MuiForm.css"; @import "./~components/MuiIconButton.css"; @import "./~components/MuiInput.css"; +@import "./~components/MuiLinearProgress.css"; @import "./~components/MuiLink.css"; @import "./~components/MuiList.css"; @import "./~components/MuiMenu.css"; diff --git a/packages/mui/src/~components/MuiCircularProgress.css b/packages/mui/src/~components/MuiCircularProgress.css new file mode 100644 index 000000000000..c649acac9aa1 --- /dev/null +++ b/packages/mui/src/~components/MuiCircularProgress.css @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ + +.MuiCircularProgress-root { + --_MuiCircularProgress-track-thickness: 1px; + --_MuiCircularProgress-fill-thickness: 5px; + + &:where(.MuiCircularProgress-colorPrimary) { + --_MuiCircularProgress-color: var(--stratakit-color-icon-accent-strong); + } + + &:where(.MuiCircularProgress-colorSecondary) { + --_MuiCircularProgress-color: var(--stratakit-color-icon-neutral-base); + } + + &:where(.MuiCircularProgress-colorError) { + --_MuiCircularProgress-color: var(--stratakit-color-icon-critical-base); + } + + &:where(.MuiCircularProgress-colorWarning) { + --_MuiCircularProgress-color: var(--stratakit-color-icon-attention-base); + } + + &:where(.MuiCircularProgress-colorInfo) { + --_MuiCircularProgress-color: var(--stratakit-color-icon-info-base); + } + + &:where(.MuiCircularProgress-colorSuccess) { + --_MuiCircularProgress-color: var(--stratakit-color-icon-positive-base); + } +} + +:is(.MuiCircularProgress-track, .MuiCircularProgress-circle) { + stroke: var(--_MuiCircularProgress-color); +} + +.MuiCircularProgress-track { + opacity: 1; + stroke-width: var(--_MuiCircularProgress-track-thickness); +} + +.MuiCircularProgress-circle { + stroke-linecap: round; + stroke-width: var(--_MuiCircularProgress-fill-thickness); +} diff --git a/packages/mui/src/~components/MuiLinearProgress.css b/packages/mui/src/~components/MuiLinearProgress.css new file mode 100644 index 000000000000..2d35f5efee58 --- /dev/null +++ b/packages/mui/src/~components/MuiLinearProgress.css @@ -0,0 +1,83 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Bentley Systems, Incorporated. All rights reserved. + * See LICENSE.md in the project root for license terms and full copyright notice. + *--------------------------------------------------------------------------------------------*/ + +.MuiLinearProgress-root { + --_MuiLinearProgress-track-thickness: 1px; + --_MuiLinearProgress-fill-thickness: 5px; + + background-color: transparent; + block-size: var(--_MuiLinearProgress-fill-thickness); + border-radius: calc(infinity * 1px); + + &:where(.MuiLinearProgress-colorPrimary) { + --_MuiLinearProgress-color: var(--stratakit-color-icon-accent-strong); + } + + &:where(.MuiLinearProgress-colorSecondary) { + --_MuiLinearProgress-color: var(--stratakit-color-icon-neutral-base); + } + + &:where(.MuiLinearProgress-colorError) { + --_MuiLinearProgress-color: var(--stratakit-color-icon-critical-base); + } + + &:where(.MuiLinearProgress-colorWarning) { + --_MuiLinearProgress-color: var(--stratakit-color-icon-attention-base); + } + + &:where(.MuiLinearProgress-colorInfo) { + --_MuiLinearProgress-color: var(--stratakit-color-icon-info-base); + } + + &:where(.MuiLinearProgress-colorSuccess) { + --_MuiLinearProgress-color: var(--stratakit-color-icon-positive-base); + } + + &:where(.MuiLinearProgress-determinate, .MuiLinearProgress-indeterminate) { + &::before { + content: ""; + position: absolute; + block-size: var(--_MuiLinearProgress-track-thickness); + inset-block-start: calc( + (var(--_MuiLinearProgress-fill-thickness) - var(--_MuiLinearProgress-track-thickness)) * + 0.5 + ); + inset-inline: 0; + background-color: var(--_MuiLinearProgress-color); + border-radius: inherit; + } + } + + &:where(.MuiLinearProgress-buffer, .MuiLinearProgress-determinate) { + &::after { + content: ""; + position: absolute; + inset-inline-end: 0; + inset-block: 0; + aspect-ratio: 1; + background-color: var(--_MuiLinearProgress-color); + border-radius: inherit; + } + } +} + +.MuiLinearProgress-bar { + border-radius: inherit; + background-color: var(--_MuiLinearProgress-color); +} + +.MuiLinearProgress-bar2 { + :where(.MuiLinearProgress-root.MuiLinearProgress-buffer) & { + block-size: var(--_MuiLinearProgress-track-thickness); + inset-block-start: calc( + (var(--_MuiLinearProgress-fill-thickness) - var(--_MuiLinearProgress-track-thickness)) * + 0.5 + ); + } +} + +.MuiLinearProgress-dashed { + display: none; /* We're not using the animated dashed line */ +} diff --git a/packages/mui/src/~createTheme.tsx b/packages/mui/src/~createTheme.tsx index fb6313bc7662..3bba6816d316 100644 --- a/packages/mui/src/~createTheme.tsx +++ b/packages/mui/src/~createTheme.tsx @@ -325,6 +325,12 @@ function createTheme(args: CreateThemeArgs) { }, }, }, + MuiCircularProgress: { + defaultProps: { + enableTrackSlot: true, + thickness: 5, + }, + }, MuiContainer: { defaultProps: { component: Role.div } }, MuiDialog: { defaultProps: { component: Role.div } }, MuiDialogContentText: { diff --git a/packages/mui/src/~forced-colors.css b/packages/mui/src/~forced-colors.css index 2c633b51a5f8..40b20f2fe9c4 100644 --- a/packages/mui/src/~forced-colors.css +++ b/packages/mui/src/~forced-colors.css @@ -114,6 +114,10 @@ } } +.MuiCircularProgress-root { + --_MuiCircularProgress-color: CanvasText; +} + .MuiDialog-paper { border: 1px solid; } @@ -158,11 +162,7 @@ } .MuiLinearProgress-root { - border: 1px solid; -} - -.MuiLinearProgress-bar { - background-color: CanvasText; + --_MuiLinearProgress-color: CanvasText; } .MuiListItemIcon-root {