diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 66c854e71624c0..9c8fbd2556e221 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: os: [macos-latest, windows-latest, ubuntu-latest] steps: - run: echo "${{ github.actor }}" - - uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3.5.0 + - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 with: # fetch all tags which are required for `yarn release:changelog` fetch-depth: 0 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index cce7877cc015d6..f26b3a7062eaee 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -16,10 +16,10 @@ jobs: security-events: write steps: - name: Checkout repository - uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3.5.0 + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@d186a2a36cc67bfa1b860e6170d37fb9634742c7 # v2.2.11 + uses: github/codeql-action/init@b2c19fb9a2a485599ccf4ed5d65527d94bc57226 # v2.3.0 with: languages: typescript config-file: ./.github/codeql/codeql-config.yml @@ -30,4 +30,4 @@ jobs: # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs # queries: security-extended,security-and-quality - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@d186a2a36cc67bfa1b860e6170d37fb9634742c7 # v2.2.11 + uses: github/codeql-action/analyze@b2c19fb9a2a485599ccf4ed5d65527d94bc57226 # v2.3.0 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index f70718ca69bcee..b34828a54bf706 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -22,7 +22,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v3.5.0 + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 with: persist-credentials: false @@ -43,6 +43,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: Upload to code-scanning - uses: github/codeql-action/upload-sarif@d186a2a36cc67bfa1b860e6170d37fb9634742c7 # v2.2.11 + uses: github/codeql-action/upload-sarif@b2c19fb9a2a485599ccf4ed5d65527d94bc57226 # v2.3.0 with: sarif_file: results.sarif diff --git a/CHANGELOG.md b/CHANGELOG.md index be1dd602ae2702..810c550c19494a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,147 @@ # [Versions](https://mui.com/versions/) +## 5.12.2 + + + +_Apr 25, 2023_ + +A big thanks to the 12 contributors who made this release possible. Here are some highlights ✨: + +- ⚠️ **[BREAKING CHANGE]** The `Unstyled` suffix has been removed from Base UI component names, including names of types and other related identifiers – a codemod script is provided to assist with the change. +- 🐛 bug fixes and 📚 documentation improvements. + +### `@mui/material@5.12.2` + +- ​[FormControl] Fix `filled` when value is set through `inputProps` (#36741) @sai6855 +- ​[Slider] `onChange` handler should be called only when value has changed (#36706) @gitstart +- ​[Table] Fix `Sorting & Selecting` tables (#36898) @oliviertassinari + +### `@mui/base@5.0.0-alpha.127` + +#### Breaking changes + +- ​[base] Remove unstyled suffix from Base components + Codemod script (#36873) @hbjORbj + + The `Unstyled` suffix has been removed from all Base UI component names, including names of types and other related identifiers. + + You can use this [codemod](https://github.com/mui/material-ui/blob/master/packages/mui-codemod/src/v5.0.0/base-remove-unstyled-suffix.js) to help with the migration: + + ```sh + npx @mui/codemod v5.0.0/base-remove-unstyled-suffix + ``` + +#### Changes + +- ​[codemod][base] Improve the removal of `component` prop codemod script (#36952) @hbjORbj +- ​[codemod][base] Write a migration script for removal of `component` prop from components (#36831) @hbjORbj +- ​[Base][useButton] Allow useButton params to be completely optional (#36922) @mj12albert + +### `@mui/joy@5.0.0-alpha.77` + +- ​[Joy][Chip] Chip button not showing up in Firefox browser (#36930) @TakhyunKim +- ​[Joy] Add `invertedColors` to Menu and Alert (#36975) @siriwatknp +- ​[joy][Select] Set focus visible on select options when navigating with arrow keys (#36689) @gitstart + +### Docs + +- ​[docs] Fix console error introduced by #36408 (#36980) @alexfauquette +- ​[docs] Add stray Joy UI documentation improvements (#36921) @danilo-leal +- ​[docs] Add Joy profile dashboard template (#36931) @siriwatknp +- ​[docs] Fix 404 links (#36969) @oliviertassinari +- ​[docs] Clarify when bundle size optimization is needed (#36823) @oliviertassinari +- ​[docs] Fix Chakra UI theme scoping typo (#36950) @mj12albert +- ​[docs] Add snackbar example using sonner (#36926) @PupoSDC +- ​[docs] Adjust the Material Icons page design and formatting (#36937) @danilo-leal +- ​[docs] Allows to customize menu with any icon (#36408) @alexfauquette +- ​[docs] Add info about passing ref to input element (#36913) @tomaskebrle +- ​[docs][material] Tabs API section cleanup (#36942) @mnajdova + +### Core + +- ​[core] Fix CI failure on `master` (#37016) @hbjORbj +- ​[typescript] Add the missing explicit component return types (#36924) @michaldudak +- ​[website] Update main data grid demo on X landing page (#37001) @cherniavskii +- ​[website] Design role updates (#36997) @danilo-leal +- ​[website] X component section improvements (#36598) @danilo-leal +- ​[website] Developer Advocate role filled @oliviertassinari + +All contributors of this release in alphabetical order: @alexfauquette, @cherniavskii, @danilo-leal, @gitstart, @hbjORbj, @michaldudak, @mj12albert, @mnajdova, @oliviertassinari, @PupoSDC, @sai6855, @siriwatknp, @TakhyunKim, @tomaskebrle + +## 5.12.1 + + + +_Apr 17, 2023_ + +A big thanks to the 16 contributors who made this release possible. This release was mostly about 🐛 bug fixes and 📚 documentation improvements. + +### `@mui/material@5.12.1` + +- ​[Autocomplete] Fix autocomplete left padding (#36649) @mj12albert +- ​[Button] Fix contained with inherit prop not adapting on dark mode (#34508) @jesrodri +- ​[FormControlLabel] Add `required` prop (#34207) @emlai +- ​[Tabs] Fix null reference in ScrollbarSize after unmounting (#36485) @rkdrnf +- ​[TextField] Fix type error when using `inputTypeSearch` class for `outlined` and `filled` inputs (#36740) @sai6855 +- ​[ThemeProvider] Fix theme proptypes (#36852) @siriwatknp + +### `@mui/system@5.12.1` + +#### Breaking changes + +- ​[Grid2] Replace context with `cloneElement` (#36399) @siriwatknp + + `Grid2` now uses `React.cloneElement` instead of React context for passing the spacing and columns to the next container. The change is close to how CSS flexbox behaves. + +#### Changes + +- ​[CssVarsProvider] Always generate new `css` object (#36853) @siriwatknp + +### `@mui/base@5.0.0-alpha.126` + +#### Breaking changes + +- ​[base] Refactor the compound components building blocks (#36400) @michaldudak + Components affected by the changes are: + - Menu + - `MenuUnstyledContext` is replaced by `MenuProvider`. The value to pass to the provider is returned by the `useMenu` hook. + - MenuUnstyled's `onClose` prop is replaced by `onOpenChange`. It has the `open` parameter and is called when a menu is opened or closed + - Select + - `SelectUnstyledContext` is replaced by `SelectProvider`. The value to pass to the provider is returned by the `useSelect` hook. + - `SelectUnstyled`'s popup is permanently mounted. + - The `defaultOpen` prop was added to the SelectUnstyled. The open/close state can now be controlled or uncontrolled, as a `value`. + - Tabs + - `TabsContext` is replaced by `TabsProvider`. The value to pass to the provider is returned by the `useTabs` hook. + - To deselect all tabs, pass in `null` to Tabs' `value` prop, instead of `false`. This is consistent with how Select works. + - The `value` prop is still technically not mandatory on TabUnstyled and TabPanel, but when omitted, the contents of the selected tab panel will not be rendered during SSR. + +### `@mui/joy@5.0.0-alpha.76` + +- ​[Table][Joy] Replace uses of css selector `*-child` to `*-of-type` (#36839) @keyvanm + +### Docs + +- ​ [docs][base] Move styles to the bottom of demos code for `BadgeUnstyled` (#36723) @varunmulay22 +- ​[docs][base] Mention that the hook does not accept any parameters in the `Parameters` section of the API docs (#36773) @ZeeshanTamboli +- ​[docs][base] Move styles to the bottom of demos code for `ModalUnstyled` (#36580) @gitstart +- ​[docs][base] Move styles to the bottom of demos code for `Tabs` (#36577) @gitstart +- ​[docs][base] Move styles to the bottom of demos code for `Popper` (#36578) @gitstart +- ​[docs][base] Move styles to the bottom of demos code for `TablePagination` (#36593) @gitstart +- ​[docs] Remove the incorrect info about useButton's ref parameter (#36883) @michaldudak +- ​[docs] Sync between projects (#36785) @oliviertassinari +- ​[docs] Add guides to overriding component structure in Base UI and Joy UI docs (#34990) @samuelsycamore +- ​[docs] Content changed from 'row' to 'orientation=horizontal' (#36858) @navedqb +- ​[docs][Joy] `component`, `slots`, `slotProps` must be visible in Prop table in API docs (#36666) @hbjORbj +- ​[docs][Select] Fix duplicate ID in small size Select demo (#36792) @sai6855 + +### Core + +- ​[core] Use glob to find the test files in parseTest (#36305) @flaviendelangle +- ​[core] Fix minor SEO issues @oliviertassinari +- ​[website] Fix visual bug appbar (#36875) @oliviertassinari + +All contributors of this release in alphabetical order: @emlai, @flaviendelangle, @gitstart, @hbjORbj, @jesrodri, @keyvanm, @michaldudak, @mj12albert, @navedqb, @oliviertassinari, @rkdrnf, @sai6855, @samuelsycamore, @siriwatknp, @varunmulay22, @ZeeshanTamboli + ## 5.12.0 diff --git a/benchmark/package.json b/benchmark/package.json index ac436ac8a6ed57..db5a7f7e7325cd 100644 --- a/benchmark/package.json +++ b/benchmark/package.json @@ -15,9 +15,9 @@ "@emotion/react": "^11.10.6", "@emotion/styled": "^11.10.6", "@mdx-js/react": "^2.3.0", - "@mui/material": "^5.12.0", + "@mui/material": "^5.12.2", "@mui/styles": "^5.12.0", - "@mui/system": "^5.12.0", + "@mui/system": "^5.12.1", "@styled-system/css": "^5.1.5", "benchmark": "^2.1.4", "playwright": "^1.31.2", @@ -28,7 +28,7 @@ "react-redux": "^8.0.5", "redux": "^4.2.1", "serve-handler": "^6.1.5", - "styled-components": "^5.3.9", + "styled-components": "^5.3.10", "theme-ui": "^0.15.7", "webpack": "^5.75.0", "webpack-cli": "^4.10.0" diff --git a/docs/.link-check-errors.txt b/docs/.link-check-errors.txt index 4f82b8fd7ece91..f6e9b299140f19 100644 --- a/docs/.link-check-errors.txt +++ b/docs/.link-check-errors.txt @@ -1,4 +1,6 @@ Broken links found by `yarn docs:link-check` that exist: +- https://mui.com/base/react-portal/components-api/#portal - https://mui.com/blog/material-ui-v4-is-out/#premium-themes-store-✨ +- https://mui.com/material-ui/guides/minimizing-bundle-size/#legacy-bundle - https://mui.com/size-snapshot diff --git a/docs/data/base/components/badge/AccessibleBadges.js b/docs/data/base/components/badge/AccessibleBadges.js index 9eb163092ff855..9fed8aea783a01 100644 --- a/docs/data/base/components/badge/AccessibleBadges.js +++ b/docs/data/base/components/badge/AccessibleBadges.js @@ -1,8 +1,27 @@ import * as React from 'react'; import { styled } from '@mui/system'; -import BadgeUnstyled, { badgeUnstyledClasses } from '@mui/base/BadgeUnstyled'; +import Badge, { badgeClasses } from '@mui/base/Badge'; import MailIcon from '@mui/icons-material/Mail'; +function notificationsLabel(count) { + if (count === 0) { + return 'no notifications'; + } + if (count > 99) { + return 'more than 99 notifications'; + } + return `${count} notifications`; +} + +export default function AccessibleBadges() { + return ( +
+ + + +
+ ); +} const blue = { 500: '#007FFF', }; @@ -12,7 +31,7 @@ const grey = { 900: '#24292f', }; -const StyledBadge = styled(BadgeUnstyled)( +const StyledBadge = styled(Badge)( ({ theme }) => ` box-sizing: border-box; margin: 0; @@ -24,7 +43,7 @@ const StyledBadge = styled(BadgeUnstyled)( display: inline-block; line-height: 1; - & .${badgeUnstyledClasses.badge} { + & .${badgeClasses.badge} { z-index: auto; position: absolute; top: 0; @@ -46,23 +65,3 @@ const StyledBadge = styled(BadgeUnstyled)( } `, ); - -function notificationsLabel(count) { - if (count === 0) { - return 'no notifications'; - } - if (count > 99) { - return 'more than 99 notifications'; - } - return `${count} notifications`; -} - -export default function AccessibleBadges() { - return ( -
- - - -
- ); -} diff --git a/docs/data/base/components/badge/AccessibleBadges.tsx b/docs/data/base/components/badge/AccessibleBadges.tsx index 1d6006093cd0d0..916eb4afeae278 100644 --- a/docs/data/base/components/badge/AccessibleBadges.tsx +++ b/docs/data/base/components/badge/AccessibleBadges.tsx @@ -1,8 +1,27 @@ import * as React from 'react'; import { styled } from '@mui/system'; -import BadgeUnstyled, { badgeUnstyledClasses } from '@mui/base/BadgeUnstyled'; +import Badge, { badgeClasses } from '@mui/base/Badge'; import MailIcon from '@mui/icons-material/Mail'; +function notificationsLabel(count: number) { + if (count === 0) { + return 'no notifications'; + } + if (count > 99) { + return 'more than 99 notifications'; + } + return `${count} notifications`; +} + +export default function AccessibleBadges() { + return ( +
+ + + +
+ ); +} const blue = { 500: '#007FFF', }; @@ -12,7 +31,7 @@ const grey = { 900: '#24292f', }; -const StyledBadge = styled(BadgeUnstyled)( +const StyledBadge = styled(Badge)( ({ theme }) => ` box-sizing: border-box; margin: 0; @@ -24,7 +43,7 @@ const StyledBadge = styled(BadgeUnstyled)( display: inline-block; line-height: 1; - & .${badgeUnstyledClasses.badge} { + & .${badgeClasses.badge} { z-index: auto; position: absolute; top: 0; @@ -46,23 +65,3 @@ const StyledBadge = styled(BadgeUnstyled)( } `, ); - -function notificationsLabel(count: number) { - if (count === 0) { - return 'no notifications'; - } - if (count > 99) { - return 'more than 99 notifications'; - } - return `${count} notifications`; -} - -export default function AccessibleBadges() { - return ( -
- - - -
- ); -} diff --git a/docs/data/base/components/badge/BadgeMax.js b/docs/data/base/components/badge/BadgeMax.js index df0553434f79f8..90b5a24ac4ff68 100644 --- a/docs/data/base/components/badge/BadgeMax.js +++ b/docs/data/base/components/badge/BadgeMax.js @@ -1,9 +1,24 @@ import * as React from 'react'; import Stack from '@mui/material/Stack'; import { styled } from '@mui/system'; -import BadgeUnstyled, { badgeUnstyledClasses } from '@mui/base/BadgeUnstyled'; +import Badge, { badgeClasses } from '@mui/base/Badge'; import MailIcon from '@mui/icons-material/Mail'; +export default function BadgeMax() { + return ( + + + + + + + + + + + + ); +} const blue = { 500: '#007FFF', }; @@ -13,7 +28,7 @@ const grey = { 900: '#24292f', }; -const StyledBadge = styled(BadgeUnstyled)( +const StyledBadge = styled(Badge)( ({ theme }) => ` box-sizing: border-box; margin: 0; @@ -25,7 +40,7 @@ const StyledBadge = styled(BadgeUnstyled)( display: inline-block; line-height: 1; - & .${badgeUnstyledClasses.badge} { + & .${badgeClasses.badge} { z-index: auto; position: absolute; top: 0; @@ -47,19 +62,3 @@ const StyledBadge = styled(BadgeUnstyled)( } `, ); - -export default function BadgeMax() { - return ( - - - - - - - - - - - - ); -} diff --git a/docs/data/base/components/badge/BadgeMax.tsx b/docs/data/base/components/badge/BadgeMax.tsx index df0553434f79f8..90b5a24ac4ff68 100644 --- a/docs/data/base/components/badge/BadgeMax.tsx +++ b/docs/data/base/components/badge/BadgeMax.tsx @@ -1,9 +1,24 @@ import * as React from 'react'; import Stack from '@mui/material/Stack'; import { styled } from '@mui/system'; -import BadgeUnstyled, { badgeUnstyledClasses } from '@mui/base/BadgeUnstyled'; +import Badge, { badgeClasses } from '@mui/base/Badge'; import MailIcon from '@mui/icons-material/Mail'; +export default function BadgeMax() { + return ( + + + + + + + + + + + + ); +} const blue = { 500: '#007FFF', }; @@ -13,7 +28,7 @@ const grey = { 900: '#24292f', }; -const StyledBadge = styled(BadgeUnstyled)( +const StyledBadge = styled(Badge)( ({ theme }) => ` box-sizing: border-box; margin: 0; @@ -25,7 +40,7 @@ const StyledBadge = styled(BadgeUnstyled)( display: inline-block; line-height: 1; - & .${badgeUnstyledClasses.badge} { + & .${badgeClasses.badge} { z-index: auto; position: absolute; top: 0; @@ -47,19 +62,3 @@ const StyledBadge = styled(BadgeUnstyled)( } `, ); - -export default function BadgeMax() { - return ( - - - - - - - - - - - - ); -} diff --git a/docs/data/base/components/badge/BadgeVisibility.js b/docs/data/base/components/badge/BadgeVisibility.js index 9cf0cb40f4b627..254d91ecbf5538 100644 --- a/docs/data/base/components/badge/BadgeVisibility.js +++ b/docs/data/base/components/badge/BadgeVisibility.js @@ -1,7 +1,7 @@ import * as React from 'react'; import Box from '@mui/material/Box'; import { styled } from '@mui/system'; -import BadgeUnstyled, { badgeUnstyledClasses } from '@mui/base/BadgeUnstyled'; +import Badge, { badgeClasses } from '@mui/base/Badge'; import ButtonGroup from '@mui/material/ButtonGroup'; import Button from '@mui/material/Button'; import AddIcon from '@mui/icons-material/Add'; @@ -10,55 +10,6 @@ import MailIcon from '@mui/icons-material/Mail'; import Switch from '@mui/material/Switch'; import FormControlLabel from '@mui/material/FormControlLabel'; -const blue = { - 500: '#007FFF', -}; - -const grey = { - 300: '#afb8c1', - 900: '#24292f', -}; - -const StyledBadge = styled(BadgeUnstyled)( - ({ theme }) => ` - box-sizing: border-box; - margin: 0; - padding: 0; - font-size: 14px; - list-style: none; - font-family: IBM Plex Sans, sans-serif; - position: relative; - display: inline-block; - line-height: 1; - - & .${badgeUnstyledClasses.badge} { - z-index: auto; - position: absolute; - top: 0; - right: 0; - min-width: 22px; - height: 22px; - padding: 0 6px; - color: #fff; - font-weight: 600; - font-size: 12px; - line-height: 22px; - white-space: nowrap; - text-align: center; - border-radius: 12px; - background: ${blue[500]}; - box-shadow: 0px 4px 6x ${theme.palette.mode === 'dark' ? grey[900] : grey[300]}; - transform: translate(50%, -50%); - transform-origin: 100% 0; - } - - & .${badgeUnstyledClasses.invisible} { - opacity: 0; - pointer-events: none; - } - `, -); - export default function BadgeVisibility() { const [count, setCount] = React.useState(1); const [invisible, setInvisible] = React.useState(false); @@ -76,7 +27,7 @@ export default function BadgeVisibility() { '& > *': { marginBottom: 2, }, - [`& .${badgeUnstyledClasses.root}`]: { + [`& .${badgeClasses.root}`]: { marginRight: 4, }, }} @@ -117,3 +68,51 @@ export default function BadgeVisibility() { ); } +const blue = { + 500: '#007FFF', +}; + +const grey = { + 300: '#afb8c1', + 900: '#24292f', +}; + +const StyledBadge = styled(Badge)( + ({ theme }) => ` + box-sizing: border-box; + margin: 0; + padding: 0; + font-size: 14px; + list-style: none; + font-family: IBM Plex Sans, sans-serif; + position: relative; + display: inline-block; + line-height: 1; + + & .${badgeClasses.badge} { + z-index: auto; + position: absolute; + top: 0; + right: 0; + min-width: 22px; + height: 22px; + padding: 0 6px; + color: #fff; + font-weight: 600; + font-size: 12px; + line-height: 22px; + white-space: nowrap; + text-align: center; + border-radius: 12px; + background: ${blue[500]}; + box-shadow: 0px 4px 6x ${theme.palette.mode === 'dark' ? grey[900] : grey[300]}; + transform: translate(50%, -50%); + transform-origin: 100% 0; + } + + & .${badgeClasses.invisible} { + opacity: 0; + pointer-events: none; + } + `, +); diff --git a/docs/data/base/components/badge/BadgeVisibility.tsx b/docs/data/base/components/badge/BadgeVisibility.tsx index 9cf0cb40f4b627..254d91ecbf5538 100644 --- a/docs/data/base/components/badge/BadgeVisibility.tsx +++ b/docs/data/base/components/badge/BadgeVisibility.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import Box from '@mui/material/Box'; import { styled } from '@mui/system'; -import BadgeUnstyled, { badgeUnstyledClasses } from '@mui/base/BadgeUnstyled'; +import Badge, { badgeClasses } from '@mui/base/Badge'; import ButtonGroup from '@mui/material/ButtonGroup'; import Button from '@mui/material/Button'; import AddIcon from '@mui/icons-material/Add'; @@ -10,55 +10,6 @@ import MailIcon from '@mui/icons-material/Mail'; import Switch from '@mui/material/Switch'; import FormControlLabel from '@mui/material/FormControlLabel'; -const blue = { - 500: '#007FFF', -}; - -const grey = { - 300: '#afb8c1', - 900: '#24292f', -}; - -const StyledBadge = styled(BadgeUnstyled)( - ({ theme }) => ` - box-sizing: border-box; - margin: 0; - padding: 0; - font-size: 14px; - list-style: none; - font-family: IBM Plex Sans, sans-serif; - position: relative; - display: inline-block; - line-height: 1; - - & .${badgeUnstyledClasses.badge} { - z-index: auto; - position: absolute; - top: 0; - right: 0; - min-width: 22px; - height: 22px; - padding: 0 6px; - color: #fff; - font-weight: 600; - font-size: 12px; - line-height: 22px; - white-space: nowrap; - text-align: center; - border-radius: 12px; - background: ${blue[500]}; - box-shadow: 0px 4px 6x ${theme.palette.mode === 'dark' ? grey[900] : grey[300]}; - transform: translate(50%, -50%); - transform-origin: 100% 0; - } - - & .${badgeUnstyledClasses.invisible} { - opacity: 0; - pointer-events: none; - } - `, -); - export default function BadgeVisibility() { const [count, setCount] = React.useState(1); const [invisible, setInvisible] = React.useState(false); @@ -76,7 +27,7 @@ export default function BadgeVisibility() { '& > *': { marginBottom: 2, }, - [`& .${badgeUnstyledClasses.root}`]: { + [`& .${badgeClasses.root}`]: { marginRight: 4, }, }} @@ -117,3 +68,51 @@ export default function BadgeVisibility() { ); } +const blue = { + 500: '#007FFF', +}; + +const grey = { + 300: '#afb8c1', + 900: '#24292f', +}; + +const StyledBadge = styled(Badge)( + ({ theme }) => ` + box-sizing: border-box; + margin: 0; + padding: 0; + font-size: 14px; + list-style: none; + font-family: IBM Plex Sans, sans-serif; + position: relative; + display: inline-block; + line-height: 1; + + & .${badgeClasses.badge} { + z-index: auto; + position: absolute; + top: 0; + right: 0; + min-width: 22px; + height: 22px; + padding: 0 6px; + color: #fff; + font-weight: 600; + font-size: 12px; + line-height: 22px; + white-space: nowrap; + text-align: center; + border-radius: 12px; + background: ${blue[500]}; + box-shadow: 0px 4px 6x ${theme.palette.mode === 'dark' ? grey[900] : grey[300]}; + transform: translate(50%, -50%); + transform-origin: 100% 0; + } + + & .${badgeClasses.invisible} { + opacity: 0; + pointer-events: none; + } + `, +); diff --git a/docs/data/base/components/badge/ShowZeroBadge.js b/docs/data/base/components/badge/ShowZeroBadge.js index 67d776c969e496..4982c5a6461bc1 100644 --- a/docs/data/base/components/badge/ShowZeroBadge.js +++ b/docs/data/base/components/badge/ShowZeroBadge.js @@ -1,9 +1,22 @@ import * as React from 'react'; import Stack from '@mui/material/Stack'; import { styled } from '@mui/system'; -import BadgeUnstyled, { badgeUnstyledClasses } from '@mui/base/BadgeUnstyled'; +import Badge, { badgeClasses } from '@mui/base/Badge'; import MailIcon from '@mui/icons-material/Mail'; +export default function ShowZeroBadge() { + return ( + + + + + + + + + ); +} + const blue = { 500: '#007FFF', }; @@ -13,7 +26,7 @@ const grey = { 900: '#24292f', }; -const StyledBadge = styled(BadgeUnstyled)( +const StyledBadge = styled(Badge)( ({ theme }) => ` box-sizing: border-box; margin: 0; @@ -25,7 +38,7 @@ const StyledBadge = styled(BadgeUnstyled)( display: inline-block; line-height: 1; - & .${badgeUnstyledClasses.badge} { + & .${badgeClasses.badge} { z-index: auto; position: absolute; top: 0; @@ -46,21 +59,8 @@ const StyledBadge = styled(BadgeUnstyled)( transform-origin: 100% 0; } - & .${badgeUnstyledClasses.invisible} { + & .${badgeClasses.invisible} { display: none; } `, ); - -export default function ShowZeroBadge() { - return ( - - - - - - - - - ); -} diff --git a/docs/data/base/components/badge/ShowZeroBadge.tsx b/docs/data/base/components/badge/ShowZeroBadge.tsx index 67d776c969e496..4982c5a6461bc1 100644 --- a/docs/data/base/components/badge/ShowZeroBadge.tsx +++ b/docs/data/base/components/badge/ShowZeroBadge.tsx @@ -1,9 +1,22 @@ import * as React from 'react'; import Stack from '@mui/material/Stack'; import { styled } from '@mui/system'; -import BadgeUnstyled, { badgeUnstyledClasses } from '@mui/base/BadgeUnstyled'; +import Badge, { badgeClasses } from '@mui/base/Badge'; import MailIcon from '@mui/icons-material/Mail'; +export default function ShowZeroBadge() { + return ( + + + + + + + + + ); +} + const blue = { 500: '#007FFF', }; @@ -13,7 +26,7 @@ const grey = { 900: '#24292f', }; -const StyledBadge = styled(BadgeUnstyled)( +const StyledBadge = styled(Badge)( ({ theme }) => ` box-sizing: border-box; margin: 0; @@ -25,7 +38,7 @@ const StyledBadge = styled(BadgeUnstyled)( display: inline-block; line-height: 1; - & .${badgeUnstyledClasses.badge} { + & .${badgeClasses.badge} { z-index: auto; position: absolute; top: 0; @@ -46,21 +59,8 @@ const StyledBadge = styled(BadgeUnstyled)( transform-origin: 100% 0; } - & .${badgeUnstyledClasses.invisible} { + & .${badgeClasses.invisible} { display: none; } `, ); - -export default function ShowZeroBadge() { - return ( - - - - - - - - - ); -} diff --git a/docs/data/base/components/badge/UnstyledBadge.js b/docs/data/base/components/badge/UnstyledBadge.js index 7ad760e63bf762..13358f49052d19 100644 --- a/docs/data/base/components/badge/UnstyledBadge.js +++ b/docs/data/base/components/badge/UnstyledBadge.js @@ -1,6 +1,31 @@ import * as React from 'react'; import { styled, Box } from '@mui/system'; -import BadgeUnstyled, { badgeUnstyledClasses } from '@mui/base/BadgeUnstyled'; +import Badge, { badgeClasses } from '@mui/base/Badge'; + +function BadgeContent() { + return ( + + theme.palette.mode === 'dark' ? grey[400] : grey[300], + display: 'inline-block', + verticalAlign: 'middle', + }} + /> + ); +} + +export default function UnstyledBadge() { + return ( + + + + ); +} const blue = { 500: '#007FFF', @@ -12,7 +37,7 @@ const grey = { 900: '#24292f', }; -const StyledBadge = styled(BadgeUnstyled)( +const StyledBadge = styled(Badge)( ({ theme }) => ` box-sizing: border-box; margin: 0; @@ -25,7 +50,7 @@ const StyledBadge = styled(BadgeUnstyled)( display: inline-block; line-height: 1; - & .${badgeUnstyledClasses.badge} { + & .${badgeClasses.badge} { z-index: auto; position: absolute; top: 0; @@ -47,28 +72,3 @@ const StyledBadge = styled(BadgeUnstyled)( } `, ); - -function BadgeContent() { - return ( - - theme.palette.mode === 'dark' ? grey[400] : grey[300], - display: 'inline-block', - verticalAlign: 'middle', - }} - /> - ); -} - -export default function UnstyledBadge() { - return ( - - - - ); -} diff --git a/docs/data/base/components/badge/UnstyledBadge.tsx b/docs/data/base/components/badge/UnstyledBadge.tsx index 7ad760e63bf762..13358f49052d19 100644 --- a/docs/data/base/components/badge/UnstyledBadge.tsx +++ b/docs/data/base/components/badge/UnstyledBadge.tsx @@ -1,6 +1,31 @@ import * as React from 'react'; import { styled, Box } from '@mui/system'; -import BadgeUnstyled, { badgeUnstyledClasses } from '@mui/base/BadgeUnstyled'; +import Badge, { badgeClasses } from '@mui/base/Badge'; + +function BadgeContent() { + return ( + + theme.palette.mode === 'dark' ? grey[400] : grey[300], + display: 'inline-block', + verticalAlign: 'middle', + }} + /> + ); +} + +export default function UnstyledBadge() { + return ( + + + + ); +} const blue = { 500: '#007FFF', @@ -12,7 +37,7 @@ const grey = { 900: '#24292f', }; -const StyledBadge = styled(BadgeUnstyled)( +const StyledBadge = styled(Badge)( ({ theme }) => ` box-sizing: border-box; margin: 0; @@ -25,7 +50,7 @@ const StyledBadge = styled(BadgeUnstyled)( display: inline-block; line-height: 1; - & .${badgeUnstyledClasses.badge} { + & .${badgeClasses.badge} { z-index: auto; position: absolute; top: 0; @@ -47,28 +72,3 @@ const StyledBadge = styled(BadgeUnstyled)( } `, ); - -function BadgeContent() { - return ( - - theme.palette.mode === 'dark' ? grey[400] : grey[300], - display: 'inline-block', - verticalAlign: 'middle', - }} - /> - ); -} - -export default function UnstyledBadge() { - return ( - - - - ); -} diff --git a/docs/data/base/components/badge/UnstyledBadgeIntroduction.js b/docs/data/base/components/badge/UnstyledBadgeIntroduction.js index cb3aba3d7eb4e8..b05ce3e7c2b501 100644 --- a/docs/data/base/components/badge/UnstyledBadgeIntroduction.js +++ b/docs/data/base/components/badge/UnstyledBadgeIntroduction.js @@ -1,6 +1,31 @@ import * as React from 'react'; import { styled, Box } from '@mui/system'; -import BadgeUnstyled, { badgeUnstyledClasses } from '@mui/base/BadgeUnstyled'; +import Badge, { badgeClasses } from '@mui/base/Badge'; + +function BadgeContent() { + return ( + + theme.palette.mode === 'dark' ? grey[400] : grey[300], + display: 'inline-block', + verticalAlign: 'middle', + }} + /> + ); +} + +export default function UnstyledBadgeIntroduction() { + return ( + + + + ); +} const blue = { 500: '#007FFF', @@ -12,7 +37,7 @@ const grey = { 900: '#24292f', }; -const StyledBadge = styled(BadgeUnstyled)( +const StyledBadge = styled(Badge)( ({ theme }) => ` box-sizing: border-box; margin: 0; @@ -25,7 +50,7 @@ const StyledBadge = styled(BadgeUnstyled)( display: inline-block; line-height: 1; - & .${badgeUnstyledClasses.badge} { + & .${badgeClasses.badge} { z-index: auto; position: absolute; top: 0; @@ -49,28 +74,3 @@ const StyledBadge = styled(BadgeUnstyled)( } `, ); - -function BadgeContent() { - return ( - - theme.palette.mode === 'dark' ? grey[400] : grey[300], - display: 'inline-block', - verticalAlign: 'middle', - }} - /> - ); -} - -export default function UnstyledBadgeIntroduction() { - return ( - - - - ); -} diff --git a/docs/data/base/components/badge/UnstyledBadgeIntroduction.tsx b/docs/data/base/components/badge/UnstyledBadgeIntroduction.tsx index cb3aba3d7eb4e8..b05ce3e7c2b501 100644 --- a/docs/data/base/components/badge/UnstyledBadgeIntroduction.tsx +++ b/docs/data/base/components/badge/UnstyledBadgeIntroduction.tsx @@ -1,6 +1,31 @@ import * as React from 'react'; import { styled, Box } from '@mui/system'; -import BadgeUnstyled, { badgeUnstyledClasses } from '@mui/base/BadgeUnstyled'; +import Badge, { badgeClasses } from '@mui/base/Badge'; + +function BadgeContent() { + return ( + + theme.palette.mode === 'dark' ? grey[400] : grey[300], + display: 'inline-block', + verticalAlign: 'middle', + }} + /> + ); +} + +export default function UnstyledBadgeIntroduction() { + return ( + + + + ); +} const blue = { 500: '#007FFF', @@ -12,7 +37,7 @@ const grey = { 900: '#24292f', }; -const StyledBadge = styled(BadgeUnstyled)( +const StyledBadge = styled(Badge)( ({ theme }) => ` box-sizing: border-box; margin: 0; @@ -25,7 +50,7 @@ const StyledBadge = styled(BadgeUnstyled)( display: inline-block; line-height: 1; - & .${badgeUnstyledClasses.badge} { + & .${badgeClasses.badge} { z-index: auto; position: absolute; top: 0; @@ -49,28 +74,3 @@ const StyledBadge = styled(BadgeUnstyled)( } `, ); - -function BadgeContent() { - return ( - - theme.palette.mode === 'dark' ? grey[400] : grey[300], - display: 'inline-block', - verticalAlign: 'middle', - }} - /> - ); -} - -export default function UnstyledBadgeIntroduction() { - return ( - - - - ); -} diff --git a/docs/data/base/components/badge/badge.md b/docs/data/base/components/badge/badge.md index 3243a5ea0fe1d6..ec65a62c88a7c8 100644 --- a/docs/data/base/components/badge/badge.md +++ b/docs/data/base/components/badge/badge.md @@ -1,14 +1,14 @@ --- product: base -title: Unstyled React Badge component and hook -components: BadgeUnstyled +title: React Badge component and hook +components: Badge hooks: useBadge githubLabel: 'component: badge' --- -# Unstyled badge +# Badge -

The Unstyled Badge component generates a small label that is attached to its child element.

+

The Badge component generates a small label that is attached to its child element.

{{"component": "modules/components/ComponentLinkHeader.js", "design": false}} @@ -19,7 +19,7 @@ githubLabel: 'component: badge' A badge is a small descriptor for UI elements. It typically sits on or near an element and indicates the status of that element by displaying a number, icon, or other short set of characters. -The Unstyled Badge component creates a badge that is applied to its child element. +The Badge component creates a badge that is applied to its child element. {{"demo": "UnstyledBadgeIntroduction.js", "defaultCodeOpen": false, "bg": "gradient"}} @@ -30,29 +30,27 @@ The Unstyled Badge component creates a badge that is applied to its child elemen After [installation](/base/getting-started/installation/), you can start building with this component using the following basic elements: ```jsx -import BadgeUnstyled from '@mui/base/BadgeUnstyled'; +import Badge from '@mui/base/Badge'; export default function MyApp() { - return ( - {/* the element that the badge is attached to */} - ); + return {/* the element that the badge is attached to */}; } ``` ### Basics -The Unstyled Badge wraps around the UI element that it's attached to. +The Badge wraps around the UI element that it's attached to. For instance, if the badge indicates the number of emails in an inbox, then the component will be structured like this: ```jsx - + - + ``` ### Anatomy -The Unstyled Badge component is composed of a root `` that houses the element that the badge is attached to, followed by a `` slot to represent the badge itself: +The Badge component is composed of a root `` that houses the element that the badge is attached to, followed by a `` slot to represent the badge itself: ```html @@ -61,34 +59,38 @@ The Unstyled Badge component is composed of a root `` that houses the elem ``` -### Slot props +### Custom structure + +Use the `slots` prop to override the root or any other interior slot: + +```jsx + +``` :::info -The following props are available on all non-utility Base components. -See [Usage](/base/getting-started/usage/) for full details. +The `slots` prop is available on all non-utility Base components. +See [Overriding component structure](/base/guides/overriding-component-structure/) for full details. ::: -Use the `component` prop to override the root slot with a custom element: +Use the `slotProps` prop to pass custom props to internal slots. +The following code snippet applies a CSS class called `my-badge` to the badge slot: ```jsx - + ``` -Use the `slots` prop to override any interior slots in addition to the root: +#### Usage with TypeScript -```jsx - -``` +In TypeScript, you can specify the custom component type used in the `slots.root` as a generic parameter of the unstyled component. This way, you can safely provide the custom root's props directly on the component: -:::warning -If the root element is customized with both the `component` and `slots` props, then `component` will take precedence. -::: +```tsx + slots={{ root: CustomComponent }} customProp /> +``` -Use the `slotProps` prop to pass custom props to internal slots. -The following code snippet applies a CSS class called `my-badge` to the badge slot: +The same applies for props specific to custom primitive elements: -```jsx - +```tsx + slots={{ root: 'img' }} src="badge.png" /> ``` ## Hook diff --git a/docs/data/base/components/button/UnstyledButtonCustom.js b/docs/data/base/components/button/UnstyledButtonCustom.js index 7ebad32a539b62..629ed5a0f2d9f2 100644 --- a/docs/data/base/components/button/UnstyledButtonCustom.js +++ b/docs/data/base/components/button/UnstyledButtonCustom.js @@ -1,6 +1,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import ButtonUnstyled, { buttonUnstyledClasses } from '@mui/base/ButtonUnstyled'; +import Button, { buttonClasses } from '@mui/base/Button'; import { styled } from '@mui/system'; const ButtonRoot = React.forwardRef(function ButtonRoot(props, ref) { @@ -22,7 +22,7 @@ ButtonRoot.propTypes = { }; const SvgButton = React.forwardRef(function SvgButton(props, ref) { - return ; + return ; } ``` ### Basics -The Unstyled Button behaves similar to the native HTML ` ``` -### Slot props +### Custom structure -:::info -The following props are available on all non-utility Base components. -See [Usage](/base/getting-started/usage/) for full details. -::: - -Use the `component` prop to override the root slot with a custom element: +Use the `slots.root` prop to override the root slot with a custom element: ```jsx - + - + ``` -The following demo shows how to create and style a form that uses Unstyled Form Control to wrap the elements of the form. -Note that it also uses the `useFormControlUnstyledContext` hook in order to pass props to the custom Unstyled Input—see the [Hook](#hook) section below for more details. +The following demo shows how to create and style a form that uses Form Control to wrap the elements of the form. +Note that it also uses the `useFormControlContext` hook in order to pass props to the custom Input—see the [Hook](#hook) section below for more details. {{"demo": "BasicFormControl.js"}} +#### Usage with TypeScript + +In TypeScript, you can specify the custom component type used in the `slots.root` as a generic parameter of the unstyled component. This way, you can safely provide the custom root's props directly on the component: + +```tsx + slots={{ root: CustomComponent }} customProp /> +``` + +The same applies for props specific to custom primitive elements: + +```tsx + slots={{ root: 'button' }} onClick={() => {}} /> +``` + ## Hook ```jsx -import { useFormControlUnstyledContext } from '@mui/base/FormControlUnstyled'; +import { useFormControlContext } from '@mui/base/FormControl'; ``` -The `useFormControlUnstyledContext` hook reads the context provided by Unstyled Form Control. +The `useFormControlContext` hook reads the context provided by Form Control. This hook lets you work with custom input components inside of the Form Control. You can also use it to read the form control's state and react to its changes in a custom component. @@ -82,27 +94,8 @@ The demo below shows how to integrate this hook with its component counterpart: {{"demo": "UseFormControl.js", "defaultCodeOpen": false}} Note that even though Form Control supports both controlled and uncontrolled-style APIs -(i.e. it accepts `value` and `defaultValue` props), `useFormControlUnstyledContext` returns only the controlled `value`. -This way, you don't have to implement both in your custom input—Unstyled Form Control does this for you. - -`useFormControlUnstyledContext` returns an object with the following fields: - -| Name | Type | Description | -| :--------- | :------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `disabled` | boolean | Represents the value of the FormControlUnstyled's `disabled` prop. | -| `error` | boolean | Represents the value of the Unstyled Form Control component's `error` prop. Note that it is not calculated automatically (i.e. it's not set when `required: true` and `value: ''`). | -| `filled` | boolean | Set to `true` if `value` is not empty. | -| `focused` | boolean | Set to `true` if the wrapped input has received focus. | -| `required` | boolean | Represents the value of the Unstyled Form Control component's `required` prop. | -| `value` | unknown | The current value of the form control. | - -The following callbacks are also part of the returned object—they are meant to be used when creating custom inputs: - -| Name | Type | Description | -| :--------- | :------------------------ | :------------------------------------------------------------ | -| `onChange` | React.ChangeEvent => void | Value change handler. Should be forwarded to the inner input. | -| `onBlur` | () => void | Focus change handler. Should be forwarded to the inner input. | -| `onFocus` | () => void | Focus change handler. Should be forwarded to the inner input. | +(i.e. it accepts `value` and `defaultValue` props), `useFormControlContext` returns only the controlled `value`. +This way, you don't have to implement both in your custom input—Form Control does this for you. ## Customization @@ -116,6 +109,6 @@ For the sake of simplicity, demos and code snippets primarily feature components You can access the state of the form control by providing a function as a child of the Form Control. The state will be provided as a parameter to this function. -The following demo shows how to access the state of the form control in an Unstyled Input component nested inside of the Form Control: +The following demo shows how to access the state of the form control in an Input component nested inside of the Form Control: {{"demo": "FormControlFunctionChild.js"}} diff --git a/docs/data/base/components/input/InputAdornments.js b/docs/data/base/components/input/InputAdornments.js index 65d35f210cdcbf..71e3963941b019 100644 --- a/docs/data/base/components/input/InputAdornments.js +++ b/docs/data/base/components/input/InputAdornments.js @@ -1,12 +1,91 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import Box from '@mui/material/Box'; -import ButtonUnstyled from '@mui/base/ButtonUnstyled'; -import InputUnstyled, { inputUnstyledClasses } from '@mui/base/InputUnstyled'; +import Button from '@mui/base/Button'; +import Input, { inputClasses } from '@mui/base/Input'; import Visibility from '@mui/icons-material/Visibility'; import VisibilityOff from '@mui/icons-material/VisibilityOff'; import { styled } from '@mui/system'; +const CustomInput = React.forwardRef(function CustomInput(props, ref) { + const { slots, ...other } = props; + return ( + + ); +}); + +CustomInput.propTypes = { + /** + * The components used for each slot inside the InputBase. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes.shape({ + input: PropTypes.elementType, + root: PropTypes.elementType, + textarea: PropTypes.elementType, + }), +}; + +export default function InputAdornments() { + const [values, setValues] = React.useState({ + amount: '', + password: '', + weight: '', + weightRange: '', + showPassword: false, + }); + + const handleChange = (prop) => (event) => { + setValues({ ...values, [prop]: event.target.value }); + }; + + const handleClickShowPassword = () => { + setValues({ + ...values, + showPassword: !values.showPassword, + }); + }; + + const handleMouseDownPassword = (event) => { + event.preventDefault(); + }; + + return ( + * + *': { ml: 1 } }}> + kg} + /> + + + {values.showPassword ? : } + + + } + /> + + ); +} + const blue = { 100: '#DAECFF', 200: '#80BFFF', @@ -42,7 +121,7 @@ const StyledInputRoot = styled('div')( justify-content: center; - &.${inputUnstyledClasses.focused} { + &.${inputClasses.focused} { border-color: ${blue[400]}; box-shadow: 0 0 0 3px ${theme.palette.mode === 'dark' ? blue[500] : blue[200]}; } @@ -74,7 +153,7 @@ const StyledInputElement = styled('input')( `, ); -const IconButton = styled(ButtonUnstyled)( +const IconButton = styled(Button)( ({ theme }) => ` display: inline-flex; align-items: center; @@ -92,82 +171,3 @@ const InputAdornment = styled('div')` align-items: center; justify-content: center; `; - -const CustomInput = React.forwardRef(function CustomInput(props, ref) { - const { slots, ...other } = props; - return ( - - ); -}); - -CustomInput.propTypes = { - /** - * The components used for each slot inside the InputBase. - * Either a string to use a HTML element or a component. - * @default {} - */ - slots: PropTypes.shape({ - input: PropTypes.elementType, - root: PropTypes.elementType, - textarea: PropTypes.elementType, - }), -}; - -export default function InputAdornments() { - const [values, setValues] = React.useState({ - amount: '', - password: '', - weight: '', - weightRange: '', - showPassword: false, - }); - - const handleChange = (prop) => (event) => { - setValues({ ...values, [prop]: event.target.value }); - }; - - const handleClickShowPassword = () => { - setValues({ - ...values, - showPassword: !values.showPassword, - }); - }; - - const handleMouseDownPassword = (event) => { - event.preventDefault(); - }; - - return ( - * + *': { ml: 1 } }}> - kg} - /> - - - {values.showPassword ? : } - - - } - /> - - ); -} diff --git a/docs/data/base/components/input/InputAdornments.tsx b/docs/data/base/components/input/InputAdornments.tsx index 34dee6fcf652ff..808931cc4476d6 100644 --- a/docs/data/base/components/input/InputAdornments.tsx +++ b/docs/data/base/components/input/InputAdornments.tsx @@ -1,14 +1,89 @@ import * as React from 'react'; import Box from '@mui/material/Box'; -import ButtonUnstyled from '@mui/base/ButtonUnstyled'; -import InputUnstyled, { - InputUnstyledProps, - inputUnstyledClasses, -} from '@mui/base/InputUnstyled'; +import Button from '@mui/base/Button'; +import Input, { InputProps, inputClasses } from '@mui/base/Input'; import Visibility from '@mui/icons-material/Visibility'; import VisibilityOff from '@mui/icons-material/VisibilityOff'; import { styled } from '@mui/system'; +const CustomInput = React.forwardRef(function CustomInput( + props: InputProps, + ref: React.ForwardedRef, +) { + const { slots, ...other } = props; + return ( + + ); +}); + +interface State { + amount: string; + password: string; + weight: string; + weightRange: string; + showPassword: boolean; +} + +export default function InputAdornments() { + const [values, setValues] = React.useState({ + amount: '', + password: '', + weight: '', + weightRange: '', + showPassword: false, + }); + + const handleChange = + (prop: keyof State) => (event: React.ChangeEvent) => { + setValues({ ...values, [prop]: event.target.value }); + }; + + const handleClickShowPassword = () => { + setValues({ + ...values, + showPassword: !values.showPassword, + }); + }; + + const handleMouseDownPassword = (event: React.MouseEvent) => { + event.preventDefault(); + }; + + return ( + * + *': { ml: 1 } }}> + kg} + /> + + + {values.showPassword ? : } + + + } + /> + + ); +} + const blue = { 100: '#DAECFF', 200: '#80BFFF', @@ -44,7 +119,7 @@ const StyledInputRoot = styled('div')( justify-content: center; - &.${inputUnstyledClasses.focused} { + &.${inputClasses.focused} { border-color: ${blue[400]}; box-shadow: 0 0 0 3px ${theme.palette.mode === 'dark' ? blue[500] : blue[200]}; } @@ -76,7 +151,7 @@ const StyledInputElement = styled('input')( `, ); -const IconButton = styled(ButtonUnstyled)( +const IconButton = styled(Button)( ({ theme }) => ` display: inline-flex; align-items: center; @@ -94,81 +169,3 @@ const InputAdornment = styled('div')` align-items: center; justify-content: center; `; - -const CustomInput = React.forwardRef(function CustomInput( - props: InputUnstyledProps, - ref: React.ForwardedRef, -) { - const { slots, ...other } = props; - return ( - - ); -}); - -interface State { - amount: string; - password: string; - weight: string; - weightRange: string; - showPassword: boolean; -} - -export default function InputAdornments() { - const [values, setValues] = React.useState({ - amount: '', - password: '', - weight: '', - weightRange: '', - showPassword: false, - }); - - const handleChange = - (prop: keyof State) => (event: React.ChangeEvent) => { - setValues({ ...values, [prop]: event.target.value }); - }; - - const handleClickShowPassword = () => { - setValues({ - ...values, - showPassword: !values.showPassword, - }); - }; - - const handleMouseDownPassword = (event: React.MouseEvent) => { - event.preventDefault(); - }; - - return ( - * + *': { ml: 1 } }}> - kg} - /> - - - {values.showPassword ? : } - - - } - /> - - ); -} diff --git a/docs/data/base/components/input/InputMultiline.js b/docs/data/base/components/input/InputMultiline.js index f0cf031bd3854d..12af43e924dfe3 100644 --- a/docs/data/base/components/input/InputMultiline.js +++ b/docs/data/base/components/input/InputMultiline.js @@ -1,7 +1,23 @@ import * as React from 'react'; -import InputUnstyled from '@mui/base/InputUnstyled'; +import Input from '@mui/base/Input'; import { styled } from '@mui/system'; +const CustomInput = React.forwardRef(function CustomInput(props, ref) { + return ( + + ); +}); + +export default function InputMultiline() { + return ( + + ); +} + const blue = { 100: '#DAECFF', 200: '#80BFFF', @@ -85,19 +101,3 @@ const StyledTextareaElement = styled('textarea', { } `, ); - -const CustomInput = React.forwardRef(function CustomInput(props, ref) { - return ( - - ); -}); - -export default function UnstyledInputBasic() { - return ( - - ); -} diff --git a/docs/data/base/components/input/InputMultiline.tsx b/docs/data/base/components/input/InputMultiline.tsx index 21e71babb16216..d3a8e784bb388e 100644 --- a/docs/data/base/components/input/InputMultiline.tsx +++ b/docs/data/base/components/input/InputMultiline.tsx @@ -1,7 +1,26 @@ import * as React from 'react'; -import InputUnstyled, { InputUnstyledProps } from '@mui/base/InputUnstyled'; +import Input, { InputProps } from '@mui/base/Input'; import { styled } from '@mui/system'; +const CustomInput = React.forwardRef(function CustomInput( + props: InputProps, + ref: React.ForwardedRef, +) { + return ( + + ); +}); + +export default function InputMultiline() { + return ( + + ); +} + const blue = { 100: '#DAECFF', 200: '#80BFFF', @@ -85,22 +104,3 @@ const StyledTextareaElement = styled('textarea', { } `, ); - -const CustomInput = React.forwardRef(function CustomInput( - props: InputUnstyledProps, - ref: React.ForwardedRef, -) { - return ( - - ); -}); - -export default function UnstyledInputBasic() { - return ( - - ); -} diff --git a/docs/data/base/components/input/InputMultilineAutosize.js b/docs/data/base/components/input/InputMultilineAutosize.js index efad1c94230bed..475b1ee89d7c98 100644 --- a/docs/data/base/components/input/InputMultilineAutosize.js +++ b/docs/data/base/components/input/InputMultilineAutosize.js @@ -1,8 +1,24 @@ import * as React from 'react'; -import InputUnstyled from '@mui/base/InputUnstyled'; +import Input from '@mui/base/Input'; import TextareaAutosize from '@mui/base/TextareaAutosize'; import { styled } from '@mui/system'; +const CustomInput = React.forwardRef(function CustomInput(props, ref) { + return ( + + ); +}); + +export default function InputMultilineAutosize() { + return ( + + ); +} + const blue = { 100: '#DAECFF', 200: '#80BFFF', @@ -83,19 +99,3 @@ const StyledTextareaElement = styled(TextareaAutosize)( } `, ); - -const CustomInput = React.forwardRef(function CustomInput(props, ref) { - return ( - - ); -}); - -export default function UnstyledInputBasic() { - return ( - - ); -} diff --git a/docs/data/base/components/input/InputMultilineAutosize.tsx b/docs/data/base/components/input/InputMultilineAutosize.tsx index f29bd97062c7ee..a5639eaabf1996 100644 --- a/docs/data/base/components/input/InputMultilineAutosize.tsx +++ b/docs/data/base/components/input/InputMultilineAutosize.tsx @@ -1,8 +1,27 @@ import * as React from 'react'; -import InputUnstyled, { InputUnstyledProps } from '@mui/base/InputUnstyled'; +import Input, { InputProps } from '@mui/base/Input'; import TextareaAutosize from '@mui/base/TextareaAutosize'; import { styled } from '@mui/system'; +const CustomInput = React.forwardRef(function CustomInput( + props: InputProps, + ref: React.ForwardedRef, +) { + return ( + + ); +}); + +export default function InputMultilineAutosize() { + return ( + + ); +} + const blue = { 100: '#DAECFF', 200: '#80BFFF', @@ -83,22 +102,3 @@ const StyledTextareaElement = styled(TextareaAutosize)( } `, ); - -const CustomInput = React.forwardRef(function CustomInput( - props: InputUnstyledProps, - ref: React.ForwardedRef, -) { - return ( - - ); -}); - -export default function UnstyledInputBasic() { - return ( - - ); -} diff --git a/docs/data/base/components/input/UnstyledInputBasic.js b/docs/data/base/components/input/UnstyledInputBasic.js index 4b95721ec2c211..bdcfaa32765aa2 100644 --- a/docs/data/base/components/input/UnstyledInputBasic.js +++ b/docs/data/base/components/input/UnstyledInputBasic.js @@ -1,7 +1,15 @@ import * as React from 'react'; -import InputUnstyled from '@mui/base/InputUnstyled'; +import Input from '@mui/base/Input'; import { styled } from '@mui/system'; +const CustomInput = React.forwardRef(function CustomInput(props, ref) { + return ; +}); + +export default function UnstyledInputBasic() { + return ; +} + const blue = { 100: '#DAECFF', 200: '#80BFFF', @@ -52,13 +60,3 @@ const StyledInputElement = styled('input')( } `, ); - -const CustomInput = React.forwardRef(function CustomInput(props, ref) { - return ( - - ); -}); - -export default function UnstyledInputBasic() { - return ; -} diff --git a/docs/data/base/components/input/UnstyledInputBasic.tsx b/docs/data/base/components/input/UnstyledInputBasic.tsx index fad30aeca15e33..6855b5801e13ac 100644 --- a/docs/data/base/components/input/UnstyledInputBasic.tsx +++ b/docs/data/base/components/input/UnstyledInputBasic.tsx @@ -1,7 +1,18 @@ import * as React from 'react'; -import InputUnstyled, { InputUnstyledProps } from '@mui/base/InputUnstyled'; +import Input, { InputProps } from '@mui/base/Input'; import { styled } from '@mui/system'; +const CustomInput = React.forwardRef(function CustomInput( + props: InputProps, + ref: React.ForwardedRef, +) { + return ; +}); + +export default function UnstyledInputBasic() { + return ; +} + const blue = { 100: '#DAECFF', 200: '#80BFFF', @@ -52,16 +63,3 @@ const StyledInputElement = styled('input')( } `, ); - -const CustomInput = React.forwardRef(function CustomInput( - props: InputUnstyledProps, - ref: React.ForwardedRef, -) { - return ( - - ); -}); - -export default function UnstyledInputBasic() { - return ; -} diff --git a/docs/data/base/components/input/UnstyledInputIntroduction.js b/docs/data/base/components/input/UnstyledInputIntroduction.js index 5f994e6f84bfdb..a4ac1068eb6c67 100644 --- a/docs/data/base/components/input/UnstyledInputIntroduction.js +++ b/docs/data/base/components/input/UnstyledInputIntroduction.js @@ -1,7 +1,15 @@ import * as React from 'react'; -import InputUnstyled from '@mui/base/InputUnstyled'; +import Input from '@mui/base/Input'; import { styled } from '@mui/system'; +const CustomInput = React.forwardRef(function CustomInput(props, ref) { + return ; +}); + +export default function UnstyledInputIntroduction() { + return ; +} + const blue = { 100: '#DAECFF', 200: '#b6daff', @@ -52,13 +60,3 @@ const StyledInputElement = styled('input')( } `, ); - -const CustomInput = React.forwardRef(function CustomInput(props, ref) { - return ( - - ); -}); - -export default function UnstyledInputIntroduction() { - return ; -} diff --git a/docs/data/base/components/input/UnstyledInputIntroduction.tsx b/docs/data/base/components/input/UnstyledInputIntroduction.tsx index ca0eb2ad9aca71..5faf387f0a3d09 100644 --- a/docs/data/base/components/input/UnstyledInputIntroduction.tsx +++ b/docs/data/base/components/input/UnstyledInputIntroduction.tsx @@ -1,7 +1,18 @@ import * as React from 'react'; -import InputUnstyled from '@mui/base/InputUnstyled'; +import Input from '@mui/base/Input'; import { styled } from '@mui/system'; +const CustomInput = React.forwardRef(function CustomInput( + props: React.InputHTMLAttributes, + ref: React.ForwardedRef, +) { + return ; +}); + +export default function UnstyledInputIntroduction() { + return ; +} + const blue = { 100: '#DAECFF', 200: '#b6daff', @@ -52,16 +63,3 @@ const StyledInputElement = styled('input')( } `, ); - -const CustomInput = React.forwardRef(function CustomInput( - props: React.InputHTMLAttributes, - ref: React.ForwardedRef, -) { - return ( - - ); -}); - -export default function UnstyledInputIntroduction() { - return ; -} diff --git a/docs/data/base/components/input/UseInput.js b/docs/data/base/components/input/UseInput.js index 692fcd899be9c9..1fbc559f906243 100644 --- a/docs/data/base/components/input/UseInput.js +++ b/docs/data/base/components/input/UseInput.js @@ -3,6 +3,25 @@ import useInput from '@mui/base/useInput'; import { styled } from '@mui/system'; import { unstable_useForkRef as useForkRef } from '@mui/utils'; +const CustomInput = React.forwardRef(function CustomInput(props, ref) { + const { getRootProps, getInputProps } = useInput(props); + + const inputProps = getInputProps(); + + // Make sure that both the forwarded ref and the ref returned from the getInputProps are applied on the input element + inputProps.ref = useForkRef(inputProps.ref, ref); + + return ( +
+ +
+ ); +}); + +export default function UseInput() { + return ; +} + const blue = { 100: '#DAECFF', 200: '#80BFFF', @@ -53,22 +72,3 @@ const StyledInputElement = styled('input')( } `, ); - -const CustomInput = React.forwardRef(function CustomInput(props, ref) { - const { getRootProps, getInputProps } = useInput(props); - - const inputProps = getInputProps(); - - // Make sure that both the forwarded ref and the ref returned from the getInputProps are applied on the input element - inputProps.ref = useForkRef(inputProps.ref, ref); - - return ( -
- -
- ); -}); - -export default function UseInput() { - return ; -} diff --git a/docs/data/base/components/input/UseInput.tsx b/docs/data/base/components/input/UseInput.tsx index f65a8bf9898950..7159ce62bf5789 100644 --- a/docs/data/base/components/input/UseInput.tsx +++ b/docs/data/base/components/input/UseInput.tsx @@ -3,6 +3,28 @@ import useInput from '@mui/base/useInput'; import { styled } from '@mui/system'; import { unstable_useForkRef as useForkRef } from '@mui/utils'; +const CustomInput = React.forwardRef(function CustomInput( + props: React.InputHTMLAttributes, + ref: React.ForwardedRef, +) { + const { getRootProps, getInputProps } = useInput(props); + + const inputProps = getInputProps(); + + // Make sure that both the forwarded ref and the ref returned from the getInputProps are applied on the input element + inputProps.ref = useForkRef(inputProps.ref, ref); + + return ( +
+ +
+ ); +}); + +export default function UseInput() { + return ; +} + const blue = { 100: '#DAECFF', 200: '#80BFFF', @@ -53,25 +75,3 @@ const StyledInputElement = styled('input')( } `, ); - -const CustomInput = React.forwardRef(function CustomInput( - props: React.InputHTMLAttributes, - ref: React.ForwardedRef, -) { - const { getRootProps, getInputProps } = useInput(props); - - const inputProps = getInputProps(); - - // Make sure that both the forwarded ref and the ref returned from the getInputProps are applied on the input element - inputProps.ref = useForkRef(inputProps.ref, ref); - - return ( -
- -
- ); -}); - -export default function UseInput() { - return ; -} diff --git a/docs/data/base/components/input/input.md b/docs/data/base/components/input/input.md index 440d7a46a25c92..6100658cbe7f75 100644 --- a/docs/data/base/components/input/input.md +++ b/docs/data/base/components/input/input.md @@ -1,14 +1,14 @@ --- product: base -title: Unstyled React Input component and hook -components: InputUnstyled +title: React Input component and hook +components: Input hooks: useInput githubLabel: 'component: input' --- -# Unstyled Input +# Input -

The Unstyled Input component provides users with a field to enter and edit text.

+

The Input component provides users with a field to enter and edit text.

{{"component": "modules/components/ComponentLinkHeader.js", "design": false}} @@ -17,7 +17,7 @@ githubLabel: 'component: input' ## Introduction An input is a UI element that accepts text data from the user. -The Unstyled Input component replaces the native HTML `` tag, and offers expanded customization and accessibility features. +The Input component replaces the native HTML `` tag, and offers expanded customization and accessibility features. It can also be transformed into a `