Skip to content

Commit

Permalink
Merge branch 'master' into pr/36829
Browse files Browse the repository at this point in the history
  • Loading branch information
danilo-leal committed Sep 18, 2023
2 parents c7d31d4 + 1ad6d26 commit 8bc653a
Show file tree
Hide file tree
Showing 24 changed files with 283 additions and 98 deletions.
6 changes: 4 additions & 2 deletions docs/data/joy/components/autocomplete/Asynchronous.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import FormLabel from '@mui/joy/FormLabel';
import Autocomplete from '@mui/joy/Autocomplete';
import CircularProgress from '@mui/joy/CircularProgress';

function sleep(delay = 0) {
function sleep(duration) {
return new Promise((resolve) => {
setTimeout(resolve, delay);
setTimeout(() => {
resolve();
}, duration);
});
}

Expand Down
8 changes: 5 additions & 3 deletions docs/data/joy/components/autocomplete/Asynchronous.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import FormLabel from '@mui/joy/FormLabel';
import Autocomplete from '@mui/joy/Autocomplete';
import CircularProgress from '@mui/joy/CircularProgress';

function sleep(delay = 0) {
return new Promise((resolve) => {
setTimeout(resolve, delay);
function sleep(duration: number): Promise<void> {
return new Promise<void>((resolve) => {
setTimeout(() => {
resolve();
}, duration);
});
}

Expand Down
6 changes: 4 additions & 2 deletions docs/data/material/components/autocomplete/Asynchronous.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import TextField from '@mui/material/TextField';
import Autocomplete from '@mui/material/Autocomplete';
import CircularProgress from '@mui/material/CircularProgress';

function sleep(delay = 0) {
function sleep(duration) {
return new Promise((resolve) => {
setTimeout(resolve, delay);
setTimeout(() => {
resolve();
}, duration);
});
}

Expand Down
8 changes: 5 additions & 3 deletions docs/data/material/components/autocomplete/Asynchronous.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ interface Film {
year: number;
}

function sleep(delay = 0) {
return new Promise((resolve) => {
setTimeout(resolve, delay);
function sleep(duration: number): Promise<void> {
return new Promise<void>((resolve) => {
setTimeout(() => {
resolve();
}, duration);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ With these variables, you can inject a theme into your app's stylesheet _at buil

For server-side applications, there are some trade-offs to consider:

| | Compare to the default method | Reason |
| :--------------------------------------------------- | :---------------------------- | :----------------------------------------------------------------------------------------------------------- |
| HTML size | Bigger | CSS variables are generated for both light and dark mode at build time. |
| [First Contentful Paint (FCP)](https://web.dev/fcp/) | Larger | Since the HTML size is generally bigger, the time to download the HTML before showing the content is longer. |
| [Time to Interactive (TTI)](https://web.dev/tti/) | Smaller (for dark mode) | Stylesheets are not regenerated between light and dark mode, so it takes less time for JavaScript to run. |
| | Compare to the default method | Reason |
| :--------------------------------------------------- | :---------------------------- | :------------------------------------------------------------------------------------------------------------- |
| HTML size | Bigger | CSS variables are generated for both light and dark mode at build time. |
| [First Contentful Paint (FCP)](https://web.dev/fcp/) | Longer | Since the HTML size is bigger, the time to download the HTML before showing the content is a bit longer. |
| [Time to Interactive (TTI)](https://web.dev/tti/) | Shorter (for dark mode) | Stylesheets are not regenerated between light and dark mode, a lot less time is spent running JavaScript code. |

:::warning
The comparison described in the table above may not be applicable to large and complex applications since there are so many factors that can impact performance metrics.
Expand All @@ -46,6 +46,8 @@ Adopting CSS variables requires some shifts in your mental model of theming and
**[Default approach](/material-ui/customization/dark-mode/)**: Light and dark colors are created separately.

```js
import { createTheme } from '@mui/material/styles';

const lightTheme = createTheme();

const darkTheme = createTheme({
Expand All @@ -58,6 +60,8 @@ const darkTheme = createTheme({
**CSS theme variables**: Light and dark colors are consolidated into a theme.

```js
import { experimental_extendTheme as extendTheme } from '@mui/material/styles';

// `extendTheme` is a new API
const theme = extendTheme({
colorSchemes: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as React from 'react';
import {
experimental_extendTheme as extendTheme,
Experimental_CssVarsProvider as CssVarsProvider,
} from '@mui/material/styles';
import Button from '@mui/material/Button';

const theme = extendTheme({
cssVarPrefix: 'md-demo',
});

export default function CssVarsBasic() {
return (
<CssVarsProvider theme={theme}>
<Button variant="contained">Hello world</Button>
</CssVarsProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as React from 'react';
import {
experimental_extendTheme as extendTheme,
Experimental_CssVarsProvider as CssVarsProvider,
} from '@mui/material/styles';
import Button from '@mui/material/Button';

const theme = extendTheme({
cssVarPrefix: 'md-demo',
});

export default function CssVarsBasic() {
return (
<CssVarsProvider theme={theme}>
<Button variant="contained">Hello world</Button>
</CssVarsProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<CssVarsProvider theme={theme}>
<Button variant="contained">Hello world</Button>
</CssVarsProvider>
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,6 @@
The CSS variables API relies on a new experimental provider for the theme called `Experimental_CssVarsProvider` to inject styles into Material UI components.
In addition to providing the theme in the inner React context, this new provider also generates CSS variables out of all tokens in the theme that are not functions, and makes them available in the context as well.

```js
import { Experimental_CssVarsProvider as CssVarsProvider } from '@mui/material/styles';

function App() {
return <CssVarsProvider>...</CssVarsProvider>;
}
```

Once the `App` renders on the screen, you will see the CSS theme variables in the html `:root` stylesheet.
The variables are flattened and prefixed with `--mui` by default:

Expand All @@ -29,6 +21,10 @@ The variables are flattened and prefixed with `--mui` by default:
}
```

The following demo uses `--md-demo` as a prefix for the variables:

{{"demo": "CssVarsBasic.js", "defaultCodeOpen": true}}

:::info
The `CssVarsProvider` is built on top of the [`ThemeProvider`](/material-ui/customization/theming/#themeprovider) with extra features like CSS variable generation, storage synchronization, unlimited color schemes, and more.
:::
Expand Down Expand Up @@ -167,7 +163,6 @@ const StyledComponent = styled('button')(({ theme }) => ({

- `defaultMode?: 'light' | 'dark' | 'system'` - Application's default mode (`light` by default)
- `disableTransitionOnChange : boolean` - Disable CSS transitions when switching between modes
- `prefix: string` - CSS variable prefix
- `theme: ThemeInput` - the theme provided to React's context
- `modeStorageKey?: string` - localStorage key used to store application `mode`
- `attribute?: string` - DOM attribute for applying color scheme
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ You can checkout the [advantages](https://mui.com/material-ui/experimental-api/c

For server-side applications, there are some trade-offs to consider:

| | Compare to the default method | Reason |
| :--------------------------------------------------- | :---------------------------- | :----------------------------------------------------------------------------------------------------------- |
| HTML size | Bigger | CSS variables are generated for both light and dark mode at build time. |
| [First Contentful Paint (FCP)](https://web.dev/fcp/) | Larger | Since the HTML size is generally bigger, the time to download the HTML before showing the content is longer. |
| [Time to Interactive (TTI)](https://web.dev/tti/) | Smaller (for dark mode) | Stylesheets are not regenerated between light and dark mode, so it takes less time for JavaScript to run. |
| | Compare to the default method | Reason |
| :--------------------------------------------------- | :---------------------------- | :------------------------------------------------------------------------------------------------------------- |
| HTML size | Bigger | CSS variables are generated for both light and dark mode at build time. |
| [First Contentful Paint (FCP)](https://web.dev/fcp/) | Longer | Since the HTML size is bigger, the time to download the HTML before showing the content is bit longer. |
| [Time to Interactive (TTI)](https://web.dev/tti/) | Shorter (for dark mode) | Stylesheets are not regenerated between light and dark mode, a lot less time is spent running JavaScript code. |

:::warning
The comparison described in the table above may not be applicable to large and complex applications since there are so many factors that can impact performance metrics.
Expand Down Expand Up @@ -209,7 +209,6 @@ See the complete usage of `createVssVarsProvider` in [Material UI](https://githu

- `defaultMode?: 'light' | 'dark' | 'system'` - Application's default mode (`light` by default)
- `disableTransitionOnChange : boolean` - Disable CSS transitions when switching between modes
- `prefix: string` - CSS variable prefix
- `theme: ThemeInput` - the theme provided to React's context
- `modeStorageKey?: string` - localStorage key used to store application `mode`
- `attribute?: string` - DOM attribute for applying color scheme
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
demos,
docs,
demoComponents,
} from 'docs/data/material/experimental-api/css-theme-variables/usage.md?@mui/markdown';
} from 'docs/data/material/experimental-api/css-theme-variables/usage/usage.md?@mui/markdown';

export default function Page() {
return <MarkdownDocs demos={demos} docs={docs} demoComponents={demoComponents} />;
Expand Down
128 changes: 128 additions & 0 deletions packages/mui-base/src/TextareaAutosize/TextareaAutosize.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import sinon, { spy, stub } from 'sinon';
import {
describeConformanceUnstyled,
act,
screen,
waitFor,
createMount,
createRenderer,
fireEvent,
Expand All @@ -15,6 +17,29 @@ function getStyleValue(value: string) {
return parseInt(value, 10) || 0;
}

// TODO: merge into a shared test helpers.
// MUI X already have one under mui-x/test/utils/helperFn.ts
function sleep(duration: number): Promise<void> {
return new Promise<void>((resolve) => {
setTimeout(() => {
resolve();
}, duration);
});
}

async function raf() {
return new Promise<void>((resolve) => {
// Chrome and Safari have a bug where calling rAF once returns the current
// frame instead of the next frame, so we need to call a double rAF here.
// See crbug.com/675795 for more.
requestAnimationFrame(() => {
requestAnimationFrame(() => {
resolve();
});
});
});
}

describe('<TextareaAutosize />', () => {
const { clock, render } = createRenderer();
const mount = createMount();
Expand All @@ -36,6 +61,109 @@ describe('<TextareaAutosize />', () => {
],
}));

// For https://github.com/mui/material-ui/pull/33238
it('should not crash when unmounting with Suspense', async () => {
const LazyRoute = React.lazy(() => {
// Force react to show fallback suspense
return new Promise<any>((resolve) => {
setTimeout(() => {
resolve({
default: () => <div>LazyRoute</div>,
});
}, 0);
});
});

function App() {
const [toggle, setToggle] = React.useState(false);

return (
<React.Suspense fallback={null}>
<button onClick={() => setToggle((r) => !r)}>Toggle</button>
{toggle ? <LazyRoute /> : <TextareaAutosize />}
</React.Suspense>
);
}

render(<App />);
const button = screen.getByRole('button');
fireEvent.click(button);
await waitFor(() => {
expect(screen.queryByText('LazyRoute')).not.to.equal(null);
});
});

// For https://github.com/mui/material-ui/pull/33253
it('should update height without an infinite rendering loop', async () => {
function App() {
const [value, setValue] = React.useState('Controlled');

const handleChange = (event: React.ChangeEvent<any>) => {
setValue(event.target.value);
};

return <TextareaAutosize value={value} onChange={handleChange} />;
}
const { container } = render(<App />);
const input = container.querySelector<HTMLTextAreaElement>('textarea')!;
act(() => {
input.focus();
});
const activeElement = document.activeElement!;
// set the value of the input to be 1 larger than its content width
fireEvent.change(activeElement, {
target: { value: 'Controlled\n' },
});
await sleep(0);
fireEvent.change(activeElement, {
target: { value: 'Controlled\n\n' },
});
});

// For https://github.com/mui/material-ui/pull/37135
it('should update height without delay', async function test() {
if (/jsdom/.test(window.navigator.userAgent)) {
// It depends on ResizeObserver
this.skip();
}

function App() {
const ref = React.useRef<HTMLTextAreaElement>(null);
return (
<div>
<button
onClick={() => {
ref.current!.style.width = '250px';
}}
>
change
</button>
<div>
<TextareaAutosize
ref={ref}
style={{
width: 150,
padding: 0,
fontSize: 14,
lineHeight: '15px',
border: '1px solid',
}}
defaultValue="qdzqzd qzd qzd qzd qz dqz"
/>
</div>
</div>
);
}
const { container } = render(<App />);
const input = container.querySelector<HTMLTextAreaElement>('textarea')!;
const button = screen.getByRole('button');
expect(parseInt(input.style.height, 10)).to.be.within(30, 32);
fireEvent.click(button);
await raf();
await raf();
expect(parseInt(input.style.height, 10)).to.be.within(15, 17);
});

describe('layout', () => {
const getComputedStyleStub = new Map<Element, Partial<CSSStyleDeclaration>>();
function setLayout(
Expand Down
Loading

0 comments on commit 8bc653a

Please sign in to comment.