docs(bep): define shared AI assets repo and cli support
this PR introduces BEP for backstage managed AI assets in the backstage monorepo that can be shared with backstage contributors and adaptors. added first skill to the docs to test this out. locally it's possible to run: npx skills add ./docs which adds the mui-to-bui skill to be used. Signed-off-by: Hellgren Heikki <heikki.hellgren@op.fi>
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"skills": [
|
||||
{
|
||||
"name": "mui-to-bui-migration",
|
||||
"description": "Migrate Backstage plugins from Material-UI (MUI) to Backstage UI (BUI). Use this skill when migrating components, updating imports, replacing styling patterns, or converting MUI components to their BUI equivalents.",
|
||||
"files": ["SKILL.md"]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,781 @@
|
||||
---
|
||||
name: mui-to-bui-migration
|
||||
description: Migrate Backstage plugins from Material-UI (MUI) to Backstage UI (BUI). Use this skill when migrating components, updating imports, replacing styling patterns, or converting MUI components to their BUI equivalents.
|
||||
---
|
||||
|
||||
# MUI to BUI Migration Skill
|
||||
|
||||
This skill helps migrate Backstage plugins from Material-UI (@material-ui/core, @material-ui/icons) to Backstage UI (
|
||||
@backstage/ui).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before starting migration:
|
||||
|
||||
1. Install the BUI package:
|
||||
|
||||
```bash
|
||||
yarn add @backstage/ui
|
||||
```
|
||||
|
||||
2. Add the CSS import to your root file (typically `src/index.ts` or app entry point):
|
||||
```typescript
|
||||
import '@backstage/ui/css/styles.css';
|
||||
```
|
||||
|
||||
## Available BUI Components
|
||||
|
||||
### Layout Components
|
||||
|
||||
- `Box` - Basic layout container with CSS properties
|
||||
- `Container` - Centered content container with max-width
|
||||
- `Grid` - CSS Grid-based layout (`Grid.Root`, `Grid.Item`)
|
||||
- `Flex` - `Flexbox` layout component
|
||||
|
||||
### UI Components
|
||||
|
||||
- `Accordion` - Collapsible content panels
|
||||
- `Avatar` - User/entity avatars
|
||||
- `Button` - Primary action buttons (`variant="primary"`, `variant="secondary"`, `isDisabled`)
|
||||
- `ButtonIcon` - Icon-only buttons (`icon`, `onPress`, `variant`)
|
||||
- `ButtonLink` - Link styled as button
|
||||
- `Card` - Content cards (`Card`, `CardHeader`, `CardBody`, `CardFooter`)
|
||||
- `Checkbox` - Checkbox input
|
||||
- `Dialog` - Modal dialogs (`DialogTrigger`, `Dialog`, `DialogHeader`, `DialogBody`, `DialogFooter`)
|
||||
- `Header` - Page headers
|
||||
- `HeaderPage` - Full page header component
|
||||
- `Link` - Navigation links
|
||||
- `Menu` - Dropdown menus (`MenuTrigger`, `Menu`, `MenuItem`)
|
||||
- `PasswordField` - Password input field
|
||||
- `Popover` - Popover overlays
|
||||
- `RadioGroup` - Radio button groups
|
||||
- `SearchField` - Search input
|
||||
- `Select` - Dropdown select
|
||||
- `Skeleton` - Loading skeleton
|
||||
- `Switch` - Toggle switch
|
||||
- `Table` - Data tables
|
||||
- `Tabs` - Tab navigation (`Tabs`, `TabList`, `Tab`, `TabPanel`)
|
||||
- `Tag` - Tag/chip component (replaces MUI Chip)
|
||||
- `TagGroup` - Tag/chip groups
|
||||
- `Text` - Typography component (`variant`, `color`)
|
||||
- `TextField` - Text input (`isRequired`, `onChange` receives string directly)
|
||||
- `ToggleButton` - Toggle buttons
|
||||
- `ToggleButtonGroup` - Grouped toggle buttons
|
||||
- `Tooltip` - Tooltip overlays (used with TooltipTrigger from react-aria-components)
|
||||
- `VisuallyHidden` - Accessibility helper
|
||||
|
||||
### Hooks
|
||||
|
||||
- `useBreakpoint` - Responsive breakpoint hook
|
||||
|
||||
## Migration Patterns
|
||||
|
||||
### 1. Import Changes
|
||||
|
||||
**Remove MUI imports:**
|
||||
|
||||
```typescript
|
||||
// REMOVE these imports
|
||||
import { Box, Typography, Tooltip, Paper } from '@material-ui/core';
|
||||
import { makeStyles, Theme } from '@material-ui/core/styles';
|
||||
import SomeIcon from '@material-ui/icons/SomeIcon';
|
||||
```
|
||||
|
||||
**Add BUI imports:**
|
||||
|
||||
```typescript
|
||||
// ADD these imports
|
||||
import { Box, Flex, Text, Tooltip, Card } from '@backstage/ui';
|
||||
import { RiSomeIcon } from '@remixicon/react';
|
||||
import styles from './MyComponent.module.css';
|
||||
```
|
||||
|
||||
### 2. Styling: `makeStyles` to CSS Modules
|
||||
|
||||
Create a `.module.css` file alongside your component using BUI CSS variables.
|
||||
|
||||
**Before (MUI `makeStyles`):**
|
||||
|
||||
```typescript
|
||||
// MyComponent.tsx
|
||||
import {makeStyles, Theme} from '@material-ui/core/styles';
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => ({
|
||||
container: {
|
||||
padding: theme.spacing(2),
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
},
|
||||
title: {
|
||||
marginBottom: theme.spacing(1),
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
listItem: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
},
|
||||
icon: {
|
||||
minWidth: 56,
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
}));
|
||||
|
||||
function MyComponent() {
|
||||
const classes = useStyles();
|
||||
return (
|
||||
<div className = {classes.container} >
|
||||
<Typography className = {classes.title} > Title < /Typography>
|
||||
< div
|
||||
className = {classes.listItem} >
|
||||
<div className = {classes.icon} >
|
||||
<SomeIcon / >
|
||||
</div>
|
||||
< span > Content < /span>
|
||||
< /div>
|
||||
< /div>
|
||||
)
|
||||
;
|
||||
}
|
||||
```
|
||||
|
||||
**After (CSS Modules with BUI variables):**
|
||||
|
||||
```css
|
||||
/* MyComponent.module.css */
|
||||
@layer components {
|
||||
.container {
|
||||
padding: var(--bui-space-4);
|
||||
background-color: var(--bui-bg-surface-1);
|
||||
border-radius: var(--bui-radius-2);
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-bottom: var(--bui-space-2);
|
||||
color: var(--bui-fg-primary);
|
||||
}
|
||||
|
||||
.listItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: var(--bui-space-2) 0;
|
||||
}
|
||||
|
||||
.icon {
|
||||
min-width: 56px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--bui-fg-secondary);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
// MyComponent.tsx
|
||||
import {Box, Text} from '@backstage/ui';
|
||||
import {RiSomeIcon} from '@remixicon/react';
|
||||
import styles from './MyComponent.module.css';
|
||||
|
||||
function MyComponent() {
|
||||
return (
|
||||
<Box className = {styles.container} >
|
||||
<Text className = {styles.title} > Title < /Text>
|
||||
< div
|
||||
className = {styles.listItem} >
|
||||
<div className = {styles.icon} >
|
||||
<RiSomeIcon size = {24}
|
||||
/>
|
||||
< /div>
|
||||
< span > Content < /span>
|
||||
< /div>
|
||||
< /Box>
|
||||
)
|
||||
;
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Layout: Box with display to `Flex`
|
||||
|
||||
**Before (MUI Box with display prop):**
|
||||
|
||||
```typescript
|
||||
<Box
|
||||
display = "flex"
|
||||
flexDirection = "column"
|
||||
alignItems = "center"
|
||||
justifyContent = "space-between"
|
||||
>
|
||||
<Box display = "flex"
|
||||
flexDirection = "row"
|
||||
gap = {2} >
|
||||
{children}
|
||||
< /Box>
|
||||
< /Box>
|
||||
```
|
||||
|
||||
**After (BUI `Flex` component):**
|
||||
|
||||
```typescript
|
||||
<Flex direction = "column"
|
||||
align = "center"
|
||||
justify = "between" >
|
||||
<Flex direction = "row"
|
||||
style = {
|
||||
{
|
||||
gap: 'var(--bui-space-4)'
|
||||
}
|
||||
}>
|
||||
{
|
||||
children
|
||||
}
|
||||
</Flex>
|
||||
< /Flex>
|
||||
```
|
||||
|
||||
Note: BUI `Flex` uses `justify="between"` not `justify="space-between"`.
|
||||
|
||||
### 4. Grid Layout
|
||||
|
||||
**Before (MUI Grid):**
|
||||
|
||||
```typescript
|
||||
<Grid container
|
||||
spacing = {3} >
|
||||
<Grid item
|
||||
xs = {12}
|
||||
md = {6} >
|
||||
{content}
|
||||
< /Grid>
|
||||
< /Grid>
|
||||
```
|
||||
|
||||
**After (BUI Grid):**
|
||||
|
||||
```typescript
|
||||
<Grid.Root columns = {
|
||||
{
|
||||
sm: '12'
|
||||
}
|
||||
}
|
||||
gap = "6" >
|
||||
<Grid.Item colSpan = {
|
||||
{
|
||||
sm: '12', md
|
||||
:
|
||||
'6'
|
||||
}
|
||||
}>
|
||||
{
|
||||
content
|
||||
}
|
||||
</Grid.Item>
|
||||
< /Grid.Root>
|
||||
```
|
||||
|
||||
### 5. Typography to Text
|
||||
|
||||
**Before (MUI Typography):**
|
||||
|
||||
```typescript
|
||||
<Typography variant = "h1" > Heading < /Typography>
|
||||
< Typography
|
||||
variant = "h6" > Subheading < /Typography>
|
||||
< Typography
|
||||
variant = "body1" > Body
|
||||
text < /Typography>
|
||||
< Typography
|
||||
variant = "body2"
|
||||
color = "textSecondary" > Secondary
|
||||
text < /Typography>
|
||||
```
|
||||
|
||||
**After (BUI Text):**
|
||||
|
||||
```typescript
|
||||
<Text variant = "title-large" > Heading < /Text>
|
||||
< Text
|
||||
variant = "title-small" > Subheading < /Text>
|
||||
< Text
|
||||
variant = "body-medium" > Body
|
||||
text < /Text>
|
||||
< Text
|
||||
variant = "body-small"
|
||||
color = "secondary" > Secondary
|
||||
text < /Text>
|
||||
```
|
||||
|
||||
Valid Text variants: `title-large`, `title-medium`, `title-small`, `title-x-small`, `body-large`, `body-medium`,
|
||||
`body-small`, `body-x-small`
|
||||
|
||||
### 6. Tooltip Pattern
|
||||
|
||||
**Before (MUI Tooltip):**
|
||||
|
||||
```typescript
|
||||
import {Tooltip, Typography} from '@material-ui/core';
|
||||
|
||||
<Tooltip title = { < Typography > Tooltip
|
||||
content < /Typography>}>
|
||||
< span > Hover
|
||||
me < /span>
|
||||
< /Tooltip>;
|
||||
```
|
||||
|
||||
**After (BUI TooltipTrigger pattern):**
|
||||
|
||||
```typescript
|
||||
import {Tooltip, Text} from '@backstage/ui';
|
||||
import {TooltipTrigger} from 'react-aria-components';
|
||||
|
||||
<TooltipTrigger>
|
||||
<Text>Hover
|
||||
me < /Text>
|
||||
< Tooltip > Tooltip
|
||||
content < /Tooltip>
|
||||
< /TooltipTrigger>;
|
||||
```
|
||||
|
||||
Note: Add `react-aria-components` to your dependencies.
|
||||
|
||||
### 7. Dialog Pattern
|
||||
|
||||
**Before (MUI Dialog):**
|
||||
|
||||
```typescript
|
||||
import {Dialog, DialogTitle, DialogActions, Button} from '@material-ui/core';
|
||||
|
||||
<Dialog open = {isOpen}
|
||||
onClose = {onClose} >
|
||||
<DialogTitle>Title < /DialogTitle>
|
||||
< DialogActions >
|
||||
<Button onClick = {onClose} > Cancel < /Button>
|
||||
< Button
|
||||
onClick = {onConfirm}
|
||||
color = "primary" >
|
||||
Confirm
|
||||
< /Button>
|
||||
< /DialogActions>
|
||||
< /Dialog>;
|
||||
```
|
||||
|
||||
**After (BUI Dialog):**
|
||||
|
||||
```typescript
|
||||
import {
|
||||
Dialog,
|
||||
DialogTrigger,
|
||||
DialogHeader,
|
||||
DialogFooter,
|
||||
Button,
|
||||
} from '@backstage/ui';
|
||||
|
||||
<DialogTrigger>
|
||||
<Dialog
|
||||
isOpen = {isOpen}
|
||||
isDismissable
|
||||
onOpenChange = {open
|
||||
=>
|
||||
{
|
||||
if (!open) onClose();
|
||||
}
|
||||
}
|
||||
>
|
||||
<DialogHeader>Title < /DialogHeader>
|
||||
< DialogFooter >
|
||||
<Button onClick = {onConfirm}
|
||||
variant = "primary" >
|
||||
Confirm
|
||||
< /Button>
|
||||
< Button
|
||||
onClick = {onClose}
|
||||
variant = "secondary"
|
||||
slot = "close" >
|
||||
Cancel
|
||||
< /Button>
|
||||
< /DialogFooter>
|
||||
< /Dialog>
|
||||
< /DialogTrigger>;
|
||||
```
|
||||
|
||||
### 8. Button Changes
|
||||
|
||||
**Before (MUI Button):**
|
||||
|
||||
```typescript
|
||||
<Button variant = "contained"
|
||||
color = "primary"
|
||||
disabled = {loading}
|
||||
onClick = {handleClick} >
|
||||
Submit
|
||||
< /Button>
|
||||
< IconButton
|
||||
onClick = {handleDelete}
|
||||
disabled = {!
|
||||
canDelete
|
||||
}>
|
||||
<DeleteIcon / >
|
||||
</IconButton>
|
||||
```
|
||||
|
||||
**After (BUI Button):**
|
||||
|
||||
```typescript
|
||||
<Button variant = "primary"
|
||||
isDisabled = {loading}
|
||||
onClick = {handleClick} >
|
||||
Submit
|
||||
< /Button>
|
||||
< ButtonIcon
|
||||
aria - label = "delete"
|
||||
isDisabled = {!
|
||||
canDelete
|
||||
}
|
||||
onPress = {handleDelete}
|
||||
icon = { < RiDeleteBinLine
|
||||
size = {16}
|
||||
/>}
|
||||
variant = "secondary"
|
||||
/ >
|
||||
```
|
||||
|
||||
### 9. TextField Changes
|
||||
|
||||
**Before (MUI TextField):**
|
||||
|
||||
```typescript
|
||||
<TextField
|
||||
required
|
||||
name="title"
|
||||
label="Title"
|
||||
value={value}
|
||||
onChange={e => setValue(e.target.value)}
|
||||
fullWidth
|
||||
/>
|
||||
```
|
||||
|
||||
**After (BUI TextField):**
|
||||
|
||||
```typescript
|
||||
<TextField
|
||||
isRequired
|
||||
id="title"
|
||||
label="Title"
|
||||
value={value}
|
||||
onChange={newValue => setValue(newValue)} // receives string directly!
|
||||
/>
|
||||
```
|
||||
|
||||
Note: BUI TextField `onChange` receives the string value directly, not an event object.
|
||||
|
||||
### 10. Tabs Pattern
|
||||
|
||||
**Before (MUI Tabs):**
|
||||
|
||||
```typescript
|
||||
import {Tab} from '@material-ui/core';
|
||||
import {TabContext, TabList, TabPanel} from '@material-ui/lab';
|
||||
|
||||
<TabContext value = {tab} >
|
||||
<TabList onChange = {handleChange} >
|
||||
<Tab label = "Tab 1"
|
||||
value = "tab1" / >
|
||||
<Tab label = "Tab 2"
|
||||
value = "tab2" / >
|
||||
</TabList>
|
||||
< TabPanel
|
||||
value = "tab1" > Content
|
||||
1 < /TabPanel>
|
||||
< TabPanel
|
||||
value = "tab2" > Content
|
||||
2 < /TabPanel>
|
||||
< /TabContext>;
|
||||
```
|
||||
|
||||
**After (BUI Tabs):**
|
||||
|
||||
```typescript
|
||||
import {Tabs, TabList, Tab, TabPanel} from '@backstage/ui';
|
||||
|
||||
<Tabs defaultSelectedKey = "tab1" >
|
||||
<TabList>
|
||||
<Tab id = "tab1" > Tab
|
||||
1 < /Tab>
|
||||
< Tab
|
||||
id = "tab2" > Tab
|
||||
2 < /Tab>
|
||||
< /TabList>
|
||||
< TabPanel
|
||||
id = "tab1" > Content
|
||||
1 < /TabPanel>
|
||||
< TabPanel
|
||||
id = "tab2" > Content
|
||||
2 < /TabPanel>
|
||||
< /Tabs>;
|
||||
```
|
||||
|
||||
### 11. Menu Pattern
|
||||
|
||||
**Before (MUI Menu):**
|
||||
|
||||
```typescript
|
||||
import {IconButton, Popover, MenuList, MenuItem} from '@material-ui/core';
|
||||
import MoreVertIcon from '@material-ui/icons/MoreVert';
|
||||
|
||||
<IconButton onClick = {handleOpen} > <MoreVertIcon / > </IconButton>
|
||||
< Popover
|
||||
open = {open}
|
||||
anchorEl = {anchorEl}
|
||||
onClose = {handleClose} >
|
||||
<MenuList>
|
||||
<MenuItem onClick = {handleAction} > Action < /MenuItem>
|
||||
< /MenuList>
|
||||
< /Popover>
|
||||
```
|
||||
|
||||
**After (BUI Menu):**
|
||||
|
||||
```typescript
|
||||
import {ButtonIcon, Menu, MenuItem, MenuTrigger} from '@backstage/ui';
|
||||
import {RiMore2Line} from '@remixicon/react';
|
||||
|
||||
<MenuTrigger>
|
||||
<ButtonIcon aria - label = "more"
|
||||
icon = { < RiMore2Line / >
|
||||
}
|
||||
variant = "secondary" / >
|
||||
<Menu>
|
||||
<MenuItem onAction = {handleAction} > Action < /MenuItem>
|
||||
< /Menu>
|
||||
< /MenuTrigger>;
|
||||
```
|
||||
|
||||
### 12. List to HTML with CSS Modules
|
||||
|
||||
**Before (MUI List):**
|
||||
|
||||
```typescript
|
||||
import {List, ListItem, ListItemIcon, ListItemText} from '@material-ui/core';
|
||||
|
||||
<List>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<SomeIcon / >
|
||||
</ListItemIcon>
|
||||
< ListItemText
|
||||
primary = "Title"
|
||||
secondary = "Description" / >
|
||||
</ListItem>
|
||||
< /List>;
|
||||
```
|
||||
|
||||
**After (HTML list with BUI and CSS Modules):**
|
||||
|
||||
```css
|
||||
/* MyList.module.css */
|
||||
@layer components {
|
||||
.list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.listItem {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: var(--bui-space-2) 0;
|
||||
}
|
||||
|
||||
.listItemIcon {
|
||||
min-width: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--bui-fg-primary);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
import {Flex, Text} from '@backstage/ui';
|
||||
import {RiSomeIcon} from '@remixicon/react';
|
||||
import styles from './MyList.module.css';
|
||||
|
||||
<ul className = {styles.list} >
|
||||
<li className = {styles.listItem} >
|
||||
<div className = {styles.listItemIcon} >
|
||||
<RiSomeIcon size = {20}
|
||||
/>
|
||||
< /div>
|
||||
< Flex
|
||||
direction = "column" >
|
||||
<Text>Title < /Text>
|
||||
< Text
|
||||
variant = "body-small"
|
||||
color = "secondary" >
|
||||
Description
|
||||
< /Text>
|
||||
< /Flex>
|
||||
< /li>
|
||||
< /ul>;
|
||||
```
|
||||
|
||||
### 13. Chip to Tag
|
||||
|
||||
**Before (MUI Chip):**
|
||||
|
||||
```typescript
|
||||
import { Chip } from '@material-ui/core';
|
||||
|
||||
<Chip label="Category" size="small" />;
|
||||
```
|
||||
|
||||
**After (BUI Tag):**
|
||||
|
||||
```typescript
|
||||
import {Tag} from '@backstage/ui';
|
||||
|
||||
<Tag size = "small" > Category < /Tag>;
|
||||
```
|
||||
|
||||
### 14. Icons: MUI Icons to Remix Icons
|
||||
|
||||
**Before (MUI Icons):**
|
||||
|
||||
```typescript
|
||||
import CloseIcon from '@material-ui/icons/Close';
|
||||
import SearchIcon from '@material-ui/icons/Search';
|
||||
|
||||
<CloseIcon / >
|
||||
<SearchIcon fontSize = "small" / >
|
||||
```
|
||||
|
||||
**After (Remix Icons):**
|
||||
|
||||
```typescript
|
||||
import {RiCloseLine, RiSearchLine} from '@remixicon/react';
|
||||
|
||||
<RiCloseLine / >
|
||||
<RiSearchLine size = {16}
|
||||
/>
|
||||
```
|
||||
|
||||
Common icon mappings:
|
||||
|
||||
| MUI Icon | Remix Icon |
|
||||
| ----------------- | -------------------- |
|
||||
| `Close` | `RiCloseLine` |
|
||||
| `Search` | `RiSearchLine` |
|
||||
| `Settings` | `RiSettingsLine` |
|
||||
| `Add` | `RiAddLine` |
|
||||
| `Delete` | `RiDeleteBinLine` |
|
||||
| `Edit` | `RiEditLine` |
|
||||
| `Check` | `RiCheckLine` |
|
||||
| `Error` | `RiErrorWarningLine` |
|
||||
| `Warning` | `RiAlertLine` |
|
||||
| `Info` | `RiInformationLine` |
|
||||
| `ExpandMore` | `RiArrowDownSLine` |
|
||||
| `ExpandLess` | `RiArrowUpSLine` |
|
||||
| `ChevronRight` | `RiArrowRightSLine` |
|
||||
| `ChevronLeft` | `RiArrowLeftSLine` |
|
||||
| `Menu` | `RiMenuLine` |
|
||||
| `MoreVert` | `RiMore2Line` |
|
||||
| `Visibility` | `RiEyeLine` |
|
||||
| `VisibilityOff` | `RiEyeOffLine` |
|
||||
| `NewReleases` | `RiMegaphoneLine` |
|
||||
| `RecordVoiceOver` | `RiMegaphoneLine` |
|
||||
| `Description` | `RiFileTextLine` |
|
||||
|
||||
Find more icons at: https://remixicon.com/
|
||||
|
||||
## CSS Variable Reference
|
||||
|
||||
### Spacing
|
||||
|
||||
| MUI theme.spacing() | BUI CSS Variable |
|
||||
| -------------------- | -------------------- |
|
||||
| `theme.spacing(0.5)` | `var(--bui-space-1)` |
|
||||
| `theme.spacing(1)` | `var(--bui-space-2)` |
|
||||
| `theme.spacing(1.5)` | `var(--bui-space-3)` |
|
||||
| `theme.spacing(2)` | `var(--bui-space-4)` |
|
||||
| `theme.spacing(3)` | `var(--bui-space-6)` |
|
||||
| `theme.spacing(4)` | `var(--bui-space-8)` |
|
||||
|
||||
### Colors
|
||||
|
||||
| MUI theme.palette | BUI CSS Variable |
|
||||
| -------------------- | ------------------------------------------ |
|
||||
| `text.primary` | `var(--bui-fg-primary)` |
|
||||
| `text.secondary` | `var(--bui-fg-secondary)` |
|
||||
| `background.paper` | `var(--bui-bg-surface-1)` |
|
||||
| `background.default` | `var(--bui-bg-surface-0)` |
|
||||
| `primary.main` | `var(--bui-bg-solid)` or `var(--bui-ring)` |
|
||||
| `error.main` | `var(--bui-fg-danger)` |
|
||||
| `action.hover` | `var(--bui-bg-hover)` |
|
||||
| `divider` | `var(--bui-border)` |
|
||||
|
||||
### Typography
|
||||
|
||||
| Property | BUI CSS Variable |
|
||||
| ------------------- | -------------------------------- |
|
||||
| Font family | `var(--bui-font-regular)` |
|
||||
| Font size small | `var(--bui-font-size-1)` |
|
||||
| Font size medium | `var(--bui-font-size-2)` |
|
||||
| Font size large | `var(--bui-font-size-3)` |
|
||||
| Font weight regular | `var(--bui-font-weight-regular)` |
|
||||
| Font weight bold | `var(--bui-font-weight-bold)` |
|
||||
|
||||
### Other
|
||||
|
||||
| Property | BUI CSS Variable |
|
||||
| -------------------- | ------------------------ |
|
||||
| Border radius small | `var(--bui-radius-2)` |
|
||||
| Border radius medium | `var(--bui-radius-3)` |
|
||||
| Border radius full | `var(--bui-radius-full)` |
|
||||
| Link color | `var(--bui-fg-link)` |
|
||||
|
||||
## Known Limitations
|
||||
|
||||
Some Backstage APIs still require MUI-compatible icon types:
|
||||
|
||||
- **NavItemBlueprint** (`@backstage/frontend-plugin-api`): The `icon` prop expects MUI `IconComponent` type. Remix icons
|
||||
are not type-compatible.
|
||||
- **Timeline** (`@material-ui/lab`): No BUI equivalent exists.
|
||||
- **Pagination** (`@material-ui/lab`): No BUI equivalent exists.
|
||||
- **Alert** (`@material-ui/lab`): No BUI equivalent exists.
|
||||
|
||||
For these cases, keep using MUI components.
|
||||
|
||||
## Migration Checklist
|
||||
|
||||
When migrating a plugin:
|
||||
|
||||
1. [ ] Add `@backstage/ui` dependency
|
||||
2. [ ] Add `@remixicon/react` dependency (if using icons)
|
||||
3. [ ] Add `react-aria-components` dependency (if using Tooltip)
|
||||
4. [ ] Add CSS import to root file
|
||||
5. [ ] Remove `@material-ui/core` imports (except components with no BUI equivalent)
|
||||
6. [ ] Remove `@material-ui/icons` imports
|
||||
7. [ ] Remove `makeStyles` and related imports
|
||||
8. [ ] Create `.module.css` files for component styles
|
||||
9. [ ] Replace `Typography` with `Text`
|
||||
10. [ ] Replace `Box display="flex"` with `Flex`
|
||||
11. [ ] Replace `Grid container/item` with `Grid.Root/Grid.Item`
|
||||
12. [ ] Replace `Paper` with `Card`
|
||||
13. [ ] Replace MUI `Dialog` with BUI `DialogTrigger` pattern
|
||||
14. [ ] Replace MUI `Tooltip` with BUI `TooltipTrigger` pattern
|
||||
15. [ ] Replace MUI `Tabs` with BUI `Tabs`
|
||||
16. [ ] Replace MUI `Menu` with BUI `MenuTrigger` pattern
|
||||
17. [ ] Replace `Chip` with `Tag`
|
||||
18. [ ] Replace `IconButton` with `ButtonIcon`
|
||||
19. [ ] Update `Button` props (`disabled` → `isDisabled`, `variant="contained"` → `variant="primary"`)
|
||||
20. [ ] Update `TextField` props (`required` → `isRequired`, `onChange` signature)
|
||||
21. [ ] Replace MUI icons with Remix icons
|
||||
22. [ ] Run `yarn tsc` to check for type errors
|
||||
23. [ ] Run `yarn build` to verify build
|
||||
24. [ ] Run `yarn lint` to check for missing dependencies
|
||||
25. [ ] Test component rendering and functionality
|
||||
|
||||
## Reference
|
||||
|
||||
- BUI Documentation: https://ui.backstage.io
|
||||
- Remix Icons: https://remixicon.com/
|
||||
- Example Migration PR: https://github.com/backstage/backstage/pull/31631
|
||||
Reference in New Issue
Block a user