Merge branch 'master' into bui-text

This commit is contained in:
Charles de Dreuille
2025-07-22 09:38:49 +01:00
81 changed files with 1036 additions and 1224 deletions
+1 -1
View File
@@ -22,6 +22,7 @@
"@mdx-js/loader": "^3.1.0",
"@mdx-js/react": "^3.1.0",
"@next/mdx": "15.3.4",
"@remixicon/react": "^4.6.0",
"@storybook/react": "^8.6.8",
"@uiw/codemirror-themes": "^4.23.7",
"@uiw/react-codemirror": "^4.23.7",
@@ -32,7 +33,6 @@
"prop-types": "^15.8.1",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-frame-component": "^5.2.7",
"shiki": "^1.26.1",
"storybook": "^8.6.8"
},
-6
View File
@@ -1,6 +0,0 @@
.pageContainer {
width: 100%;
max-width: 960px;
margin: 0 auto;
padding: 0 24px 64px;
}
-16
View File
@@ -1,16 +0,0 @@
import type { Metadata } from 'next';
import styles from './layout.module.css';
export const metadata: Metadata = {
title: 'Backstage UI',
description: 'UI library for Backstage',
};
export default function DocsLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return <div className={styles.pageContainer}>{children}</div>;
}
@@ -1,87 +0,0 @@
'use client';
import { ReactNode } from 'react';
import { Grid, Flex, Text } from '../../../../../packages/ui';
import { screenSizes } from '@/utils/data';
import { Frame } from '@/components/Frame';
import { usePlayground } from '@/utils/playground-context';
import {
ButtonSnippet,
CheckboxSnippet,
HeadingSnippet,
TextSnippet,
} from '@/snippets/stories-snippets';
import styles from './styles.module.css';
export default function PlaygroundPage() {
const { selectedScreenSizes } = usePlayground();
const filteredScreenSizes = screenSizes.filter(item =>
selectedScreenSizes.includes(item.slug),
);
if (filteredScreenSizes.length === 0) {
return (
<div className={styles.containerEmpty}>
<Content />
</div>
);
}
return (
<div className={styles.container}>
{filteredScreenSizes.map(screenSize => (
<div
className={styles.breakpointContainer}
style={{ width: screenSize.width }}
key={screenSize.slug}
>
<Text>
{screenSize.title} - {screenSize.width}px
</Text>
<div className={styles.breakpointContent}>
<Frame>
<Content />
</Frame>
</div>
</div>
))}
</div>
);
}
const Content = () => {
const { selectedComponents } = usePlayground();
return (
<Flex direction="column" gap="4">
{selectedComponents.find(c => c === 'button') && (
<Line content={<ButtonSnippet story="Playground" />} title="Button" />
)}
{selectedComponents.find(c => c === 'checkbox') && (
<Line
content={<CheckboxSnippet story="Playground" />}
title="Checkbox"
/>
)}
{selectedComponents.find(c => c === 'heading') && (
<Line content={<HeadingSnippet story="Playground" />} title="Heading" />
)}
{selectedComponents.find(c => c === 'text') && (
<Line content={<TextSnippet story="Playground" />} title="Text" />
)}
</Flex>
);
};
const Line = ({ content, title }: { content: ReactNode; title: string }) => {
return (
<Grid.Root gap={{ xs: '2', md: '4' }}>
<Grid.Item colSpan="2">
<Text>{title}</Text>
</Grid.Item>
<Grid.Item colSpan="10">{content}</Grid.Item>
</Grid.Root>
);
};
@@ -1,36 +0,0 @@
.container {
height: 100vh;
display: flex;
flex-direction: row;
gap: 24px;
overflow-x: scroll;
}
.containerEmpty {
padding: 78px 40px;
}
.breakpointContainer {
flex-shrink: 0;
margin-top: 40px;
height: calc(100vh - 86px);
display: flex;
flex-direction: column;
gap: 8px;
&:first-child {
margin-left: 48px;
}
&:last-child {
margin-right: 48px;
}
}
.breakpointContent {
height: 100%;
border-radius: 4px;
border: 1px solid var(--border);
background-color: var(--bg);
padding: 16px;
}
+28
View File
@@ -0,0 +1,28 @@
.container {
position: relative;
z-index: 20;
width: calc(100% - 64px);
margin-inline: 0 16px;
margin-left: 32px;
margin-right: 32px;
margin-top: 112px;
margin-bottom: 48px;
padding-inline: 40px;
padding-block: 48px;
background-color: var(--panel);
border-radius: 0.5rem;
}
.content {
width: 100%;
max-width: 960px;
margin: 0 auto;
}
@media (min-width: 768px) {
.container {
width: calc(100% - 332px - 40px);
margin-left: 332px;
margin-right: 40px;
}
}
+27 -9
View File
@@ -3,7 +3,7 @@ import { Sidebar } from '../components/Sidebar';
import { Toolbar } from '@/components/Toolbar';
import { Providers } from './providers';
import { CustomTheme } from '@/components/CustomTheme';
import styles from '../css/page.module.css';
import styles from './layout.module.css';
import '../css/globals.css';
import '/public/theme-backstage.css';
@@ -15,11 +15,31 @@ export const metadata: Metadata = {
metadataBase: new URL('https://ui.backstage.io'),
};
export default function RootLayout({
async function getLatestPackageVersion(): Promise<string> {
try {
const response = await fetch('https://registry.npmjs.org/@backstage/ui', {
next: { revalidate: 3600 }, // Cache for 1 hour
});
if (!response.ok) {
throw new Error('Failed to fetch package info');
}
const data = await response.json();
return data['dist-tags']?.latest;
} catch (error) {
console.error('Error fetching package version:', error);
return '0.0.0';
}
}
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const packageVersion = await getLatestPackageVersion();
return (
<html
lang="en"
@@ -29,14 +49,12 @@ export default function RootLayout({
>
<body>
<Providers>
<div className={styles.global}>
<Sidebar />
<div className={styles.container}>
<Toolbar />
{children}
</div>
<CustomTheme />
<Sidebar version={packageVersion} />
<Toolbar />
<div className={styles.container}>
<div className={styles.content}>{children}</div>
</div>
<CustomTheme />
</Providers>
</body>
</html>
@@ -0,0 +1,32 @@
import { changelog } from '@/utils/changelog';
import { MDXRemote } from 'next-mdx-remote-client/rsc';
import { formattedMDXComponents } from '@/mdx-components';
import type { Component } from '@/utils/changelog';
export const ChangelogComponent = ({ component }: { component: Component }) => {
const componentChangelog = changelog.filter(c =>
c.components.includes(component),
);
return (
<MDXRemote
components={formattedMDXComponents}
source={`
## Changelog
${componentChangelog
?.map(change => {
const prs =
change.prs.length > 0 &&
change.prs
.map(
pr =>
`[#${pr}](https://github.com/backstage/backstage/pull/${pr})`,
)
.join(', ');
return `- \`${change.version}\` - ${change.description} ${prs}`;
})
.join('\n')}`}
/>
);
};
@@ -1,68 +0,0 @@
import { Tabs } from '@/components/Tabs';
import { CodeBlock } from '@/components/CodeBlock';
import type { ComponentInfosProps } from './types';
import styles from '@/css/mdx.module.css';
import Link from 'next/link';
import { changelog } from '@/utils/changelog';
import { MDXRemote } from 'next-mdx-remote-client/rsc';
import { formattedMDXComponents } from '@/mdx-components';
export const ComponentInfos = ({
usageCode,
component,
classNames,
}: ComponentInfosProps) => {
const componentChangelog = changelog.filter(c =>
c.components.includes(component),
);
return (
<Tabs.Root>
<Tabs.List>
<Tabs.Tab>Usage</Tabs.Tab>
{classNames && classNames.length > 0 && <Tabs.Tab>Theming</Tabs.Tab>}
<Tabs.Tab>Changelog</Tabs.Tab>
</Tabs.List>
<Tabs.Panel>
<CodeBlock code={usageCode} />
</Tabs.Panel>
{classNames && classNames.length > 0 && (
<Tabs.Panel>
<p className={styles.p}>
We recommend starting with our{' '}
<Link className={styles.a} href="/theme/theming">
global tokens
</Link>{' '}
to customize the library and align it with your brand. For
additional flexibility, you can use the provided class names for
each element listed below.
</p>
<MDXRemote
components={formattedMDXComponents}
source={`${classNames
?.map(className => `- \`${className}\``)
.join('\n')}`}
/>
</Tabs.Panel>
)}
<Tabs.Panel>
<MDXRemote
components={formattedMDXComponents}
source={`${componentChangelog
?.map(change => {
const prs =
change.prs.length > 0 &&
change.prs
.map(
pr =>
`[#${pr}](https://github.com/backstage/backstage/pull/${pr})`,
)
.join(', ');
return `- \`${change.version}\` - ${change.description} ${prs}`;
})
.join('\n')}`}
/>
</Tabs.Panel>
</Tabs.Root>
);
};
@@ -1 +0,0 @@
export { ComponentInfos } from './ComponentInfos';
@@ -1,9 +0,0 @@
import type { Component } from '@/utils/changelog';
import { ReactNode } from 'react';
export interface ComponentInfosProps {
usageCode?: string;
classNames?: string[];
component: Component;
children: ReactNode;
}
@@ -1,5 +1,6 @@
.container {
position: fixed;
z-index: 100;
bottom: 16px;
right: 16px;
width: 240px;
-32
View File
@@ -1,32 +0,0 @@
'use client';
import { useEffect, useState } from 'react';
import ReactFrame from 'react-frame-component';
export const Frame = ({ children }: { children: React.ReactNode }) => {
const [show, setShow] = useState(false);
useEffect(() => {
setShow(true);
}, []);
if (!show) return null;
return (
<ReactFrame
loading="lazy"
style={{ width: '100%', height: '100%' }}
initialContent={`<!DOCTYPE html><html data-theme="light"><head></head><body><div class="frame-root"></div></body></html>`}
mountTarget=".frame-root"
head={
<>
<link rel="stylesheet" href="/core.css" />
<link rel="stylesheet" href="/components.css" />
<link rel="stylesheet" href="/backstage.css" />
</>
}
>
{children}
</ReactFrame>
);
};
@@ -0,0 +1,12 @@
.container {
margin-bottom: 40px;
}
.component {
font-size: 11px;
text-transform: uppercase;
font-weight: 500;
letter-spacing: 0.05em;
color: var(--secondary);
margin-bottom: 6px;
}
@@ -0,0 +1,23 @@
import { MDXRemote } from 'next-mdx-remote-client/rsc';
import { formattedMDXComponents } from '@/mdx-components';
import styles from './PageTitle.module.css';
export const PageTitle = ({
title,
description,
type = 'component',
}: {
title: string;
type?: string;
description: string;
}) => {
return (
<div className={styles.container}>
<div className={styles.component}>{type}</div>
<MDXRemote
components={formattedMDXComponents}
source={`# ${title}\n\n${description}`}
/>
</div>
);
};
@@ -6,99 +6,46 @@
.sidebar {
display: block;
position: fixed;
top: 16px;
left: 16px;
border-radius: 8px;
width: 300px;
height: calc(100vh - 32px);
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.025);
top: 112px;
left: 0;
width: 332px;
height: calc(100vh - 112px);
color: var(--primary);
background-color: var(--panel);
border: 1px solid var(--border);
overflow: hidden;
}
}
.version {
font-size: 0.875rem;
font-weight: 500;
color: var(--secondary);
margin-inline: 32px;
border-bottom: 1px solid var(--border);
padding-bottom: 12px;
display: flex;
align-items: center;
justify-content: space-between;
}
.versionLinks {
display: flex;
align-items: center;
gap: 8px;
a {
color: var(--secondary);
transition: color 0.2s ease-in-out;
&:hover {
color: var(--primary);
}
}
}
.root {
height: 100%;
}
.viewport {
overflow: scroll;
height: 100%;
}
.content {
padding: 0 20px 20px;
}
.logoContainer {
padding-left: 6px;
padding-top: 20px;
}
.logo path {
fill: var(--primary);
}
.menu {
display: flex;
flex-direction: row;
position: relative;
}
.section {
width: 100%;
display: flex;
flex-direction: column;
gap: 2px;
}
.sectionTitle {
font-size: 0.875rem;
font-weight: 600;
padding: 12px 0;
color: var(--primary);
margin-top: 24px;
}
.line {
text-decoration: none;
align-items: center;
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 26px;
padding: 0 12px;
border-radius: 4px;
&:hover {
background-color: var(--surface-1);
transition: background-color 0.2s ease-in-out;
}
}
.line.active {
background-color: var(--surface-1);
}
.line.active .lineTitle {
color: var(--primary);
}
.lineTitle {
font-size: 14px;
font-weight: 400;
color: var(--secondary);
}
.lineStatus {
font-size: 14px;
color: var(--secondary);
}
.scrollbar {
display: flex;
justify-content: center;
@@ -110,7 +57,6 @@
transition: opacity 150ms 300ms;
right: -20px;
&[data-hovering],
&[data-scrolling] {
opacity: 1;
transition-duration: 75ms;
@@ -130,3 +76,70 @@
border-radius: inherit;
background-color: rgba(0, 0, 0, 0.2);
}
.viewport {
overflow: scroll;
height: 100%;
}
.content {
padding: 0 20px 64px;
}
.menu {
display: flex;
flex-direction: row;
position: relative;
}
.section {
width: 100%;
display: flex;
flex-direction: column;
gap: 2px;
}
.sectionTitle {
font-size: 0.6875rem;
font-weight: 500;
padding: 0 12px 4px;
color: var(--secondary);
margin-top: 40px;
text-transform: uppercase;
}
.line {
text-decoration: none;
align-items: center;
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 26px;
padding: 0 12px;
border-radius: 4px;
&:hover {
background-color: var(--action);
}
}
.line.active {
background-color: var(--action);
}
.line.active .lineTitle {
color: var(--primary);
}
.lineTitle {
font-size: 14px;
font-weight: 400;
color: var(--primary);
}
.lineStatus {
font-size: 14px;
color: var(--secondary);
}
-82
View File
@@ -1,82 +0,0 @@
'use client';
import Link from 'next/link';
import { components, overview, layoutComponents, theme } from '@/utils/data';
import { motion } from 'motion/react';
import styles from './Sidebar.module.css';
import { usePathname } from 'next/navigation';
import { Fragment } from 'react';
const data = [
{
title: 'Overview',
content: overview,
url: '',
},
{
title: 'Theme',
content: theme,
url: '/theme',
},
{
title: 'Layout Components',
content: layoutComponents,
url: '/components',
},
{
title: 'Components',
content: components,
url: '/components',
},
];
export const Docs = () => {
const pathname = usePathname();
const isPlayground = pathname.includes('/playground');
return (
<motion.div
className={styles.section}
animate={{
x: isPlayground ? -10 : 0,
opacity: isPlayground ? 0 : 1,
visibility: isPlayground ? 'hidden' : 'visible',
}}
initial={{
x: isPlayground ? -10 : 0,
opacity: isPlayground ? 0 : 1,
visibility: isPlayground ? 'hidden' : 'visible',
}}
transition={{ duration: 0.2 }}
>
{data.map(section => {
return (
<Fragment key={section.title}>
<div className={styles.sectionTitle}>{section.title}</div>
{section.content.map(item => {
const isActive = pathname === `${section.url}/${item.slug}`;
return (
<Link
href={`${section.url}/${item.slug}`}
key={item.slug}
className={`${styles.line} ${isActive ? styles.active : ''}`}
>
<div className={styles.lineTitle}>{item.title}</div>
<div className={styles.lineStatus}>
{item.status === 'alpha' && 'Alpha'}
{item.status === 'beta' && 'Beta'}
{item.status === 'inProgress' && 'In Progress'}
{item.status === 'stable' && 'Stable'}
{item.status === 'deprecated' && 'Deprecated'}
</div>
</Link>
);
})}
</Fragment>
);
})}
</motion.div>
);
};
File diff suppressed because one or more lines are too long
@@ -1,77 +0,0 @@
'use client';
import { components } from '@/utils/data';
import { Checkbox } from '@backstage/ui';
import { motion } from 'motion/react';
import styles from './Sidebar.module.css';
import { usePathname } from 'next/navigation';
import { screenSizes } from '@/utils/data';
import { usePlayground } from '@/utils/playground-context';
export const Playground = () => {
const pathname = usePathname();
const isPlayground = pathname.includes('/playground');
const {
selectedScreenSizes,
setSelectedScreenSizes,
selectedComponents,
setSelectedComponents,
} = usePlayground();
const handleComponentCheckboxChange = (slug: string) => {
if (selectedComponents.find(item => item === slug)) {
const res = selectedComponents.filter(item => item !== slug);
setSelectedComponents(res);
} else {
setSelectedComponents([...selectedComponents, slug]);
}
};
const handleCheckboxChange = (slug: string) => {
if (selectedScreenSizes.find(item => item === slug)) {
const res = selectedScreenSizes.filter(item => item !== slug);
setSelectedScreenSizes(res);
} else {
setSelectedScreenSizes([...selectedScreenSizes, slug]);
}
};
return (
<motion.div
className={styles.section}
animate={{
opacity: isPlayground ? 1 : 0,
x: isPlayground ? 0 : 20,
visibility: isPlayground ? 'visible' : 'hidden',
}}
initial={{
opacity: isPlayground ? 1 : 0,
x: isPlayground ? 0 : 20,
visibility: isPlayground ? 'visible' : 'hidden',
}}
transition={{ duration: 0.2 }}
style={{ position: 'absolute' }}
>
<div className={styles.sectionTitle}>Components</div>
{components.map(({ slug, title }) => (
<div className={styles.line} key={slug}>
<div className={styles.lineTitle}>{title}</div>
<Checkbox
checked={selectedComponents.includes(slug)}
onChange={() => handleComponentCheckboxChange(slug)}
/>
</div>
))}
<div className={styles.sectionTitle}> Screen sizes</div>
{screenSizes.map(({ slug, title }) => (
<div className={styles.line} key={slug}>
<div className={styles.lineTitle}>{title}</div>
<Checkbox
checked={selectedScreenSizes.includes(slug)}
onChange={() => handleCheckboxChange(slug)}
/>
</div>
))}
</motion.div>
);
};
+52
View File
@@ -0,0 +1,52 @@
import { MDXRemote } from 'next-mdx-remote-client/rsc';
import { formattedMDXComponents } from '@/mdx-components';
import { Component } from '@/utils/changelog';
import { componentDefinitions } from '../../../../packages/ui/src/utils/componentDefinitions';
import type { DataAttributeValues } from '../../../../packages/ui/src/types';
export function Theming({ component }: { component: Component }) {
const componentDefinition = componentDefinitions[component];
if (!componentDefinition) {
return null;
}
const classNames = componentDefinition.classNames;
const dataAttributes = componentDefinition.dataAttributes;
// Get the first class name
const firstClassName = Object.values(classNames)[0];
// Create array of selectors combining first class name with data attributes
const selectorArray: string[] = [];
if (dataAttributes) {
Object.entries(dataAttributes).forEach(
([attributeName, attributeValues]) => {
(attributeValues as DataAttributeValues).forEach(value => {
selectorArray.push(
`${firstClassName}[data-${attributeName}="${value}"]`,
);
});
},
);
}
const classNamesArray = [
`${firstClassName}`,
...selectorArray,
...Object.values(classNames).slice(1),
];
return (
<MDXRemote
components={formattedMDXComponents}
source={`## Theming
Our theming system is based on a mix between CSS classes, CSS variables and data attributes. If you want to customise this component, you can use one of these class names below.
${classNamesArray.map(selector => `- \`${selector}\``).join('\n')}
`}
/>
);
}
@@ -0,0 +1,44 @@
.toolbar {
position: fixed;
display: flex;
top: 0;
left: 32px;
right: 32px;
height: 112px;
z-index: 10;
align-items: center;
justify-content: space-between;
padding-left: 0.25rem;
}
@media (min-width: 960px) {
.toolbar {
left: 332px;
right: 40px;
}
}
.left {
display: flex;
align-items: center;
gap: 0.5rem;
}
.name {
margin-top: 3px;
font-size: 28px;
color: #26c9ad;
font-weight: 500;
}
.actions {
display: none;
}
@media (min-width: 600px) {
.actions {
display: flex;
align-items: center;
gap: 1rem;
}
}
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
export { Toolbar } from './Toolbar';
-18
View File
@@ -1,18 +0,0 @@
import { ThemeSelector } from './theme';
import { ThemeNameSelector } from './theme-name';
import styles from './styles.module.css';
import { Nav } from './nav';
export const Toolbar = () => {
return (
<div className={styles.toolbar}>
<div>
<Nav />
</div>
<div className={styles.actions}>
<ThemeNameSelector />
<ThemeSelector />
</div>
</div>
);
};
@@ -1,78 +0,0 @@
.tabs {
display: none;
}
@media (min-width: 768px) {
.tabs {
display: block;
height: 60px;
}
}
.tabsTheme {
width: 142px;
border-radius: 0.375rem;
background-color: var(--bg);
transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
}
.list {
display: flex;
position: relative;
z-index: 0;
gap: 2rem;
}
.tab {
all: unset;
height: 60px;
color: var(--secondary);
font-size: 0.875rem;
font-weight: 600;
cursor: pointer;
&:hover {
transition: color 0.2s ease-in-out;
color: var(--primary);
}
&[data-selected] {
color: var(--primary);
& p {
color: var(--primary);
}
}
&:focus-visible {
position: relative;
&::before {
content: '';
position: absolute;
inset: 0.25rem 0;
border-radius: 0.25rem;
outline: 2px solid var(--panel);
outline-offset: -1px;
}
}
}
.tab p {
color: var(--secondary) !important;
}
.indicator {
position: absolute;
z-index: -1;
left: 0;
bottom: -1px;
translate: var(--active-tab-left) -50%;
width: var(--active-tab-width);
height: 1px;
border-radius: 0.25rem;
background-color: var(--primary);
transition-property: translate, width;
transition-duration: 200ms;
transition-timing-function: ease-in-out;
}
-49
View File
@@ -1,49 +0,0 @@
'use client';
import { Tabs } from '@base-ui-components/react/tabs';
import { usePathname } from 'next/navigation';
import { useRouter } from 'next/navigation';
import styles from './nav.module.css';
export const Nav = () => {
const pathname = usePathname();
const router = useRouter();
const onValueChange = (value: string) => {
if (value === 'docs') {
router.push('/');
} else {
router.push('/playground');
}
};
return (
<Tabs.Root
className={styles.tabs}
value={pathname.includes('playground') ? 'playground' : 'docs'}
onValueChange={onValueChange}
>
<Tabs.List className={styles.list}>
<Tabs.Tab
className={styles.tab}
value="docs"
onClick={() => {
router.push('/');
}}
>
Documentation
</Tabs.Tab>
<Tabs.Tab
className={styles.tab}
value="playground"
onClick={() => {
router.push('/playground');
}}
>
Playground
</Tabs.Tab>
<Tabs.Indicator className={styles.indicator} />
</Tabs.List>
</Tabs.Root>
);
};
@@ -1,22 +0,0 @@
.toolbar {
position: sticky;
top: 16px;
left: 0;
right: 0;
border-radius: 0.5rem;
z-index: 10;
background-color: var(--panel);
height: 60px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 1.5rem;
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.025);
border: 1px solid var(--border);
}
.actions {
display: flex;
align-items: center;
gap: 1rem;
}
@@ -4,20 +4,20 @@
align-items: center;
justify-content: space-between;
gap: 0.75rem;
height: 2rem;
padding-left: 0.875rem;
padding-right: 0.75rem;
height: 3rem;
padding-left: 1.25rem;
padding-right: 1rem;
margin: 0;
outline: 0;
border: 1px solid var(--color-gray-200);
border-radius: 0.375rem;
border-radius: 3rem;
font-family: inherit;
font-size: 1rem;
line-height: 1.5rem;
color: var(--color-gray-900);
cursor: pointer;
user-select: none;
background-color: var(--surface-1);
background-color: var(--action);
&:focus-visible {
outline: 2px solid var(--color-blue);
@@ -1,20 +1,17 @@
.tabs {
border-radius: 0.375rem;
width: 100%;
background-color: var(--surface-1);
}
.tabsTheme {
width: 100px;
border-radius: 0.375rem;
background-color: var(--surface-1);
}
.list {
display: flex;
position: relative;
z-index: 0;
padding-inline: 0.25rem;
gap: 0.25rem;
}
@@ -29,9 +26,10 @@
appearance: none;
color: var(--secondary);
user-select: none;
height: 2rem;
flex: 1;
cursor: pointer;
width: 3rem;
height: 3rem;
&[data-selected] {
color: var(--primary);
@@ -55,7 +53,7 @@
position: absolute;
inset: 0.25rem 0;
border-radius: 0.25rem;
outline: 2px solid var(--panel);
outline: 2px solid var(--action);
outline-offset: -1px;
}
}
@@ -72,9 +70,9 @@
top: 50%;
translate: var(--active-tab-left) -50%;
width: var(--active-tab-width);
height: 1.5rem;
border-radius: 0.25rem;
background-color: var(--panel);
height: 3rem;
border-radius: 3rem;
background-color: var(--action);
transition-property: translate, width;
transition-duration: 200ms;
transition-timing-function: ease-in-out;
+14 -16
View File
@@ -8,11 +8,14 @@ import {
snippetSizes,
snippetFallback,
} from './avatar.props';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
# Avatar
An avatar component with a fallback for initials.
<PageTitle
title="Avatar"
description="An avatar component with a fallback for initials."
/>
<Snippet
align="center"
@@ -21,18 +24,9 @@ An avatar component with a fallback for initials.
code={`<Avatar src="https://avatars.githubusercontent.com/u/1540635?v=4" name="Charles de Dreuille" />`}
/>
<ComponentInfos
component="avatar"
usageCode={snippetUsage}
classNames={[
'bui-AvatarRoot',
'bui-AvatarRoot[data-size="small"]',
'bui-AvatarRoot[data-size="medium"]',
'bui-AvatarRoot[data-size="large"]',
'bui-AvatarImage',
'bui-AvatarFallback',
]}
/>
## Usage
<CodeBlock code={snippetUsage} />
## API reference
@@ -63,3 +57,7 @@ If the image is not available, the avatar will show the initials of the name.
preview={<AvatarSnippet story="Fallback" />}
code={snippetFallback}
/>
<Theming component="Avatar" />
<ChangelogComponent component="avatar" />
+15 -5
View File
@@ -10,11 +10,15 @@ import {
boxResponsiveSnippet,
} from './box.props';
import { spacingPropDefs } from '@/utils/propDefs';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
# Box
Box is the lowest-level component in Backstage UI. It provides a consistent API for styling and layout.
<PageTitle
type="Layout"
title="Box"
description="Box is the lowest-level component in Backstage UI. It provides a consistent API for styling and layout."
/>
<Snippet
py={4}
@@ -23,7 +27,9 @@ Box is the lowest-level component in Backstage UI. It provides a consistent API
align="center"
/>
<ComponentInfos component="box" usageCode={snippetUsage} />
## Usage
<CodeBlock code={snippetUsage} />
## API reference
@@ -53,3 +59,7 @@ A simple example of how to use the Box component.
Here's a view when buttons are responsive.
<CodeBlock code={boxResponsiveSnippet} />
<Theming component="Box" />
<ChangelogComponent component="box" />
+14 -9
View File
@@ -12,11 +12,14 @@ import {
buttonIconResponsiveSnippet,
buttonIconAsLinkSnippet,
} from './button-icon.props';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
# ButtonIcon
A button component with a single icon that can be used to trigger actions.
<PageTitle
title="ButtonIcon"
description="A button component with a single icon that can be used to trigger actions."
/>
<Snippet
align="center"
@@ -25,11 +28,9 @@ A button component with a single icon that can be used to trigger actions.
code={buttonIconDefaultSnippet}
/>
<ComponentInfos
component="button-icon"
classNames={['bui-Button', 'bui-ButtonIcon']}
usageCode={buttonIconUsageSnippet}
/>
## Usage
<CodeBlock code={buttonIconUsageSnippet} />
## API reference
@@ -78,3 +79,7 @@ Here's a view when buttons are disabled.
Here's a view when buttons are responsive.
<CodeBlock code={buttonIconResponsiveSnippet} />
<Theming component="ButtonIcon" />
<ChangelogComponent component="button-icon" />
+14 -9
View File
@@ -11,11 +11,14 @@ import {
buttonLinkDisabledSnippet,
buttonLinkResponsiveSnippet,
} from './button-link.props';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
# ButtonLink
A button component that can be used as a link.
<PageTitle
title="ButtonLink"
description="A button component that can be used as a link."
/>
<Snippet
align="center"
@@ -24,11 +27,9 @@ A button component that can be used as a link.
code={buttonLinkVariantsSnippet}
/>
<ComponentInfos
component="button-link"
classNames={['bui-Button', 'bui-ButtonLink']}
usageCode={buttonLinkSnippetUsage}
/>
## Usage
<CodeBlock code={buttonLinkSnippetUsage} />
## API reference
@@ -89,3 +90,7 @@ Here's a view when buttons are disabled.
Here's a view when buttons are responsive.
<CodeBlock code={buttonLinkResponsiveSnippet} />
<Theming component="ButtonLink" />
<ChangelogComponent component="button-link" />
+14 -9
View File
@@ -12,11 +12,14 @@ import {
buttonResponsiveSnippet,
buttonAsLinkSnippet,
} from './button.props';
import { ComponentInfos } from '@/components/ComponentInfos';
import { ChangelogComponent } from '@/components/ChangelogComponent';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
# Button
A button component that can be used to trigger actions.
<PageTitle
title="Button"
description="A button component that can be used to trigger actions."
/>
<Snippet
align="center"
@@ -25,11 +28,9 @@ A button component that can be used to trigger actions.
code={buttonVariantsSnippet}
/>
<ComponentInfos
component="button"
classNames={['bui-Button']}
usageCode={buttonSnippetUsage}
/>
## Usage
<CodeBlock code={buttonSnippetUsage} />
## API reference
@@ -102,3 +103,7 @@ If you want to use a button as a link, please use the `ButtonLink` component.
preview={<ButtonLinkSnippet story="Variants" />}
code={buttonAsLinkSnippet}
/>
<Theming component="Button" />
<ChangelogComponent component="button" />
+14 -9
View File
@@ -12,11 +12,14 @@ import {
cardLongBodySnippet,
cardListRowSnippet,
} from './card.props';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
# Card
A card component that can be used to display content in a box.
<PageTitle
title="Card"
description="A card component that can be used to display content in a box."
/>
<Snippet
align="center"
@@ -25,11 +28,9 @@ A card component that can be used to display content in a box.
code={cardDefaultSnippet}
/>
<ComponentInfos
component="card"
classNames={['bui-Card', 'bui-CardHeader', 'bui-CardBody', 'bui-CardFooter']}
usageCode={cardUsageSnippet}
/>
## Usage
<CodeBlock code={cardUsageSnippet} />
## API reference
@@ -82,3 +83,7 @@ Here's a view when card has a list.
code={cardListRowSnippet}
open
/>
<Theming component="Card" />
<ChangelogComponent component="card" />
+14 -9
View File
@@ -8,11 +8,14 @@ import {
checkboxDefaultSnippet,
checkboxVariantsSnippet,
} from './checkbox.props';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
# Checkbox
A checkbox component that can be used to trigger actions.
<PageTitle
title="Checkbox"
description="A checkbox component that can be used to trigger actions."
/>
<Snippet
align="center"
@@ -21,11 +24,9 @@ A checkbox component that can be used to trigger actions.
code={checkboxDefaultSnippet}
/>
<ComponentInfos
component="checkbox"
classNames={['bui-Checkbox']}
usageCode={checkboxUsageSnippet}
/>
## Usage
<CodeBlock code={checkboxUsageSnippet} />
## API reference
@@ -44,3 +45,7 @@ Here's a view when checkboxes have different variants.
preview={<CheckboxSnippet story="AllVariants" />}
code={checkboxVariantsSnippet}
/>
<Theming component="Checkbox" />
<ChangelogComponent component="checkbox" />
+14 -13
View File
@@ -11,11 +11,14 @@ import {
collapsibleTriggerSnippet,
collapsibleOpenSnippet,
} from './collapsible.props';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
# Collapsible
An avatar component with a fallback for initials.
<PageTitle
title="Collapsible"
description="A collapsible component that can be used to display content in a box."
/>
<Snippet
align="center"
@@ -25,15 +28,9 @@ An avatar component with a fallback for initials.
code={collapsibleDefaultSnippet}
/>
<ComponentInfos
component="collapsible"
classNames={[
'bui-CollapsibleRoot',
'bui-CollapsibleTrigger',
'bui-CollapsiblePanel',
]}
usageCode={collapsibleUsageSnippet}
/>
## Usage
<CodeBlock code={collapsibleUsageSnippet} />
## API reference
@@ -69,3 +66,7 @@ Open the panel by default by setting the `defaultOpen` prop to `true`.
preview={<CollapsibleSnippet story="Open" />}
code={collapsibleOpenSnippet}
/>
<Theming component="Collapsible" />
<ChangelogComponent component="collapsible" />
+15 -10
View File
@@ -9,12 +9,15 @@ import {
containerSimpleSnippet,
containerResponsiveSnippet,
} from './container.props';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
# Container
The container component let you use our default max-width and center the
content on the page.
<PageTitle
type="Layout"
title="Container"
description="The container component let you use our default max-width and center the content on the page."
/>
<Snippet
py={4}
@@ -22,11 +25,9 @@ content on the page.
code={containerDefaultSnippet}
/>
<ComponentInfos
component="container"
classNames={['bui-Container']}
usageCode={containerUsageSnippet}
/>
## Usage
<CodeBlock code={containerUsageSnippet} />
## API reference
@@ -46,3 +47,7 @@ The Container component also supports responsive values, making it easy to
create responsive designs.
<CodeBlock code={containerResponsiveSnippet} />
<Theming component="Container" />
<ChangelogComponent component="container" />
+15 -9
View File
@@ -12,11 +12,15 @@ import {
flexAlignSnippet,
} from './flex.props';
import { spacingPropDefs } from '@/utils/propDefs';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
# Flex
A responsive flex container component for vertical stacking with customizable gaps.
<PageTitle
type="Layout"
title="Flex"
description="A responsive flex container component for vertical stacking with customizable gaps."
/>
<Snippet
py={4}
@@ -25,11 +29,9 @@ A responsive flex container component for vertical stacking with customizable ga
code={flexDefaultSnippet}
/>
<ComponentInfos
component="flex"
classNames={['bui-Flex']}
usageCode={flexUsageSnippet}
/>
## Usage
<CodeBlock code={flexUsageSnippet} />
## API reference
@@ -60,3 +62,7 @@ The Flex component also supports responsive alignment, making it easy to
create responsive designs.
<CodeBlock code={flexAlignSnippet} />
<Theming component="Flex" />
<ChangelogComponent component="flex" />
+15 -10
View File
@@ -14,12 +14,15 @@ import {
gridResponsiveSnippet,
gridStartEndSnippet,
} from './grid.props';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
# Grid
A layout component that helps to create simple column-based layouts as well as
more complex ones.
<PageTitle
type="Layout"
title="Grid"
description="A layout component that helps to create simple column-based layouts as well as more complex ones."
/>
<Snippet
py={4}
@@ -27,11 +30,9 @@ more complex ones.
code={gridDefaultSnippet}
/>
<ComponentInfos
component="grid"
classNames={['bui-Grid', 'bui-GridItem']}
usageCode={gridUsageSnippet}
/>
## Usage
<CodeBlock code={gridUsageSnippet} />
## API reference
@@ -91,3 +92,7 @@ responsive designs.
The start and end props can be used to position the item in the grid.
<CodeBlock code={gridStartEndSnippet} />
<Theming component="Grid" />
<ChangelogComponent component="grid" />
+14 -9
View File
@@ -7,11 +7,14 @@ import {
iconUsageSnippet,
iconDefaultSnippet,
} from './icon.props';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
# Icon
Icons are used to represent an action or a state.
<PageTitle
title="Icon"
description="Icons are used to represent an action or a state."
/>
<Snippet
py={4}
@@ -20,12 +23,14 @@ Icons are used to represent an action or a state.
code={iconDefaultSnippet}
/>
<ComponentInfos
component="icon"
classNames={['bui-Icon']}
usageCode={iconUsageSnippet}
/>
## Usage
<CodeBlock code={iconUsageSnippet} />
## API reference
<PropsTable data={iconPropDefs} />
<Theming component="Icon" />
<ChangelogComponent component="icon" />
+14 -27
View File
@@ -16,11 +16,14 @@ import {
linkRouterSnippet,
linkTruncateSnippet,
} from './link.props';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
# Link
A link component that supports both internal routing and external navigation.
<PageTitle
title="Link"
description="A link component that renders a `<a>` element."
/>
<Snippet
align="center"
@@ -29,29 +32,9 @@ A link component that supports both internal routing and external navigation.
code={linkDefaultSnippet}
/>
<ComponentInfos
component="link"
classNames={[
'bui-Link',
'bui-Text',
"bui-Text[data-variant='title-large']",
"bui-Text[data-variant='title-medium']",
"bui-Text[data-variant='title-small']",
"bui-Text[data-variant='title-x-small']",
"bui-Text[data-variant='body-large']",
"bui-Text[data-variant='body-medium']",
"bui-Text[data-variant='body-small']",
"bui-Text[data-variant='body-x-small']",
"bui-Text[data-weight='regular']",
"bui-Text[data-weight='bold']",
"bui-Text[data-color='primary']",
"bui-Text[data-color='secondary']",
"bui-Text[data-color='danger']",
"bui-Text[data-color='warning']",
"bui-Text[data-color='success']",
]}
usageCode={linkUsageSnippet}
/>
## Usage
<CodeBlock code={linkUsageSnippet} />
## API reference
@@ -113,3 +96,7 @@ The `Link` component has a `truncate` prop that can be used to truncate the text
preview={<LinkSnippet story="Truncate" />}
code={linkTruncateSnippet}
/>
<Theming component="Link" />
<ChangelogComponent component="link" />
+14 -25
View File
@@ -13,11 +13,14 @@ import {
menuHoverSnippet,
menuSubmenuSnippet,
} from './menu.props';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
# Menu
A list of actions in a dropdown, enhanced with keyboard navigation.
<PageTitle
title="Menu"
description="A list of actions in a dropdown, enhanced with keyboard navigation."
/>
<Snippet
align="center"
@@ -26,27 +29,9 @@ A list of actions in a dropdown, enhanced with keyboard navigation.
code={menuDefaultSnippet}
/>
<ComponentInfos
component="menu"
classNames={[
'bui-MenuTrigger',
'bui-MenuBackdrop',
'bui-MenuPositioner',
'bui-MenuPopup',
'bui-MenuArrow',
'bui-MenuItem',
'bui-MenuGroup',
'bui-MenuGroupLabel',
'bui-MenuRadioGroup',
'bui-MenuRadioItem',
'bui-MenuRadioItemIndicator',
'bui-MenuCheckboxItem',
'bui-MenuCheckboxItemIndicator',
'bui-MenuSubmenuTrigger',
'bui-MenuSeparator',
]}
usageCode={menuUsageSnippet}
/>
## Usage
<CodeBlock code={menuUsageSnippet} />
## API reference
@@ -103,3 +88,7 @@ You can nest menus to create a more complex navigation structure.
preview={<MenuSnippet story="Submenu" />}
code={menuSubmenuSnippet}
/>
<Theming component="Menu" />
<ChangelogComponent component="menu" />
+15 -9
View File
@@ -12,11 +12,15 @@ import {
radioGroupValidationSnippet,
radioGroupReadOnlySnippet,
} from './radio-group.props';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
import { CodeBlock } from '@/components/CodeBlock';
# RadioGroup
A radio group allows a user to select a single item from a list of mutually exclusive options.
<PageTitle
title="RadioGroup"
description="A radio group allows a user to select a single item from a list of mutually exclusive options."
/>
<Snippet
align="center"
@@ -25,11 +29,9 @@ A radio group allows a user to select a single item from a list of mutually excl
code={radioGroupDefaultSnippet}
/>
<ComponentInfos
component="radio-group"
classNames={['bui-RadioGroup', 'bui-RadioGroupContent']}
usageCode={radioGroupUsageSnippet}
/>
## Usage
<CodeBlock code={radioGroupUsageSnippet} />
## API reference
@@ -96,3 +98,7 @@ You can make the radio group read only by adding the `isReadOnly` prop to the `R
preview={<RadioGroupSnippet story="ReadOnly" />}
code={radioGroupReadOnlySnippet}
/>
<Theming component="RadioGroup" />
<ChangelogComponent component="radio-group" />
+15 -20
View File
@@ -8,11 +8,15 @@ import {
searchFieldSizesSnippet,
searchFieldDescriptionSnippet,
} from './search-field.props';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
import { CodeBlock } from '@/components/CodeBlock';
# SearchField
A SearchField is a text field designed for searches.
<PageTitle
title="SearchField"
description="A SearchField is a text field designed for searches."
/>
<Snippet
align="center"
@@ -21,22 +25,9 @@ A SearchField is a text field designed for searches.
code={searchFieldDefaultSnippet}
/>
<ComponentInfos
component="searchfield"
classNames={[
'bui-SearchField',
'bui-TextField',
'bui-InputWrapper',
'bui-Input',
'bui-InputIcon',
'bui-FieldLabelWrapper',
'bui-FieldLabel',
'bui-FieldDescription',
'bui-FieldSecondaryLabel',
'bui-FieldError',
]}
usageCode={searchFieldUsageSnippet}
/>
## Usage
<CodeBlock code={searchFieldUsageSnippet} />
## API reference
@@ -67,3 +58,7 @@ Here's a simple SearchField with a description.
preview={<SearchFieldSnippet story="WithDescription" />}
code={searchFieldDescriptionSnippet}
/>
<Theming component="SearchField" />
<ChangelogComponent component="search-field" />
+14 -18
View File
@@ -12,11 +12,14 @@ import {
selectResponsiveSnippet,
selectIconSnippet,
} from './select.props';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
# Select
A common form component for choosing a predefined value in a dropdown menu.
<PageTitle
title="Select"
description="A common form component for choosing a predefined value in a dropdown menu."
/>
<Snippet
align="center"
@@ -25,20 +28,9 @@ A common form component for choosing a predefined value in a dropdown menu.
code={selectDefaultSnippet}
/>
<ComponentInfos
component="select"
classNames={[
'bui-Select',
'bui-SelectTrigger',
'bui-SelectValue',
'bui-SelectIcon',
'bui-SelectList',
'bui-SelectItem',
'bui-SelectItemIndicator',
'bui-SelectItemLabel',
]}
usageCode={selectUsageSnippet}
/>
## Usage
<CodeBlock code={selectUsageSnippet} />
## API reference
@@ -100,3 +92,7 @@ Here's a view when the select is disabled.
Here's a view when the select is responsive.
<CodeBlock code={selectResponsiveSnippet} />
<Theming component="Select" />
<ChangelogComponent component="select" />
+14 -9
View File
@@ -9,11 +9,14 @@ import {
skeletonDemo1Snippet,
skeletonDemo2Snippet,
} from './skeleton.props';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
# Skeleton
Use to show a placeholder while content is loading.
<PageTitle
title="Skeleton"
description="Use to show a placeholder while content is loading."
/>
<Snippet
align="center"
@@ -22,11 +25,9 @@ Use to show a placeholder while content is loading.
code={skeletonDefaultSnippet}
/>
<ComponentInfos
component="skeleton"
classNames={['bui-Skeleton']}
usageCode={skeletonUsageSnippet}
/>
## Usage
<CodeBlock code={skeletonUsageSnippet} />
## API reference
@@ -57,3 +58,7 @@ You can use a mix of different sizes to create a more complex skeleton.
code={skeletonDemo2Snippet}
open
/>
<Theming component="Skeleton" />
<ChangelogComponent component="skeleton" />
+14 -9
View File
@@ -3,11 +3,14 @@ import { Snippet } from '@/components/Snippet';
import { CodeBlock } from '@/components/CodeBlock';
import { SwitchSnippet } from '@/snippets/stories-snippets';
import { switchPropDefs, snippetUsage } from './switch.props';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
# Switch
A control that indicates whether a setting is on or off.
<PageTitle
title="Switch"
description="A control that indicates whether a setting is on or off."
/>
<Snippet
align="center"
@@ -16,11 +19,9 @@ A control that indicates whether a setting is on or off.
code={`<Switch />`}
/>
<ComponentInfos
component="switch"
usageCode={snippetUsage}
classNames={['bui-Switch', 'bui-SwitchIndicator']}
/>
## Usage
<CodeBlock code={snippetUsage} />
## API reference
@@ -39,3 +40,7 @@ A switch can be disabled using the `isDisabled` prop.
preview={<SwitchSnippet story="Disabled" />}
code={`<Switch isDisabled />`}
/>
<Theming component="Switch" />
<ChangelogComponent component="switch" />
+6 -1
View File
@@ -1 +1,6 @@
# Table (Coming soon)
import { PageTitle } from '@/components/PageTitle';
<PageTitle
title="Table"
description="A table component that can be used to display data in a grid. (Coming soon)"
/>
+14 -15
View File
@@ -10,11 +10,14 @@ import {
tabsUsageSnippet,
tabsDefaultSnippet,
} from './tabs.props';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
# Tabs
A component for toggling between related panels on the same page.
<PageTitle
title="Tabs"
description="A component for toggling between related panels on the same page."
/>
<Snippet
py={4}
@@ -22,17 +25,9 @@ A component for toggling between related panels on the same page.
code={tabsDefaultSnippet}
/>
<ComponentInfos
component="tabs"
classNames={[
'bui-TabsRoot',
'bui-TabsList',
'bui-TabsTab',
'bui-TabsPanel',
'bui-TabsIndicator',
]}
usageCode={tabsUsageSnippet}
/>
## Usage
<CodeBlock code={tabsUsageSnippet} />
## API reference
@@ -59,3 +54,7 @@ An individual interactive tab button that toggles the corresponding panel. Rende
A panel displayed when the corresponding tab is active. Renders a `<div>` element.
<PropsTable data={tabsPanelPropDefs} />
<Theming component="Tabs" />
<ChangelogComponent component="tabs" />
+15 -19
View File
@@ -8,11 +8,15 @@ import {
textFieldSizesSnippet,
textFieldDescriptionSnippet,
} from './text-field.props';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
import { CodeBlock } from '@/components/CodeBlock';
# TextField
A text field component for your forms.
<PageTitle
title="TextField"
description="A text field component for your forms."
/>
<Snippet
align="center"
@@ -21,21 +25,9 @@ A text field component for your forms.
code={textFieldDefaultSnippet}
/>
<ComponentInfos
component="textfield"
classNames={[
'bui-TextField',
'bui-InputWrapper',
'bui-Input',
'bui-InputIcon',
'bui-FieldLabelWrapper',
'bui-FieldLabel',
'bui-FieldDescription',
'bui-FieldSecondaryLabel',
'bui-FieldError',
]}
usageCode={textFieldUsageSnippet}
/>
## Usage
<CodeBlock code={textFieldUsageSnippet} />
## API reference
@@ -66,3 +58,7 @@ Here's a simple TextField with a description.
preview={<TextFieldSnippet story="WithDescription" />}
code={textFieldDescriptionSnippet}
/>
<Theming component="TextField" />
<ChangelogComponent component="text-field" />
+14 -27
View File
@@ -12,11 +12,14 @@ import {
textResponsiveSnippet,
textColorsSnippet,
} from './text.props';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
# Text
The `Text` component is used to display content on your page.
<PageTitle
title="Text"
description="The `Text` component is used to display content on your page."
/>
<Snippet
py={4}
@@ -24,29 +27,9 @@ The `Text` component is used to display content on your page.
code={textDefaultSnippet}
/>
<ComponentInfos
component="text"
classNames={[
'bui-Text',
"bui-Text[data-variant='title-large']",
"bui-Text[data-variant='title-medium']",
"bui-Text[data-variant='title-small']",
"bui-Text[data-variant='title-x-small']",
"bui-Text[data-variant='body-large']",
"bui-Text[data-variant='body-medium']",
"bui-Text[data-variant='body-small']",
"bui-Text[data-variant='body-x-small']",
"bui-Text[data-weight='regular']",
"bui-Text[data-weight='bold']",
"bui-Text[data-color='primary']",
"bui-Text[data-color='secondary']",
"bui-Text[data-color='danger']",
"bui-Text[data-color='warning']",
"bui-Text[data-color='success']",
'bui-Text[data-truncate]',
]}
usageCode={textUsageSnippet}
/>
## Usage
<CodeBlock code={textUsageSnippet} />
## API reference
@@ -103,3 +86,7 @@ You can also use the `variant` prop to change the appearance of the text based
on the screen size.
<CodeBlock code={textResponsiveSnippet} />
<Theming component="Text" />
<ChangelogComponent component="text" />
+14 -9
View File
@@ -8,11 +8,14 @@ import {
tooltipTriggerPropDefs,
tooltipPropDefs,
} from './tooltip.props';
import { ComponentInfos } from '@/components/ComponentInfos';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
# Tooltip
A tooltip displays a description of an element on hover or focus.
<PageTitle
title="Tooltip"
description="A tooltip displays a description of an element on hover or focus."
/>
<Snippet
py={4}
@@ -21,11 +24,9 @@ A tooltip displays a description of an element on hover or focus.
align="center"
/>
<ComponentInfos
component="tooltip"
classNames={['bui-Tooltip', 'bui-ToltipArrow']}
usageCode={tooltipUsageSnippet}
/>
## Usage
<CodeBlock code={tooltipUsageSnippet} />
## API reference
@@ -40,3 +41,7 @@ The trigger will wrap both the trigger and the tooltip.
The tooltip will wrap the content of the tooltip.
<PropsTable data={tooltipPropDefs} />
<Theming component="Tooltip" />
<ChangelogComponent component="tooltip" />
+4 -4
View File
@@ -2,7 +2,8 @@
--bg: #f8f8f8;
--panel: #fff;
--primary: #000;
--secondary: #757575;
--secondary: #929292;
--action: #fff;
--link: #4f5ce0;
--font-regular: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
'Helvetica Neue', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
@@ -17,17 +18,16 @@
[data-theme='dark'] {
--bg: #000;
--panel: #1a1a1a;
--panel: #181818;
--primary: #fff;
--secondary: #818181;
--action: #202020;
--link: #4856e8;
--border: #2a2a2a;
--surface-1: #282828;
}
body {
display: flex;
flex-direction: row;
background-color: var(--bg);
color: var(--primary);
font-family: var(--font-regular);
+6 -3
View File
@@ -1,8 +1,9 @@
.h1 {
font-size: 2.5rem;
margin-top: 4rem;
margin-bottom: 1.5rem;
font-size: 3rem;
margin-top: 0;
margin-bottom: 1.25rem;
color: var(--primary);
font-weight: 400;
}
.h2 {
@@ -10,6 +11,7 @@
margin-top: 3rem;
margin-bottom: 1.5rem;
color: var(--primary);
font-weight: 400;
}
.h3 {
@@ -17,6 +19,7 @@
margin-top: 2rem;
margin-bottom: 0.5rem;
color: var(--primary);
font-weight: 400;
}
.p {
-50
View File
@@ -1,50 +0,0 @@
.global {
width: 100%;
}
.container {
width: 100%;
padding: 0 16px;
}
@media (min-width: 768px) {
.container {
padding-left: 332px;
}
}
.page {
flex: 1;
}
.page p {
color: var(--primary);
font-size: 1rem;
line-height: 1.5rem;
margin-top: 0;
margin-bottom: 1rem;
}
.content {
width: 100%;
max-width: 960px;
margin: 0 auto;
padding: 64px 24px 64px;
}
.header {
width: 100%;
margin-bottom: 64px;
}
.header img {
width: 100%;
height: auto;
}
.pageContainer {
width: 100%;
max-width: 960px;
margin: 0 auto;
padding: 0 24px 64px;
}
+10 -12
View File
@@ -907,6 +907,15 @@ __metadata:
languageName: node
linkType: hard
"@remixicon/react@npm:^4.6.0":
version: 4.6.0
resolution: "@remixicon/react@npm:4.6.0"
peerDependencies:
react: ">=18.2.0"
checksum: 10/d92c8131734062fca8d82d55dd8f3f4e28cb72c5eefda528c8aba5f3298f0c847342eecdbd7787d6da5af21b699d735f6cf27f151f0c982c1c9f06a78b235c94
languageName: node
linkType: hard
"@rtsao/scc@npm:^1.1.0":
version: 1.1.0
resolution: "@rtsao/scc@npm:1.1.0"
@@ -2302,6 +2311,7 @@ __metadata:
"@mdx-js/loader": "npm:^3.1.0"
"@mdx-js/react": "npm:^3.1.0"
"@next/mdx": "npm:15.3.4"
"@remixicon/react": "npm:^4.6.0"
"@storybook/react": "npm:^8.6.8"
"@types/mdx": "npm:^2.0.13"
"@types/node": "npm:^20"
@@ -2321,7 +2331,6 @@ __metadata:
prop-types: "npm:^15.8.1"
react: "npm:19.1.0"
react-dom: "npm:19.1.0"
react-frame-component: "npm:^5.2.7"
shiki: "npm:^1.26.1"
storybook: "npm:^8.6.8"
typescript: "npm:^5"
@@ -5587,17 +5596,6 @@ __metadata:
languageName: node
linkType: hard
"react-frame-component@npm:^5.2.7":
version: 5.2.7
resolution: "react-frame-component@npm:5.2.7"
peerDependencies:
prop-types: ^15.5.9
react: ">= 16.3"
react-dom: ">= 16.3"
checksum: 10/bedee0c25075cbfb6d592991937640a9c8680f9017284e73ced338cc07348b3efc99121052b60ba0923d3d4ec1ed050348ddec452f059e0b947f6bff1d5bfe24
languageName: node
linkType: hard
"react-is@npm:^16.13.1":
version: 16.13.1
resolution: "react-is@npm:16.13.1"