diff --git a/apps/pigment-css-next-app/src/app/layout.tsx b/apps/pigment-css-next-app/src/app/layout.tsx index 77126c9b714539..b232ba291a9f28 100644 --- a/apps/pigment-css-next-app/src/app/layout.tsx +++ b/apps/pigment-css-next-app/src/app/layout.tsx @@ -1,9 +1,7 @@ import type { Metadata } from 'next'; -import { css } from '@pigment-css/react'; import { Inter } from 'next/font/google'; import { AppRouterCacheProvider } from '@mui/material-nextjs/v14-appRouter'; import { ThemeProvider } from '@mui/material/styles'; -import CssBaseline from '@mui/material/CssBaseline'; import '@pigment-css/react/styles.css'; import theme from './theme'; @@ -19,20 +17,9 @@ export const metadata: Metadata = { export default function RootLayout(props: { children: React.ReactNode }) { return ( - t.vars.palette.background.default}; - color: ${({ theme: t }) => t.vars.palette.text.primary}; - background-image: url('@/assets/mui.svg'); - background-repeat: no-repeat; - background-position: 1rem 1rem; - `}`} - > + - - - {props.children} - + {props.children} diff --git a/apps/pigment-css-next-app/src/app/material-ui/react-css-baseline/page.tsx b/apps/pigment-css-next-app/src/app/material-ui/react-css-baseline/page.tsx new file mode 100644 index 00000000000000..ba513ac0612826 --- /dev/null +++ b/apps/pigment-css-next-app/src/app/material-ui/react-css-baseline/page.tsx @@ -0,0 +1,24 @@ +'use client'; +import * as React from 'react'; +import CssBaseline from '@mui/material/CssBaseline'; +import ScopedCssBaseline from '@mui/material/ScopedCssBaseline'; + +export default function CssBaselinePage() { + return ( + + +
+

CSS Baseline

+
+

Hello world

+
+
+
+

Positioned Popper

+
+ Hello world +
+
+
+ ); +} diff --git a/apps/pigment-css-next-app/src/app/material-ui/react-popper/page.tsx b/apps/pigment-css-next-app/src/app/material-ui/react-popper/page.tsx new file mode 100644 index 00000000000000..99197dba12699d --- /dev/null +++ b/apps/pigment-css-next-app/src/app/material-ui/react-popper/page.tsx @@ -0,0 +1,51 @@ +'use client'; +import * as React from 'react'; +import PopperPopupState from '../../../../../../docs/data/material/components/popper/PopperPopupState'; +import PositionedPopper from '../../../../../../docs/data/material/components/popper/PositionedPopper'; +import SimplePopper from '../../../../../../docs/data/material/components/popper/SimplePopper'; +import SpringPopper from '../../../../../../docs/data/material/components/popper/SpringPopper'; +import TransitionsPopper from '../../../../../../docs/data/material/components/popper/TransitionsPopper'; +import VirtualElementPopper from '../../../../../../docs/data/material/components/popper/VirtualElementPopper'; + +export default function Popper() { + return ( + +
+

Popper Popup State

+
+ +
+
+
+

Positioned Popper

+
+ +
+
+
+

Simple Popper

+
+ +
+
+
+

Spring Popper

+
+ +
+
+
+

Transitions Popper

+
+ +
+
+
+

Virtual Element Popper

+
+ +
+
+
+ ); +} diff --git a/apps/pigment-css-next-app/src/app/material-ui/react-text-field/page.tsx b/apps/pigment-css-next-app/src/app/material-ui/react-text-field/page.tsx new file mode 100644 index 00000000000000..f3d627bd2944ce --- /dev/null +++ b/apps/pigment-css-next-app/src/app/material-ui/react-text-field/page.tsx @@ -0,0 +1,163 @@ +'use client'; +import * as React from 'react'; +import BasicTextFields from '../../../../../../docs/data/material/components/text-fields/BasicTextFields'; +import ColorTextFields from '../../../../../../docs/data/material/components/text-fields/ColorTextFields'; +import ComposedTextField from '../../../../../../docs/data/material/components/text-fields/ComposedTextField'; +import CustomizedInputBase from '../../../../../../docs/data/material/components/text-fields/CustomizedInputBase'; +import CustomizedInputsStyleOverrides from '../../../../../../docs/data/material/components/text-fields/CustomizedInputsStyleOverrides'; +import CustomizedInputsStyled from '../../../../../../docs/data/material/components/text-fields/CustomizedInputsStyled'; +import FormPropsTextFields from '../../../../../../docs/data/material/components/text-fields/FormPropsTextFields'; +import FormattedInputs from '../../../../../../docs/data/material/components/text-fields/FormattedInputs'; +import FullWidthTextField from '../../../../../../docs/data/material/components/text-fields/FullWidthTextField'; +import HelperTextAligned from '../../../../../../docs/data/material/components/text-fields/HelperTextAligned'; +import HelperTextMisaligned from '../../../../../../docs/data/material/components/text-fields/HelperTextMisaligned'; +import InputAdornments from '../../../../../../docs/data/material/components/text-fields/InputAdornments'; +import InputWithIcon from '../../../../../../docs/data/material/components/text-fields/InputWithIcon'; +import Inputs from '../../../../../../docs/data/material/components/text-fields/Inputs'; +import LayoutTextFields from '../../../../../../docs/data/material/components/text-fields/LayoutTextFields'; +import MultilineTextFields from '../../../../../../docs/data/material/components/text-fields/MultilineTextFields'; +import SelectTextFields from '../../../../../../docs/data/material/components/text-fields/SelectTextFields'; +import StateTextFields from '../../../../../../docs/data/material/components/text-fields/StateTextFields'; +import TextFieldHiddenLabel from '../../../../../../docs/data/material/components/text-fields/TextFieldHiddenLabel'; +import TextFieldSizes from '../../../../../../docs/data/material/components/text-fields/TextFieldSizes'; +import UseFormControl from '../../../../../../docs/data/material/components/text-fields/UseFormControl'; +import ValidationTextFields from '../../../../../../docs/data/material/components/text-fields/ValidationTextFields'; + +export default function TextFields() { + return ( + +
+

Basic Text Fields

+
+ +
+
+
+

Color Text Fields

+
+ +
+
+
+

Composed Text Field

+
+ +
+
+
+

Customized Input Base

+
+ +
+
+
+

Customized Inputs Style Overrides

+
+ +
+
+
+

Customized Inputs Styled

+
+ +
+
+
+

Form Props Text Fields

+
+ +
+
+
+

Formatted Inputs

+
+ +
+
+
+

Full Width Text Field

+
+ +
+
+
+

Helper Text Aligned

+
+ +
+
+
+

Helper Text Misaligned

+
+ +
+
+
+

Input Adornments

+
+ +
+
+
+

Input With Icon

+
+ +
+
+
+

Inputs

+
+ +
+
+
+

Layout Text Fields

+
+ +
+
+
+

Multiline Text Fields

+
+ +
+
+
+

Select Text Fields

+
+ +
+
+
+

State Text Fields

+
+ +
+
+
+

Text Field Hidden Label

+
+ +
+
+
+

Text Field Sizes

+
+ +
+
+
+

Use Form Control

+
+ +
+
+
+

Validation Text Fields

+
+ +
+
+
+ ); +} diff --git a/apps/pigment-css-vite-app/src/pages/material-ui/react-css-baseline.tsx b/apps/pigment-css-vite-app/src/pages/material-ui/react-css-baseline.tsx new file mode 100644 index 00000000000000..14caca148fca49 --- /dev/null +++ b/apps/pigment-css-vite-app/src/pages/material-ui/react-css-baseline.tsx @@ -0,0 +1,24 @@ +import * as React from 'react'; +import CssBaseline from '@mui/material/CssBaseline'; +import ScopedCssBaseline from '@mui/material/ScopedCssBaseline'; +import MaterialUILayout from '../../Layout'; + +export default function CssBaselinePage() { + return ( + + +
+

CSS Baseline

+
+

Hello world

+
+
+
+

Positioned Popper

+
+ Hello world +
+
+
+ ); +} diff --git a/apps/pigment-css-vite-app/src/pages/material-ui/react-popper.tsx b/apps/pigment-css-vite-app/src/pages/material-ui/react-popper.tsx new file mode 100644 index 00000000000000..29dccd4a30a793 --- /dev/null +++ b/apps/pigment-css-vite-app/src/pages/material-ui/react-popper.tsx @@ -0,0 +1,52 @@ +import * as React from 'react'; +import MaterialUILayout from '../../Layout'; +import PopperPopupState from '../../../../../docs/data/material/components/popper/PopperPopupState.tsx'; +import PositionedPopper from '../../../../../docs/data/material/components/popper/PositionedPopper.tsx'; +import SimplePopper from '../../../../../docs/data/material/components/popper/SimplePopper.tsx'; +import SpringPopper from '../../../../../docs/data/material/components/popper/SpringPopper.tsx'; +import TransitionsPopper from '../../../../../docs/data/material/components/popper/TransitionsPopper.tsx'; +import VirtualElementPopper from '../../../../../docs/data/material/components/popper/VirtualElementPopper.tsx'; + +export default function Popper() { + return ( + +

Popper

+
+

Popper Popup State

+
+ +
+
+
+

Positioned Popper

+
+ +
+
+
+

Simple Popper

+
+ +
+
+
+

Spring Popper

+
+ +
+
+
+

Transitions Popper

+
+ +
+
+
+

Virtual Element Popper

+
+ +
+
+
+ ); +} diff --git a/apps/pigment-css-vite-app/src/pages/material-ui/react-text-field.tsx b/apps/pigment-css-vite-app/src/pages/material-ui/react-text-field.tsx new file mode 100644 index 00000000000000..bdd998a45605f0 --- /dev/null +++ b/apps/pigment-css-vite-app/src/pages/material-ui/react-text-field.tsx @@ -0,0 +1,164 @@ +import * as React from 'react'; +import MaterialUILayout from '../../Layout'; +import BasicTextFields from '../../../../../docs/data/material/components/text-fields/BasicTextFields.tsx'; +import ColorTextFields from '../../../../../docs/data/material/components/text-fields/ColorTextFields.tsx'; +import ComposedTextField from '../../../../../docs/data/material/components/text-fields/ComposedTextField.tsx'; +import CustomizedInputBase from '../../../../../docs/data/material/components/text-fields/CustomizedInputBase.tsx'; +import CustomizedInputsStyleOverrides from '../../../../../docs/data/material/components/text-fields/CustomizedInputsStyleOverrides.tsx'; +import CustomizedInputsStyled from '../../../../../docs/data/material/components/text-fields/CustomizedInputsStyled.tsx'; +import FormPropsTextFields from '../../../../../docs/data/material/components/text-fields/FormPropsTextFields.tsx'; +import FormattedInputs from '../../../../../docs/data/material/components/text-fields/FormattedInputs.tsx'; +import FullWidthTextField from '../../../../../docs/data/material/components/text-fields/FullWidthTextField.tsx'; +import HelperTextAligned from '../../../../../docs/data/material/components/text-fields/HelperTextAligned.tsx'; +import HelperTextMisaligned from '../../../../../docs/data/material/components/text-fields/HelperTextMisaligned.tsx'; +import InputAdornments from '../../../../../docs/data/material/components/text-fields/InputAdornments.tsx'; +import InputWithIcon from '../../../../../docs/data/material/components/text-fields/InputWithIcon.tsx'; +import Inputs from '../../../../../docs/data/material/components/text-fields/Inputs.tsx'; +import LayoutTextFields from '../../../../../docs/data/material/components/text-fields/LayoutTextFields.tsx'; +import MultilineTextFields from '../../../../../docs/data/material/components/text-fields/MultilineTextFields.tsx'; +import SelectTextFields from '../../../../../docs/data/material/components/text-fields/SelectTextFields.tsx'; +import StateTextFields from '../../../../../docs/data/material/components/text-fields/StateTextFields.tsx'; +import TextFieldHiddenLabel from '../../../../../docs/data/material/components/text-fields/TextFieldHiddenLabel.tsx'; +import TextFieldSizes from '../../../../../docs/data/material/components/text-fields/TextFieldSizes.tsx'; +import UseFormControl from '../../../../../docs/data/material/components/text-fields/UseFormControl.tsx'; +import ValidationTextFields from '../../../../../docs/data/material/components/text-fields/ValidationTextFields.tsx'; + +export default function TextFields() { + return ( + +

TextFields

+
+

Basic Text Fields

+
+ +
+
+
+

Color Text Fields

+
+ +
+
+
+

Composed Text Field

+
+ +
+
+
+

Customized Input Base

+
+ +
+
+
+

Customized Inputs Style Overrides

+
+ +
+
+
+

Customized Inputs Styled

+
+ +
+
+
+

Form Props Text Fields

+
+ +
+
+
+

Formatted Inputs

+
+ +
+
+
+

Full Width Text Field

+
+ +
+
+
+

Helper Text Aligned

+
+ +
+
+
+

Helper Text Misaligned

+
+ +
+
+
+

Input Adornments

+
+ +
+
+
+

Input With Icon

+
+ +
+
+
+

Inputs

+
+ +
+
+
+

Layout Text Fields

+
+ +
+
+
+

Multiline Text Fields

+
+ +
+
+
+

Select Text Fields

+
+ +
+
+
+

State Text Fields

+
+ +
+
+
+

Text Field Hidden Label

+
+ +
+
+
+

Text Field Sizes

+
+ +
+
+
+

Use Form Control

+
+ +
+
+
+

Validation Text Fields

+
+ +
+
+
+ ); +} diff --git a/packages/mui-material/src/CssBaseline/CssBaseline.js b/packages/mui-material/src/CssBaseline/CssBaseline.js index 12d16875e3f984..9caadb2ba5efb3 100644 --- a/packages/mui-material/src/CssBaseline/CssBaseline.js +++ b/packages/mui-material/src/CssBaseline/CssBaseline.js @@ -1,8 +1,11 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import useThemeProps from '../styles/useThemeProps'; -import GlobalStyles from '../GlobalStyles'; +import { globalCss } from '../zero-styled'; +import { useDefaultProps } from '../DefaultPropsProvider'; + +// to determine if the global styles are static or dynamic +const isDynamicSupport = typeof globalCss({}) === 'function'; export const html = (theme, enableColorScheme) => ({ WebkitFontSmoothing: 'antialiased', // Antialiasing. @@ -30,9 +33,20 @@ export const styles = (theme, enableColorScheme = false) => { const colorSchemeStyles = {}; if (enableColorScheme && theme.colorSchemes) { Object.entries(theme.colorSchemes).forEach(([key, scheme]) => { - colorSchemeStyles[theme.getColorSchemeSelector(key).replace(/\s*&/, '')] = { - colorScheme: scheme.palette?.mode, - }; + const selector = theme.getColorSchemeSelector(key); + if (selector.startsWith('@')) { + // for @media (prefers-color-scheme), we need to target :root + colorSchemeStyles[selector] = { + ':root': { + colorScheme: scheme.palette?.mode, + }, + }; + } else { + // else, it's likely that the selector already target an element with a class or data attribute + colorSchemeStyles[selector.replace(/\s*&/, '')] = { + colorScheme: scheme.palette?.mode, + }; + } }); } let defaultStyles = { @@ -63,15 +77,59 @@ export const styles = (theme, enableColorScheme = false) => { return defaultStyles; }; +// `ecs` stands for enableColorScheme. This is internal logic to make it work with Pigment CSS, so shorter is better. +const SELECTOR = 'mui-ecs'; +const staticStyles = (theme) => { + const result = styles(theme, false); + const baseStyles = Array.isArray(result) ? result[0] : result; + if (!theme.vars && baseStyles) { + baseStyles.html[`:root:has(${SELECTOR})`] = { colorScheme: theme.palette.mode }; + } + if (theme.colorSchemes) { + Object.entries(theme.colorSchemes).forEach(([key, scheme]) => { + const selector = theme.getColorSchemeSelector(key); + if (selector.startsWith('@')) { + // for @media (prefers-color-scheme), we need to target :root + baseStyles[selector] = { + [`:root:not(:has(.${SELECTOR}))`]: { + colorScheme: scheme.palette?.mode, + }, + }; + } else { + // else, it's likely that the selector already target an element with a class or data attribute + baseStyles[selector.replace(/\s*&/, '')] = { + [`&:not(:has(.${SELECTOR}))`]: { + colorScheme: scheme.palette?.mode, + }, + }; + } + }); + } + return result; +}; + +const GlobalStyles = globalCss( + isDynamicSupport + ? ({ theme, enableColorScheme }) => styles(theme, enableColorScheme) + : ({ theme }) => staticStyles(theme), +); + /** * Kickstart an elegant, consistent, and simple baseline to build upon. */ function CssBaseline(inProps) { - const props = useThemeProps({ props: inProps, name: 'MuiCssBaseline' }); + const props = useDefaultProps({ props: inProps, name: 'MuiCssBaseline' }); const { children, enableColorScheme = false } = props; return ( - styles(theme, enableColorScheme)} /> + {/* Emotion */} + {isDynamicSupport && } + + {/* Pigment CSS */} + {!isDynamicSupport && !enableColorScheme && ( + + )} + {children} ); diff --git a/packages/mui-material/src/Popper/Popper.tsx b/packages/mui-material/src/Popper/Popper.tsx index ea1ee028a96a75..565559630ff4b8 100644 --- a/packages/mui-material/src/Popper/Popper.tsx +++ b/packages/mui-material/src/Popper/Popper.tsx @@ -1,12 +1,14 @@ 'use client'; import { Popper as BasePopper, PopperProps as BasePopperProps } from '@mui/base/Popper'; -import { Direction, SxProps } from '@mui/system'; -import useTheme from '@mui/system/useThemeWithoutDefault'; +import { SxProps } from '@mui/system'; +import { useRtl } from '@mui/system/RtlProvider'; import refType from '@mui/utils/refType'; import HTMLElementType from '@mui/utils/HTMLElementType'; import PropTypes from 'prop-types'; import * as React from 'react'; -import { styled, Theme, useThemeProps } from '../styles'; +import { Theme } from '../styles'; +import { styled } from '../zero-styled'; +import { useDefaultProps } from '../DefaultPropsProvider'; export interface PopperProps extends Omit { /** @@ -59,8 +61,8 @@ const Popper = React.forwardRef(function Popper( inProps: PopperProps, ref: React.ForwardedRef, ) { - const theme = useTheme<{ direction?: Direction }>(); - const props = useThemeProps({ + const isRtl = useRtl(); + const props = useDefaultProps({ props: inProps, name: 'MuiPopper', }); @@ -101,7 +103,7 @@ const Popper = React.forwardRef(function Popper( return ( styles.root, -})(({ theme, ownerState }) => { +})(({ theme }) => { const colorSchemeStyles = {}; - if (ownerState.enableColorScheme && theme.colorSchemes) { + if (theme.colorSchemes) { Object.entries(theme.colorSchemes).forEach(([key, scheme]) => { - colorSchemeStyles[`&${theme.getColorSchemeSelector(key).replace(/\s*&/, '')}`] = { - colorScheme: scheme.palette?.mode, - }; + const selector = theme.getColorSchemeSelector(key); + if (selector.startsWith('@')) { + colorSchemeStyles[selector] = { + colorScheme: scheme.palette?.mode, + }; + } else { + colorSchemeStyles[`&${selector.replace(/\s*&/, '')}`] = { + colorScheme: scheme.palette?.mode, + }; + } }); } return { - ...html(theme, ownerState.enableColorScheme), + ...html(theme, false), ...body(theme), '& *, & *::before, & *::after': { boxSizing: 'inherit', @@ -40,12 +47,17 @@ const ScopedCssBaselineRoot = styled('div', { '& strong, & b': { fontWeight: theme.typography.fontWeightBold, }, - ...colorSchemeStyles, + variants: [ + { + props: { enableColorScheme: true }, + style: theme.vars ? colorSchemeStyles : { colorScheme: theme.palette.mode }, + }, + ], }; }); const ScopedCssBaseline = React.forwardRef(function ScopedCssBaseline(inProps, ref) { - const props = useThemeProps({ props: inProps, name: 'MuiScopedCssBaseline' }); + const props = useDefaultProps({ props: inProps, name: 'MuiScopedCssBaseline' }); const { className, component = 'div', enableColorScheme, ...other } = props; const ownerState = { diff --git a/packages/mui-material/src/zero-styled/index.tsx b/packages/mui-material/src/zero-styled/index.tsx index e56c98cf9182d1..159973f48008a3 100644 --- a/packages/mui-material/src/zero-styled/index.tsx +++ b/packages/mui-material/src/zero-styled/index.tsx @@ -1,5 +1,7 @@ import * as React from 'react'; +import { Interpolation } from '@mui/system'; import { extendSxProp } from '@mui/system/styleFunctionSx'; +import { Theme } from '../styles/createTheme'; import useTheme from '../styles/useTheme'; import GlobalStyles, { GlobalStylesProps } from '../GlobalStyles'; @@ -7,9 +9,18 @@ export { css, keyframes } from '@mui/system'; export { default as styled } from '../styles/styled'; -export function globalCss(styles: GlobalStylesProps['styles']) { - return function GlobalStylesWrapper() { - return ; +export function globalCss(styles: Interpolation<{ theme: Theme }>) { + return function GlobalStylesWrapper(props: Record) { + return ( + // Pigment CSS `globalCss` support callback with theme inside an object but `GlobalStyles` support theme as a callback value. + styles({ theme, ...props }) + : styles) as GlobalStylesProps['styles'] + } + /> + ); }; }