init project
Some checks failed
No response / noResponse (push) Has been cancelled
CI / Continuous releases (push) Has been cancelled
CI / test-dev (macos-latest) (push) Has been cancelled
CI / test-dev (ubuntu-latest) (push) Has been cancelled
CI / test-dev (windows-latest) (push) Has been cancelled
Maintenance / main (push) Has been cancelled
Scorecards supply-chain security / Scorecards analysis (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled

This commit is contained in:
how2ice
2025-12-12 14:26:25 +09:00
commit 005cf56baf
43188 changed files with 1079531 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
import Stack from '@mui/joy/Stack';
import Person from '@mui/icons-material/Person';
export default function IconFontSizes() {
return (
<Stack
spacing={2}
direction="row"
sx={{ gridColumn: '1 / -1', alignItems: 'center', justifyContent: 'center' }}
>
<Person fontSize="xs" />
<Person fontSize="sm" />
<Person fontSize="md" />
<Person fontSize="lg" />
<Person fontSize="xl" />
<Person fontSize="xl2" />
<Person fontSize="xl3" />
<Person fontSize="xl4" />
</Stack>
);
}

View File

@@ -0,0 +1,21 @@
import Stack from '@mui/joy/Stack';
import Person from '@mui/icons-material/Person';
export default function IconFontSizes() {
return (
<Stack
spacing={2}
direction="row"
sx={{ gridColumn: '1 / -1', alignItems: 'center', justifyContent: 'center' }}
>
<Person fontSize="xs" />
<Person fontSize="sm" />
<Person fontSize="md" />
<Person fontSize="lg" />
<Person fontSize="xl" />
<Person fontSize="xl2" />
<Person fontSize="xl3" />
<Person fontSize="xl4" />
</Stack>
);
}

View File

@@ -0,0 +1,8 @@
<Person fontSize="xs" />
<Person fontSize="sm" />
<Person fontSize="md" />
<Person fontSize="lg" />
<Person fontSize="xl" />
<Person fontSize="xl2" />
<Person fontSize="xl3" />
<Person fontSize="xl4" />

View File

@@ -0,0 +1,37 @@
import Box from '@mui/joy/Box';
import Button from '@mui/joy/Button';
import Input from '@mui/joy/Input';
import Typography from '@mui/joy/Typography';
import Stack from '@mui/joy/Stack';
import Person from '@mui/icons-material/Person';
export default function JoyMaterialIcon() {
return (
<Box sx={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 2 }}>
<Stack spacing={2}>
{['sm', 'md', 'lg'].map((size) => (
<Button key={size} size={size} startDecorator={<Person />}>
Button
</Button>
))}
</Stack>
<Stack spacing={2}>
{['sm', 'md', 'lg'].map((size) => (
<Input
key={size}
size={size}
startDecorator={<Person />}
placeholder="Placeholder"
/>
))}
</Stack>
<Stack spacing={2}>
{['sm', 'md', 'lg', 'xl'].map((size) => (
<Typography key={size} startDecorator={<Person />} sx={{ fontSize: size }}>
Hello World
</Typography>
))}
</Stack>
</Box>
);
}

View File

@@ -0,0 +1,37 @@
import Box from '@mui/joy/Box';
import Button from '@mui/joy/Button';
import Input from '@mui/joy/Input';
import Typography from '@mui/joy/Typography';
import Stack from '@mui/joy/Stack';
import Person from '@mui/icons-material/Person';
export default function JoyMaterialIcon() {
return (
<Box sx={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 2 }}>
<Stack spacing={2}>
{(['sm', 'md', 'lg'] as const).map((size) => (
<Button key={size} size={size} startDecorator={<Person />}>
Button
</Button>
))}
</Stack>
<Stack spacing={2}>
{(['sm', 'md', 'lg'] as const).map((size) => (
<Input
key={size}
size={size}
startDecorator={<Person />}
placeholder="Placeholder"
/>
))}
</Stack>
<Stack spacing={2}>
{(['sm', 'md', 'lg', 'xl'] as const).map((size) => (
<Typography key={size} startDecorator={<Person />} sx={{ fontSize: size }}>
Hello World
</Typography>
))}
</Stack>
</Box>
);
}

View File

@@ -0,0 +1,215 @@
# Using icon libraries
<p class="description">Learn how to use your favorite icon library with Joy UI.</p>
## Material UI Icons
[@mui/icons-material](https://www.npmjs.com/package/@mui/icons-material)
includes the 2,100+ official [Material Icons](https://fonts.google.com/icons?icon.set=Material+Icons) converted to [SVG Icon](/material-ui/api/svg-icon/) components.
### Installation
This section assumes that you've already installed Joy UI in your app—see [Installation](/joy-ui/getting-started/installation/) for instructions.
#### yarn
```bash
yarn add @mui/icons-material @mui/material
```
:::warning
Because `@mui/material` is a required dependency of `@mui/icons-material`, you have to add a workaround with yarn resolutions:
```json
{
"dependencies": {
"@mui/material": "npm:@mui/joy@latest"
},
"resolutions": {
"@mui/material": "npm:@mui/joy@latest"
}
}
```
After that, run `yarn install` in your terminal.
We are aware of this limitation and are considering removing the dependency.
You can keep track of the progress in [this issue](https://github.com/mui/material-ui/issues/34489).
:::
#### npm
```bash
npm install @mui/icons-material @mui/material
```
:::warning
Because `@mui/material` is a required dependency of `@mui/icons-material`, you have to update your bundler's config to add an alias.
Here is an example of how you can do it, if you use [webpack](https://webpack.js.org/):
**webpack.config.js**
```diff
module.exports = {
//...
+ resolve: {
+ alias: {
+ '@mui/material': '@mui/joy',
+ },
+ },
};
```
If you use TypeScript, you will need to update the TSConfig.
**tsconfig.json**
```diff
{
"compilerOptions": {
+ "paths": {
+ "@mui/material": ["./node_modules/@mui/joy"]
+ }
}
}
```
:::
:::error
`<CssVarsProvider />` is _required_ when working with Material UI's icons inside an app using Joy UI, so that the components can correctly adjust the icons based on the usage.
:::
### Usage
By default, Joy UI components are able to control an icon's color, font size, and margins when its size or variant changes.
{{"demo": "JoyMaterialIcon.js"}}
### Size
To control the size of the icon, use `fontSize` prop. The value can be one of the keys in `theme.fontSize` (the default value is `"xl"`).
{{"demo": "IconFontSizes.js"}}
## Third-party icons
To use other icon libraries, web font icons, or plain SVG icons with Joy UI, apply the styles with specific CSS variables as shown in the example below:
```jsx
import { CssVarsProvider } from '@mui/joy/styles';
import GlobalStyles from '@mui/joy/GlobalStyles';
// The `GlobalStyles` component is used to create a global style sheet.
// You can replace it with your preferred CSS solution.
function App() {
return (
<CssVarsProvider>
<GlobalStyles styles={{
// The {selector} is the CSS selector to target the icon.
// We recommend using a class over a tag if possible.
'{selector}': {
color: "var(--Icon-color)",
margin: "var(--Icon-margin)",
fontSize: "var(--Icon-fontSize, 20px)",
width: "1em",
height: "1em"
}
}}>
</CssVarsProvider>
)
}
```
Joy UI components can control those variables based on their size and variant to make the icons fit perfectly.
---
Here is a collection of well-known icon libraries that you can use with Joy UI.
### react-icons
- [Installation](https://react-icons.github.io/react-icons/)
<iframe src="https://codesandbox.io/embed/joy-ui-react-icons-n6jljq?fontsize=12&hidenavigation=1&module=%2Fdemo.tsx&theme=dark"
style="width:100%; height:250px; border:0; border-radius: 12px; overflow:hidden;"
title="joy-ui-react-icons"
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
></iframe>
### Ionicons
- [Browse icons](https://ionic.io/ionicons)
- [Installation](https://ionic.io/ionicons/usage)
<iframe src="https://codesandbox.io/embed/inspiring-visvesvaraya-etcc3x?fontsize=12&hidenavigation=1&module=%2Fdemo.tsx&theme=dark"
style="width:100%; height:250px; border:0; border-radius: 12px; overflow:hidden;"
title="inspiring-visvesvaraya-etcc3x"
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
></iframe>
### Heroicons
- [Browse icons](https://heroicons.com/)
- [Installation](https://github.com/tailwindlabs/heroicons#react)
<iframe src="https://codesandbox.io/embed/joy-ui-heroicons-wv2ev1?fontsize=12&hidenavigation=1&module=%2Fdemo.tsx&theme=dark"
style="width:100%; height:250px; border:0; border-radius: 12px; overflow:hidden;"
title="joy-ui-heroicons"
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
></iframe>
### Bootstrap Icons
- [Browse icons](https://icons.getbootstrap.com/)
- [Installation](https://icons.getbootstrap.com/#install)
<iframe src="https://codesandbox.io/embed/joy-ui-bootstrap-icons-x8g0cm?fontsize=12&hidenavigation=1&module=%2Fdemo.tsx&theme=dark"
style="width:100%; height:250px; border:0; border-radius: 12px; overflow:hidden;"
title="joy-ui-bootstrap"
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
></iframe>
### Font Awesome Icons
- [Browse icons](https://fontawesome.com/icons)
- [Installation](https://docs.fontawesome.com/web/use-with/react)
<iframe src="https://codesandbox.io/embed/joy-ui-fontawesome-kjbnqj?fontsize=12&hidenavigation=1&module=%2Fdemo.tsx&theme=dark"
style="width:100%; height:250px; border:0; border-radius: 12px; overflow:hidden;"
title="joy-ui-fontawesome"
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
></iframe>
### Iconify
- [Browse icons](https://icon-sets.iconify.design/)
- [Installation—React](https://iconify.design/docs/icon-components/react/)
- [Installation—Web component](https://iconify.design/docs/iconify-icon/)
- [Figma plugin](https://iconify.design/docs/design/figma/)
<iframe src="https://codesandbox.io/embed/joy-ui-iconify-r8fjrm?fontsize=12&hidenavigation=1&module=%2Fdemo.tsx&theme=dark"
style="width:100%; height:250px; border:0; border-radius: 12px; overflow:hidden;"
title="joy-ui-iconify"
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
></iframe>
### Lucide
- [Browse icons](https://icon-sets.iconify.design/)
- [Installation—React](https://lucide.dev/guide/packages/lucide-react)
<iframe src="https://codesandbox.io/embed/joy-ui-lucide-sy7hio?fontsize=12&hidenavigation=1&module=%2Fdemo.tsx&theme=dark"
style="width:100%; height:250px; border:0; border-radius: 12px; overflow:hidden;"
title="joy-ui-lucide"
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
></iframe>

View File

@@ -0,0 +1,121 @@
# Using Joy UI and Material UI together
<p class="description">Learn how to use Joy UI and Material UI together in the same project.</p>
## Introduction
There are two main use cases for using them together:
1. Your existing project already uses Material UI but you're willing to explore the new components and style Joy UI offers.
2. You've started your project with Joy UI but you find a key component you need is missing.
:::info
Once Joy UI reaches component parity with Material UI, we recommend that you **_choose one or the other_**. Not only do they have a different design language (and therefore a different theme structure) but they would increase your bundle size as well as potentially create unnecessary complexities.
:::
Additionally, keep these in mind when using them together:
- Both of them use [MUI System](/system/getting-started/) as their style engine, which uses React context for theming.
- Theme scoping must be done on one of the libraries.
### Prerequisites
- Have `@mui/material` and `@mui/joy` installed in your project.
- The version of both libraries must be [v5.12.0](https://github.com/mui/material-ui/releases/tag/v5.12.0) or higher.
## Set up the providers
Render Joy UI's `CssVarsProvider` inside Material UI's `ThemeProvider` and use `THEME_ID` to separate the themes from each other.
```js
import {
createTheme,
ThemeProvider,
THEME_ID as MATERIAL_THEME_ID,
} from '@mui/material/styles';
import { CssVarsProvider as JoyCssVarsProvider } from '@mui/joy/styles';
import CssBaseline from '@mui/material/CssBaseline';
const materialTheme = createTheme();
export default function App() {
return (
<ThemeProvider theme={{ [MATERIAL_THEME_ID]: materialTheme }}>
<JoyCssVarsProvider>
<CssBaseline enableColorScheme />
...Material UI and Joy UI components
</JoyCssVarsProvider>
</ThemeProvider>
);
}
```
<iframe src="https://codesandbox.io/embed/using-joy-ui-and-material-ui-together-qrsz2h?module=%2Fdemo.tsx&fontsize=14&hidenavigation=1&theme=dark&view=preview"
style="width:100%; height:400px; border:0; border-radius: 4px; overflow:hidden;"
title="Joy UI - Human Interface Guidelines Typography System"
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
></iframe>
### Sync the color mode
To sync the color mode between the providers, call `setMode` from both of the libraries:
```js
import { useColorScheme as useJoyColorScheme } from '@mui/joy/styles';
import { useColorScheme as useMaterialColorScheme } from '@mui/material/styles';
const ModeToggle = () => {
const { mode, setMode: setMaterialMode } = useMaterialColorScheme();
const { setMode: setJoyMode } = useJoyColorScheme();
const [mounted, setMounted] = React.useState(false);
React.useEffect(() => {
setMounted(true);
}, []);
if (!mounted) {
// prevent server-side rendering mismatch
// because `mode` is undefined on the server.
return null;
}
return (
<IconButton
onClick={() => {
setMaterialMode(mode === 'dark' ? 'light' : 'dark');
setJoyMode(mode === 'dark' ? 'light' : 'dark');
}}
>
{/** You can use `mode` from Joy UI or Material UI since they are synced **/}
{mode === 'dark' ? <DarkMode /> : <LightMode />}
</IconButton>
);
};
```
## Caveat
Both libraries have the same class name prefix:
```js
import MaterialTypography, {
typographyClasses as materialTypographyClasses,
} from '@mui/material/Typography';
import JoyTypography, {
typographyClasses as joyTyographyClasses,
} from '@mui/joy/Typography';
import Stack from '@mui/material/Stack';
<Stack
sx={{
// similar to `& .${joyTyographyClasses.root}`
[`& .${materialTypographyClasses.root}`]: {
color: 'red',
},
}}
>
{/* Both components are red. */}
<MaterialTypography>Red</MaterialTypography>
<JoyTypography>Red</JoyTypography>
</Stack>;
```
Joy UI and Material UI components have a different name for [theming the components](/joy-ui/customization/themed-components/#component-identifier). For example, Joy UI's Button uses `JoyButton` whereas Material UI's Button uses `MuiButton`.

View File

@@ -0,0 +1,154 @@
# Next.js App Router
<p class="description">Learn how to use Joy UI with the Next.js App Router.</p>
## Example
Starting fresh on a new App Router-based project?
Jump right into the code with [this example: Joy UI - Next.js App Router with TypeScript](https://github.com/mui/material-ui/tree/master/examples/joy-ui-nextjs-ts).
## Next.js and React Server Components
The Next.js App Router implements React Server Components, [an upcoming feature for React](https://github.com/reactjs/rfcs/blob/main/text/0227-server-module-conventions.md).
To support the App Router, the components and hooks from Joy UI that need access to browser APIs are exported with the `"use client"` directive.
:::warning
React Server Components should not be conflated with the concept of server-side rendering (SSR).
So-called Client Components are still server-rendered to HTML.
For more details, see [this explanation](https://github.com/reactwg/server-components/discussions/4) of Client Components and SSR from the React Working Group.
:::
## Using Joy UI with the App Router
To set up Joy UI, create a custom `ThemeRegistry` component that combines the Emotion `CacheProvider`, Joy UI's `CssVarsProvider` and the `useServerInsertedHTML` hook from `next/navigation` as follows:
```tsx
// app/ThemeRegistry.tsx
'use client';
import createCache from '@emotion/cache';
import { useServerInsertedHTML } from 'next/navigation';
import { CacheProvider } from '@emotion/react';
import { CssVarsProvider } from '@mui/joy/styles';
import CssBaseline from '@mui/joy/CssBaseline';
import theme from '/path/to/custom/theme'; // OPTIONAL
// This implementation is from emotion-js
// https://github.com/emotion-js/emotion/issues/2928#issuecomment-1319747902
export default function ThemeRegistry(props) {
const { options, children } = props;
const [{ cache, flush }] = React.useState(() => {
const cache = createCache(options);
cache.compat = true;
const prevInsert = cache.insert;
let inserted: string[] = [];
cache.insert = (...args) => {
const serialized = args[1];
if (cache.inserted[serialized.name] === undefined) {
inserted.push(serialized.name);
}
return prevInsert(...args);
};
const flush = () => {
const prevInserted = inserted;
inserted = [];
return prevInserted;
};
return { cache, flush };
});
useServerInsertedHTML(() => {
const names = flush();
if (names.length === 0) {
return null;
}
let styles = '';
for (const name of names) {
styles += cache.inserted[name];
}
return (
<style
key={cache.key}
data-emotion={`${cache.key} ${names.join(' ')}`}
dangerouslySetInnerHTML={{
__html: styles,
}}
/>
);
});
return (
<CacheProvider value={cache}>
<CssVarsProvider theme={theme}>
{/* the custom theme is optional */}
<CssBaseline />
{children}
</CssVarsProvider>
</CacheProvider>
);
}
// app/layout.tsx
export default function RootLayout(props) {
return (
<html lang="en">
<body>
<ThemeRegistry options={{ key: 'joy' }}>{props.children}</ThemeRegistry>
</body>
</html>
);
}
```
## Props serialization
Props passed from server components-for example `page.js` or other routing files-must be [serializable](https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#passing-props-from-server-to-client-components-serialization).
:::success
This works without any additional directives:
```tsx
// app/page.tsx
import Sheet from '@mui/joy/Sheet';
import Typography from '@mui/joy/Typography';
export default function Page() {
return (
<Sheet>
<Typography fontSize="sm">Hello World</Typography>
</Sheet>
);
}
```
:::
:::error
This _doesn't work_ because the Button's click handler is **non-serializable**:
```tsx
// app/page.tsx
import Button from '@mui/joy/Button';
import Sheet from '@mui/joy/Sheet';
export default function Page() {
return (
<Sheet>
{/* Next.js won't render this button without 'use-client' */}
<Button
onClick={() => {
console.log('handle click');
}}
>
Submit
</Button>
</Sheet>
);
}
```
Instead, the Next.js team recommend moving components like these ["down the tree"](https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#moving-client-components-down-the-tree) to avoid this issue and improve overall performance.
:::