How to enable SettingDrawer in ant-design-pro v5 - reactjs

With Ant Design Pro v4, when init project, by choosing the option complete scaffolding, you'll get the Setting Drawer out of the box.
But in v5, you won't be able to select the complete option (you can refer to this demo video, no Do you need all the blocks or a simple scaffold there), and the default scaffold of v5 has no SettingDrawer.
How to enable it in Ant Design Pro v5? I've read this but not helpful because in v5 the Layout configuration code is quite different from v4. You may init the project in v5 here and v4 here to see what I mean by "quite different".

In And Design Pro v5, use various features by umi plugins. As for this feature, /src/app.tsx should like below:
// /src/app.tsx
import type { RunTimeLayoutConfig } from 'umi';
import { SettingDrawer } from '#ant-design/pro-layout';
import defaultSettings from '../config/defaultSettings';
// https://umijs.org/zh-CN/plugins/plugin-initial-state
export async function getInitialState() {
// ...
return {
// others state
settings: defaultSettings,
}
}
// https://umijs.org/zh-CN/plugins/plugin-layout
export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) => {
return {
// others props
childrenRender: (dom) => {
return (
<>
{dom}
<SettingDrawer
settings={initialState?.settings}
disableUrlParams
onSettingChange={(nextSettings) =>
setInitialState({
...initialState,
settings: nextSettings,
})
}
/>
</>
);
},
}
}

Related

If possible, how to use MUI with Qwik framework?

I try Qwik framework which looks a lot like Reactjs and uses jsx. And suddenly, I wonder if Reactjs libraries such as MUI can work with Qwik framework.
I tried this code:
import { component$ } from "#builder.io/qwik";
import Add from "#mui/icons-material/Add";
import IconButton from "#mui/material/IconButton";
const AddToCartButton = component$(() => {
return (
<IconButton>
<Add />
</IconButton>
);
});
export default AddToCartButton;
But I got this this error:
QWIK ERROR Code(25): Invalid JSXNode type. It must be either a function or a string. Found: {
'$$typeof': Symbol(react.memo),
type: {
'$$typeof': Symbol(react.forward_ref),
render: [Function: Component] { displayName: 'AddIcon', muiName: 'SvgIcon' }
},
compare: null
} Error: Code(25): Invalid JSXNode type. It must be either a function or a string. Found:
at logError (E:\qwik\flower\node_modules\#builder.io\qwik\core.cjs:4515:58)
at logErrorAndStop (E:\qwik\flower\node_modules\#builder.io\qwik\core.cjs:4521:21)
at qError (E:\qwik\flower\node_modules\#builder.io\qwik\core.cjs:4585:16)
at Proxy.jsx (E:\qwik\flower\node_modules\#builder.io\qwik\core.cjs:605:23)
at AddToCartButton_component_4S0nJgnxzBU (/src/addtocartbutton_component_4s0njgnxzbu.js:11:55)
at useInvoke (E:\qwik\flower\node_modules\#builder.io\qwik\core.cjs:149:30)
at E:\qwik\flower\node_modules\#builder.io\qwik\core.cjs:4676:32
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async renderSSR (E:\qwik\flower\node_modules\#builder.io\qwik\core.cjs:5280:9)
at async Proxy.renderToStream (E:\qwik\flower\node_modules\#builder.io\qwik\server.cjs:582:3)
at async file:///E:/qwik/flower/node_modules/#builder.io/qwik/optimizer.mjs:1776:30
QWIK ERROR Code(25): Invalid JSXNode type. It must be either a function or a string. Found: Error: Code(25): Invalid JSXNode type. It must be either a function or a string. Found:
at logError (E:\qwik\flower\node_modules\#builder.io\qwik\core.cjs:4515:58)
at logErrorAndStop (E:\qwik\flower\node_modules\#builder.io\qwik\core.cjs:4521:21)
at qError (E:\qwik\flower\node_modules\#builder.io\qwik\core.cjs:4585:16)
at Proxy.jsx (E:\qwik\flower\node_modules\#builder.io\qwik\core.cjs:605:23)
at AddToCartButton_component_4S0nJgnxzBU (/src/addtocartbutton_component_4s0njgnxzbu.js:11:55)
at useInvoke (E:\qwik\flower\node_modules\#builder.io\qwik\core.cjs:149:30)
at E:\qwik\flower\node_modules\#builder.io\qwik\core.cjs:4676:32
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async renderSSR (E:\qwik\flower\node_modules\#builder.io\qwik\core.cjs:5280:9)
at async Proxy.renderToStream (E:\qwik\flower\node_modules\#builder.io\qwik\server.cjs:582:3)
at async file:///E:/qwik/flower/node_modules/#builder.io/qwik/optimizer.mjs:1776:30
not rendered
JSX in this case is the templating language of Qwik but the underlyings are different. It is made similar so you have an easier transition from react as stated in their docs.
Qwik is familiar for React developers and can be used to build any type of web site or application.
Qwik offers some adapter for react components you need to install and wrap your components in.
npm i -D #builder.io/qwik-react
And then the usage should look like the example in their repo.
/** #jsxImportSource react */
import { qwikify$ } from '#builder.io/qwik-react';
import { Button } from '#mui/material';
export const App = qwikify$(() => {
return (
<>
<Button variant="contained">Hola</Button>
</>
);
});
This thread is a bit older but maybe someone stumbles across it like me.
I had the same issue using a UI-component library and resolved it with the following steps.
adding qwikReact into the vite.config file:
import { defineConfig } from "vite";
import { qwikVite } from "#builder.io/qwik/optimizer";
import { qwikCity } from "#builder.io/qwik-city/vite";
import { qwikReact } from "#builder.io/qwik-react";
import tsconfigPaths from "vite-tsconfig-paths";
export default defineConfig(() => {
return {
plugins: [qwikCity(), qwikVite(), qwikReact(), tsconfigPaths()],
preview: {
headers: {
"Cache-Control": "public, max-age=600",
},
},
};
});
qwikify() must be used in a seperate file only with /** #jsxImportSource react */ as Jonathan pointed out.
Be aware that react components will not be treated the same way in Qwik. As stated in the docs it should be a migration/testing tool for existing projects where react components should be introduced in "Wide islands".
For those of you who are using Qwik Speak for I18N, the proposed solution will not work as is because Qwik-Speak won't be able to handle the JSX. The solution is to individually wrap the MUI component and then use it normally as so:
import { component$ } from "#builder.io/qwik";
import { Link } from "#builder.io/qwik-city";
import { $translate as t, Speak } from "qwik-speak";
import Button from "#mui/material/Button";
import { qwikify$ } from "#builder.io/qwik-react";
export const MUIButton = qwikify$(Button);
export default component$(() => {
return (
<Speak assets={["welcome"]}>
<div>
<h1>{t("welcome.title##Welcome")}</h1>
<MUIButton variant="contained">Do Something</MUIButton>
</div>
</Speak>
);
})

How do I make Storybook run both React AND Svelte

I want to write stories for both React and Svelte components. I already have a few React components, and I'm attempting to install Svelte. My closest attempt can either run React OR Svelte depending on whether I comment out my React configuration. If I don't comment it out, I get this message when I look at my Svelte component in storybook:
Error: Objects are not valid as a React child (found: object with keys {Component}). If you meant to render a collection of children, use an array instead.
in unboundStoryFn
in ErrorBoundary
(further stack trace)
This refers to my story stories/test.svelte-stories.js:
import { storiesOf } from '#storybook/svelte';
import TestSvelteComponent from '../src/testComponentGroup/TestSvelteComponent.svelte';
storiesOf('TestSvelteComponent', module)
.add('Svelte Test', () => ({
Component: TestSvelteComponent
}));
My configuration is as follows:
.storybook/config.js:
import './config.react'; // If I comment out this line, I can make the svelte component work in storybook, but of course my react stories won't appear.
import './config.svelte';
.storybook/config.react.js:
import { configure } from '#storybook/react';
const req = require.context('../stories', true, /\.react-stories\.js$/);
function loadStories() {
req.keys().forEach(filename => req(filename));
}
configure(loadStories, module);
.storybook/config.svelte.js:
import { configure } from '#storybook/svelte';
const req = require.context('../stories', true, /\.svelte-stories\.js$/);
function loadStories() {
req.keys().forEach(filename => req(filename));
}
configure(loadStories, module);
.storybook/webpack.config.js:
module.exports = async ({ config, mode }) => {
let j;
// Find svelteloader from the webpack config
const svelteloader = config.module.rules.find((r, i) => {
if (r.loader && r.loader.includes('svelte-loader')) {
j = i;
return true;
}
});
// safely inject preprocess into the config
config.module.rules[j] = {
...svelteloader,
options: {
...svelteloader.options,
}
}
// return the overridden config
return config;
}
src/testComponentGroup/TestSvelteComponent.svelte:
<h1>
Hello
</h1>
It seems as though it's attempting to parse JSX via the Svelte test files, but if I import both React AND Svelte configurations I can still see the React components behaving properly.
See this discussion on github : https://github.com/storybookjs/storybook/issues/3889
It's not possible now and it's planned for the v7.0
The official position now is to create two sets of configuration (preview and manager), instanciate two separates storybook, and then use composition to assemble the two storybook into one.

Material UI breaks NextJS app in production

I created a NextJS app which uses server-side rendering and Material UI. It works fine in development.
The app compiles and builds without errors when I run "next build". When I run it with NODE_ENV=production, the webpage renders just fine but many features no longer work. For example:
The "Hidden" component for Material UI never shows any of its sub-components nested within even when it should (in my development app, it hides and shows certain divs depending on screen size).
None of the buttons on the webpage work. All these buttons have "onClick" events whose callback functions modify the React state object in some way when clicked. However, nothing happens when these are clicked. The state remains the same, so I'm assuming these functions never get called when these click events occur. This is true for Material UI's Button components as well as plain old HTML buttons (as JSX).
Everything works completely fine when I run this in dev mode on my laptop. However, when I build the NextJS app and deploy it to the server in production mode, I encounter the problems listed above. So far, my research has only turned up the possibility of class name conflicts during builds (this was said on Material UI's FAQ page). Has anyone had the same problem as I'm having?
EDIT: I just started a barebones NextJS app containing only one index page and minimal dependencies with one state parameter and one button to modify the parameter via an onClick event. I'm having the same problem. The button works in development but not in production. So this would be a NextJS issue rather than a Material UI problem. But that still doesn't explain why the "Hidden" component for Material UI always remains hidden regardless of screen size. Maybe it's both a Next JS and Material UI problem.
I think this can help you.
in _document.js
import React from 'react';
import Document, {
Html, Main, NextScript,
} from 'next/document';
import { ServerStyleSheets } from '#material-ui/core/styles';
export default class MyDocument extends Document {
render() {
return (
<Html lang="en">
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
// `getInitialProps` belongs to `_document` (instead of `_app`),
// it's compatible with server-side generation (SSG).
MyDocument.getInitialProps = async (ctx) => {
// Render app and page and get the context of the page with collected side effects.
const sheets = new ServerStyleSheets();
const originalRenderPage = ctx.renderPage;
ctx.renderPage = () => originalRenderPage({
enhanceApp: (App) => (props) => sheets.collect(<App {...props} />),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
// Styles fragment is rendered after the app and page rendering finish.
styles: [...React.Children.toArray(initialProps.styles), sheets.getStyleElement()],
};
};
and in add in _app.js
React.useEffect(() => {
// Remove the server-side injected CSS.
const jssStyles = document.querySelector('#jss-server-side');
if (jssStyles) {
jssStyles.parentElement.removeChild(jssStyles);
}
}, []);
Hope it work !
About the first Question, Because you open the ssr, The material ui can't judge the breakpointer in server side. Here's an official example。server-sider-rendering. You need to determine the user device based on the UA header to determine the page sizer. Use matches to determine what you need to display
_document.js -> MaterialUI styles for SSR.
import React from 'react'
import NextDocument from 'next/document'
import { ServerStyleSheet as StyledComponentSheets } from 'styled-components'
import { ServerStyleSheets as MaterialUiServerStyleSheets } from '#material-
ui/styles'
export default class Document extends NextDocument {
static async getInitialProps(ctx) {
const styledComponentSheet = new StyledComponentSheets()
const materialUiSheets = new MaterialUiServerStyleSheets()
const originalRenderPage = ctx.renderPage
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: App => props =>
styledComponentSheet.collectStyles(
materialUiSheets.collect(<App {...props} />),
),
})
const initialProps = await NextDocument.getInitialProps(ctx)
return {
...initialProps,
styles: [
<React.Fragment key="styles">
{initialProps.styles}
{materialUiSheets.getStyleElement()}
{styledComponentSheet.getStyleElement()}
</React.Fragment>,
],
}
} finally {
styledComponentSheet.seal()
}
}
}

React-JSS with material-ui and server side rendering

I have a react application and a custom component library built using material-ui. Components within the react application itself uses react-jss for styling and I'd like to avoid too many references to material-ui in the app itself just in case I wish to replace material-ui in the future.
From what I've read it seems that Material-UI uses a wrapped version of JSS so they should be compatible, but I'm unable to extract both my own styles as well as those from material-ui. I seem to be able to extract one or the other though...
I've followed the React-JSS Server Side Rendering guide and that works fine, but I'm wondering how I can most easily combine styles from both without having to resort to using #material-ui/core/styles everywhere.
Here is my bootstrap component that registers the JssProvider in my app:
export const Bootstrap: React.FC<IBootstrapProps> = ({
sheetsRegistry,
generateId
}) => {
return (
<JssProvider registry={sheetsRegistry} generateId={generateId}>
<App />
</JssProvider>
)
}
export default Bootstrap
The sheetsRegistry and generateId props comes from a render function called directly from an express handler:
const render = (props: ISSRRenderProps) => {
const sheetsRegistry = new SheetsRegistry()
const generateId = createGenerateId()
const appContent = renderToString(
<Bootstrap
sheetsRegistry={sheetsRegistry}
generateId={generateId}
/>
)
return {
appContent,
styles: sheetsRegistry.toString()
}
}
This gives me all my custom styles in the returned styles property which I in turn dump to the page without issues. The problem comes when I try to combine this with #material-ui. Simply including a component from the library does not give me it's styles server side though they do render on the client after a FOUC.
Using the server rendering guide from material-ui and modifying my Bootstrap component does give my the material-ui styles, but now my own styles are not collected. This also adds a single reference to material-ui in my react app, but if that is what it takes I can live with it as long as sub-components don't have to use material-uis style tools.
import { ServerStyleSheets } from "#material-ui/core/styles"
export const Bootstrap: React.FC<IBootstrapProps> = ({
sheetsRegistry,
generateId,
...rest
}) => {
const sheets = new ServerStyleSheets()
sheetsRegistry?.add(sheets as any)
return sheets.collect(
<JssProvider registry={sheetsRegistry} generateId={generateId}>
<App {...rest} />
</JssProvider>
)
}
Is there a way to get the best of both worlds? I'd love to use Material-UI components in my UI library and extract all styles globally for server side rendering.
I've been able to come up with a "workaround" by modifying my render function to collect material-ui styles separately and just concatenating them:
import { ServerStyleSheets } from "#material-ui/core/styles"
const render = (props: ISSRRenderProps) => {
const sheetsRegistry = new SheetsRegistry()
const generateId = createGenerateId()
const muiStyles = new ServerStyleSheets()
const appContent = renderToString(
muiStyles.collect(
<Bootstrap
sheetsRegistry={sheetsRegistry}
generateId={generateId}
/>
)
)
return {
appContent,
styles: muiStyles.toString() + sheetsRegistry.toString()
}
}
The reason believe this is a workaround and may not be the best solution is that I still have to separately handle my own styles vs material-ui styles. Seeing as they both use JSS behind the scenes I still think it should be possible to seamlessly collect both in the same sheetsRegistry, but this works for now.

React app using Material UI hooks not showing styling in production

I have a react app using Material UI (v4). In my development environment it all works fine.
In production the styling does not seem to be applied.
I have read about class name generation being different in dev to prod and potential clashes but I can't figure out how to fix it.
I have a js file which looks like:
import { makeStyles } from '#material-ui/core/styles';
const useStyles = makeStyles({
someClass: {
backgroundColor: 'red',
},
});
export default useStyles;
I then have multiple tsx files which use this, something like:
const Example = (props: IExampleState) => {
const styles = useStyles();
return (
<SomeMUIElement className={styles.someClass}>
{some inner stuff}
</SomeMUIElement>
)
}
const mapStateToProps = (state: IExampleState) => {
...
}
export default connect(mapStateToProps)(Calls);
In production none of these styling appear, and in dev tools I can see that there are no class names applied either, also appear to be no errors.
I'm sure I am missing something!

Resources