Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NoSSR] Port the component from legacy Base UI #593

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 42 additions & 11 deletions docs/data/components/no-ssr/FrameDeferring.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';
import * as React from 'react';
import { styled } from '@mui/system';
import { NoSsr } from '@base_ui/react/NoSsr';
import { Box } from '@mui/system';

function LargeTree() {
return Array.from(new Array(5000)).map((_, index) => <span key={index}>.</span>);
Expand All @@ -14,8 +14,8 @@ export default function FrameDeferring() {
});

return (
<div>
<button
<Demo>
<Button
type="button"
onClick={() =>
setState({
Expand All @@ -24,10 +24,10 @@ export default function FrameDeferring() {
})
}
>
{'Render NoSsr defer="false"'}
</button>
{'Render <NoSsr defer={false} />'}
</Button>
<br />
<button
<Button
type="button"
onClick={() =>
setState({
Expand All @@ -36,11 +36,11 @@ export default function FrameDeferring() {
})
}
>
{'Render NoSsr defer="true"'}
</button>
{'Render <NoSsr defer={true} />'}
</Button>
<br />
<br />
<Box sx={{ width: 300, display: 'flex', flexWrap: 'wrap' }}>
<Panel sx={{ width: 300, display: 'flex', flexWrap: 'wrap' }}>
{state.open ? (
<React.Fragment>
<div>Outside NoSsr</div>
Expand All @@ -50,7 +50,38 @@ export default function FrameDeferring() {
</NoSsr>
</React.Fragment>
) : null}
</Box>
</div>
</Panel>
</Demo>
);
}

const Panel = styled('div')`
padding: 16px;
`;

const Demo = styled('div')`
height: 250px;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
overflow: auto;
padding: 8px;
`;

const Button = styled('button')(
({ theme }) => `
background-color: ${theme.palette.mode === 'dark' ? 'var(--gray-50)' : 'var(--gray-900)'};
color: ${theme.palette.mode === 'dark' ? 'var(--gray-900)' : 'var(--gray-50)'};
padding: 8px 16px;
border-radius: 4px;
border: none;
font-family:
"IBM Plex Sans",
sans-serif;

&:hover {
background-color: ${theme.palette.mode === 'dark' ? 'var(--gray-200)' : 'var(--gray-700)'};
}
`,
);
53 changes: 42 additions & 11 deletions docs/data/components/no-ssr/FrameDeferring.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';
import * as React from 'react';
import { styled } from '@mui/system';
import { NoSsr } from '@base_ui/react/NoSsr';
import { Box } from '@mui/system';

function LargeTree(): any {
return Array.from(new Array(5000)).map((_, index) => <span key={index}>.</span>);
Expand All @@ -14,8 +14,8 @@ export default function FrameDeferring() {
});

return (
<div>
<button
<Demo>
<Button
type="button"
onClick={() =>
setState({
Expand All @@ -24,10 +24,10 @@ export default function FrameDeferring() {
})
}
>
{'Render NoSsr defer="false"'}
</button>
{'Render <NoSsr defer={false} />'}
</Button>
<br />
<button
<Button
type="button"
onClick={() =>
setState({
Expand All @@ -36,11 +36,11 @@ export default function FrameDeferring() {
})
}
>
{'Render NoSsr defer="true"'}
</button>
{'Render <NoSsr defer={true} />'}
</Button>
<br />
<br />
<Box sx={{ width: 300, display: 'flex', flexWrap: 'wrap' }}>
<Panel sx={{ width: 300, display: 'flex', flexWrap: 'wrap' }}>
{state.open ? (
<React.Fragment>
<div>Outside NoSsr</div>
Expand All @@ -50,7 +50,38 @@ export default function FrameDeferring() {
</NoSsr>
</React.Fragment>
) : null}
</Box>
</div>
</Panel>
</Demo>
);
}

const Panel = styled('div')`
padding: 16px;
`;

const Demo = styled('div')`
height: 250px;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
overflow: auto;
padding: 8px;
`;

const Button = styled('button')(
({ theme }) => `
background-color: ${theme.palette.mode === 'dark' ? 'var(--gray-50)' : 'var(--gray-900)'};
color: ${theme.palette.mode === 'dark' ? 'var(--gray-900)' : 'var(--gray-50)'};
padding: 8px 16px;
border-radius: 4px;
border: none;
font-family:
"IBM Plex Sans",
sans-serif;

&:hover {
background-color: ${theme.palette.mode === 'dark' ? 'var(--gray-200)' : 'var(--gray-700)'};
}
`,
);
32 changes: 21 additions & 11 deletions docs/data/components/no-ssr/SimpleNoSsr.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
'use client';
import * as React from 'react';
import { styled } from '@mui/system';
import { NoSsr } from '@base_ui/react/NoSsr';
import { Box } from '@mui/system';

export default function SimpleNoSsr() {
return (
<div>
<Box sx={{ p: 2, bgcolor: 'primary.main', color: 'primary.contrastText' }}>
Server and Client
</Box>
<Demo>
<Panel>Server and Client</Panel>
<NoSsr>
<Box
sx={{ p: 2, bgcolor: 'secondary.main', color: 'secondary.contrastText' }}
>
Client only
</Box>
<Panel>Client only</Panel>
</NoSsr>
</div>
</Demo>
);
}

const Demo = styled('div')`
height: 250px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
overflow: auto;
padding: 8px;
`;

const Panel = styled('div')`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I love how it makes the .preview much easier to follow.

padding: var(--space-2);
margin-bottom: var(--space-1);
background-color: var(--gray-100);
`;
32 changes: 21 additions & 11 deletions docs/data/components/no-ssr/SimpleNoSsr.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
'use client';
import * as React from 'react';
import { styled } from '@mui/system';
import { NoSsr } from '@base_ui/react/NoSsr';
import { Box } from '@mui/system';

export default function SimpleNoSsr() {
return (
<div>
<Box sx={{ p: 2, bgcolor: 'primary.main', color: 'primary.contrastText' }}>
Server and Client
</Box>
<Demo>
<Panel>Server and Client</Panel>
<NoSsr>
<Box
sx={{ p: 2, bgcolor: 'secondary.main', color: 'secondary.contrastText' }}
>
Client only
</Box>
<Panel>Client only</Panel>
</NoSsr>
</div>
</Demo>
);
}

const Demo = styled('div')`
height: 250px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
overflow: auto;
padding: 8px;
`;

const Panel = styled('div')`
padding: var(--space-2);
margin-bottom: var(--space-1);
background-color: var(--gray-100);
`;
16 changes: 6 additions & 10 deletions docs/data/components/no-ssr/SimpleNoSsr.tsx.preview
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
<Box sx={{ p: 2, bgcolor: 'primary.main', color: 'primary.contrastText' }}>
Server and Client
</Box>
<NoSsr>
<Box
sx={{ p: 2, bgcolor: 'secondary.main', color: 'secondary.contrastText' }}
>
Client only
</Box>
</NoSsr>
<Demo>
<Panel>Server and Client</Panel>
<NoSsr>
<Panel>Client only</Panel>
</NoSsr>
</Demo>
2 changes: 1 addition & 1 deletion docs/data/components/no-ssr/no-ssr.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
productId: base-ui
title: No SSR React component
title: No-SSR React component
description: The No-SSR component defers the rendering of children components from the server to the client.
components: NoSsr
---
Copy link
Member

@oliviertassinari oliviertassinari Sep 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To use "No-SSR" below as well for the h1 of the docs page, no? It's uses "No SSR" right now.

SCR-20240919-sqrc

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know which one is more correct TBH. @colmtuite, @atomiks, could you chime in?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe ClientOnly is a better name?

Copy link
Member

@oliviertassinari oliviertassinari Oct 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Client only as client bundle only or client side only? 😁

Expand Down
1 change: 1 addition & 0 deletions docs/data/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const pages: readonly RouteMetadata[] = [
{ pathname: '/components/react-fieldset', title: 'Fieldset' },
{ pathname: '/components/react-form', title: 'Form' },
{ pathname: '/components/react-menu', title: 'Menu' },
{ pathname: '/components/react-no-ssr', title: 'No-SSR' },
{ pathname: '/components/react-number-field', title: 'Number Field' },
{ pathname: '/components/react-popover', title: 'Popover' },
{ pathname: '/components/react-preview-card', title: 'Preview Card' },
Expand Down
2 changes: 1 addition & 1 deletion docs/data/translations/api-docs/no-ssr/no-ssr.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"componentDescription": "NoSsr purposely removes components from the subject of Server Side Rendering (SSR).\n\nThis component can be useful in a variety of situations:\n\n* Escape hatch for broken dependencies not supporting SSR.\n* Improve the time-to-first paint on the client by only rendering above the fold.\n* Reduce the rendering time on the server.\n* Under too heavy server load, you can turn on service degradation.",
"propDescriptions": {
"children": { "description": "You can wrap a node." },
"children": { "description": "React node to render on client only." },
"defer": {
"description": "If <code>true</code>, the component will not only prevent server-side rendering. It will also defer the rendering of the children into a different screen frame."
},
Expand Down
4 changes: 2 additions & 2 deletions docs/src/components/demo/Demo.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
flex-direction: column;
align-items: center;
justify-content: center;
padding-top: 64px;
padding-bottom: 64px;
min-height: 150px;
padding: var(--space-2);

&:focus {
box-shadow: 0 0 0 1px var(--gray-outline-2) inset;
Expand Down
25 changes: 22 additions & 3 deletions packages/mui-base/src/NoSsr/NoSsr.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import { exactProp, unstable_useEnhancedEffect as useEnhancedEffect } from '@mui/utils';
import { NoSsrProps } from './NoSsr.types';

/**
* NoSsr purposely removes components from the subject of Server Side Rendering (SSR).
Expand All @@ -22,7 +21,7 @@ import { NoSsrProps } from './NoSsr.types';
*
* - [NoSsr API](https://base-ui.netlify.app/components/react-no-ssr/#api-reference-NoSsr)
*/
function NoSsr(props: NoSsrProps): JSX.Element {
function NoSsr(props: NoSsr.Props): JSX.Element {
const { children, defer = false, fallback = null } = props;
const [mountedState, setMountedState] = React.useState(false);

Expand All @@ -42,13 +41,33 @@ function NoSsr(props: NoSsrProps): JSX.Element {
return <React.Fragment>{mountedState ? children : fallback}</React.Fragment>;
}

namespace NoSsr {
export interface Props {
Comment on lines +44 to +45
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a new pattern? How can people extend the NoSsr prop now?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we decided to go with this pattern. See the rationale in #517. The interface should be extendable the same way as without the namespace.

/**
* React node to render on client only.
*/
children?: React.ReactNode;
/**
* If `true`, the component will not only prevent server-side rendering.
* It will also defer the rendering of the children into a different screen frame.
* @default false
*/
defer?: boolean;
/**
* The fallback content to display.
* @default null
*/
fallback?: React.ReactNode;
}
}

NoSsr.propTypes /* remove-proptypes */ = {
// ┌────────────────────────────── Warning ──────────────────────────────┐
// │ These PropTypes are generated from the TypeScript type definitions. │
// │ To update them, edit the TypeScript types and run `pnpm proptypes`. │
// └─────────────────────────────────────────────────────────────────────┘
/**
* You can wrap a node.
* React node to render on client only.
*/
children: PropTypes.node,
/**
Expand Down
19 changes: 0 additions & 19 deletions packages/mui-base/src/NoSsr/NoSsr.types.ts

This file was deleted.

1 change: 0 additions & 1 deletion packages/mui-base/src/NoSsr/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export { NoSsr } from './NoSsr';
export * from './NoSsr.types';
Loading