First pass moving docs to Nextjs 15
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
+13
-7
@@ -8,19 +8,25 @@
|
||||
"lint": "next lint",
|
||||
"start": "npm run build:css && next dev"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "19.1.7",
|
||||
"@types/react-dom": "19.1.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"@codemirror/lang-sass": "^6.0.2",
|
||||
"@lezer/highlight": "^1.2.1",
|
||||
"@mdx-js/loader": "^3.1.0",
|
||||
"@mdx-js/react": "^3.1.0",
|
||||
"@next/mdx": "^15.1.4",
|
||||
"@next/mdx": "15.3.3",
|
||||
"@storybook/react": "^8.6.8",
|
||||
"@uiw/codemirror-themes": "^4.23.7",
|
||||
"@uiw/react-codemirror": "^4.23.7",
|
||||
"html-react-parser": "^5.2.5",
|
||||
"motion": "^12.4.1",
|
||||
"next": "14.2.26",
|
||||
"react": "^18.0.2",
|
||||
"react-dom": "^18.0.2",
|
||||
"next": "15.3.3",
|
||||
"next-mdx-remote-client": "^2.1.2",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"react-frame-component": "^5.2.7",
|
||||
"shiki": "^1.26.1",
|
||||
"storybook": "^8.6.8"
|
||||
@@ -28,10 +34,10 @@
|
||||
"devDependencies": {
|
||||
"@types/mdx": "^2.0.13",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18.0.0",
|
||||
"@types/react-dom": "^18.0.0",
|
||||
"@types/react": "19.1.7",
|
||||
"@types/react-dom": "19.1.6",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "14.2.23",
|
||||
"eslint-config-next": "15.3.3",
|
||||
"lightningcss": "^1.28.2",
|
||||
"typescript": "^5"
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,13 @@
|
||||
import { Changelog } from '@/components/Changelog';
|
||||
|
||||
# Changelog
|
||||
|
||||
<Changelog />
|
||||
|
||||
## Version 0.1.0
|
||||
|
||||
We're excited to share the initial release of Canon 💚 In this first alpha version,
|
||||
you'll find the foundation of our design system: a set of versatile layout components
|
||||
and a handful of essential atomic elements to help you get started. While Canon is
|
||||
still in its early stages, it's ready for exploration and we'd love for you to give
|
||||
it a try and share your feedback.
|
||||
@@ -0,0 +1,25 @@
|
||||
import { components, layoutComponents } from '@/utils/data';
|
||||
|
||||
export default async function Page({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ slug: string }>;
|
||||
}) {
|
||||
const { slug } = await params;
|
||||
|
||||
const { default: Component } = await import(
|
||||
`@/content/components/${slug}.mdx`
|
||||
);
|
||||
|
||||
return <Component />;
|
||||
}
|
||||
|
||||
export function generateStaticParams() {
|
||||
const list = [...components, ...layoutComponents];
|
||||
|
||||
return list.map(component => ({
|
||||
slug: component.slug,
|
||||
}));
|
||||
}
|
||||
|
||||
export const dynamicParams = false;
|
||||
@@ -1,75 +0,0 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { Tabs } from '@/components/Tabs';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import { AvatarSnippet } from '@/snippets/stories-snippets';
|
||||
import { avatarPropDefs } from './props';
|
||||
|
||||
# Avatar
|
||||
|
||||
An avatar component with a fallback for initials.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
preview={<AvatarSnippet story="Default" />}
|
||||
code={`<Avatar src="https://avatars.githubusercontent.com/u/1540635?v=4" name="Charles de Dreuille" />`}
|
||||
/>
|
||||
|
||||
<Tabs.Root>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab>Usage</Tabs.Tab>
|
||||
<Tabs.Tab>Theming</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
<Tabs.Panel>
|
||||
<CodeBlock
|
||||
code={`import { Avatar } from '@backstage/canon';
|
||||
|
||||
<Avatar src="https://avatars.githubusercontent.com/u/1540635?v=4" name="Charles de Dreuille" />`}
|
||||
/>
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel>
|
||||
We recommend starting with our [global tokens](/theme/theming) 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.
|
||||
- `canon-AvatarRoot`
|
||||
- `canon-AvatarRoot[data-size='small']`
|
||||
- `canon-AvatarRoot[data-size='medium']`
|
||||
- `canon-AvatarRoot[data-size='large']`
|
||||
- `canon-AvatarImage`
|
||||
- `canon-AvatarFallback`
|
||||
</Tabs.Panel>
|
||||
</Tabs.Root>
|
||||
|
||||
## API reference
|
||||
|
||||
<PropsTable data={avatarPropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
### Sizes
|
||||
|
||||
Avatar sizes can be set using the `size` prop.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<AvatarSnippet story="Sizes" />}
|
||||
code={`<Flex gap="4" direction="column">
|
||||
<Avatar src="https://avatars.githubusercontent.com/u/1540635?v=4" name="Charles de Dreuille" size="small" />
|
||||
<Avatar src="https://avatars.githubusercontent.com/u/1540635?v=4" name="Charles de Dreuille" size="medium" />
|
||||
<Avatar src="https://avatars.githubusercontent.com/u/1540635?v=4" name="Charles de Dreuille" size="large" />
|
||||
</Flex>`}
|
||||
/>
|
||||
|
||||
### Fallback
|
||||
|
||||
If the image is not available, the avatar will show the initials of the name.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<AvatarSnippet story="Fallback" />}
|
||||
code={`<Avatar src="https://avatars.githubusercontent.com/u/15406AAAAAAAAA" name="Charles de Dreuille" />`}
|
||||
/>
|
||||
@@ -1,19 +0,0 @@
|
||||
import { classNamePropDefs, stylePropDefs } from '@/utils/propDefs';
|
||||
import type { PropDef } from '@/utils/propDefs';
|
||||
|
||||
export const avatarPropDefs: Record<string, PropDef> = {
|
||||
src: {
|
||||
type: 'string',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
},
|
||||
size: {
|
||||
type: 'enum',
|
||||
values: ['small', 'medium', 'large'],
|
||||
default: 'medium',
|
||||
responsive: true,
|
||||
},
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
@@ -1,24 +0,0 @@
|
||||
import {
|
||||
classNamePropDefs,
|
||||
displayPropDefs,
|
||||
heightPropDefs,
|
||||
positionPropDefs,
|
||||
stylePropDefs,
|
||||
widthPropDefs,
|
||||
} from '../../../../utils/propDefs';
|
||||
import type { PropDef } from '../../../../utils/propDefs';
|
||||
|
||||
export const boxPropDefs: Record<string, PropDef> = {
|
||||
as: {
|
||||
type: 'enum',
|
||||
values: ['div', 'span'],
|
||||
default: 'div',
|
||||
responsive: true,
|
||||
},
|
||||
...widthPropDefs,
|
||||
...heightPropDefs,
|
||||
...positionPropDefs,
|
||||
...displayPropDefs,
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
@@ -1,150 +0,0 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { Tabs } from '@/components/Tabs';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import { ButtonSnippet } from '@/snippets/stories-snippets';
|
||||
import { buttonVariants } from '@/snippets/code-snippets';
|
||||
import { buttonPropDefs } from './props';
|
||||
|
||||
# Button
|
||||
|
||||
A button component that can be used to trigger actions.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
preview={<ButtonSnippet story="Variants" />}
|
||||
code={`<Inline alignY="center">
|
||||
<Button iconStart="cloud" variant="primary">
|
||||
Button
|
||||
</Button>
|
||||
<Button iconStart="cloud" variant="secondary">
|
||||
Button
|
||||
</Button>
|
||||
<Button iconStart="cloud" variant="tertiary">
|
||||
Button
|
||||
</Button>
|
||||
</Inline>`}
|
||||
/>
|
||||
|
||||
<Tabs.Root>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab>Usage</Tabs.Tab>
|
||||
<Tabs.Tab>Theming</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
<Tabs.Panel>
|
||||
<CodeBlock
|
||||
code={`import { Button } from '@backstage/canon';
|
||||
|
||||
<Button />
|
||||
`}
|
||||
/>
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel>
|
||||
We recommend starting with our [global tokens](/theme/theming) 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.
|
||||
<CodeBlock
|
||||
code={`<Button className="button" />`}
|
||||
/>
|
||||
|
||||
</Tabs.Panel>
|
||||
</Tabs.Root>
|
||||
|
||||
## API reference
|
||||
|
||||
<PropsTable data={buttonPropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
### Variants
|
||||
|
||||
Here's a view when buttons have different variants.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<ButtonSnippet story="Variants" />}
|
||||
code={buttonVariants}
|
||||
/>
|
||||
|
||||
### Sizes
|
||||
|
||||
Here's a view when buttons have different sizes.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<ButtonSnippet story="Sizes" />}
|
||||
code={`<Inline alignY="center">
|
||||
<Button size="small">Small</Button>
|
||||
<Button size="medium">Medium</Button>
|
||||
</Inline>`}
|
||||
/>
|
||||
|
||||
### With Icons
|
||||
|
||||
Here's a view when buttons have icons.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<ButtonSnippet story="WithIcons" />}
|
||||
code={`<Inline alignY="center">
|
||||
<Button iconStart="cloud">Button</Button>
|
||||
<Button iconEnd="chevronRight">Button</Button>
|
||||
<Button iconStart="cloud" iconEnd="chevronRight">Button</Button>
|
||||
</Inline>`}
|
||||
/>
|
||||
|
||||
### Full width
|
||||
|
||||
Here's a view when buttons are full width.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<ButtonSnippet story="FullWidth" />}
|
||||
code={`<Flex style={{ width: '300px' }}>
|
||||
<Button fullWidth>Full width</Button>
|
||||
</Flex>`}
|
||||
/>
|
||||
|
||||
### Disabled
|
||||
|
||||
Here's a view when buttons are disabled.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<ButtonSnippet story="Disabled" />}
|
||||
code={`<Button disabled>Button</Button>`}
|
||||
/>
|
||||
|
||||
### As Link
|
||||
|
||||
Here's a view when buttons are rendered as a link.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<ButtonSnippet story="AsLink" />}
|
||||
code={`<Button render={<a href="https://canon.backstage.io" target="_blank" />}>
|
||||
I am a link
|
||||
</Button>`}
|
||||
/>
|
||||
|
||||
### Responsive
|
||||
|
||||
Here's a view when buttons are responsive.
|
||||
|
||||
<CodeBlock
|
||||
code={`<Button variant={{ initial: 'primary', lg: 'secondary' }}>
|
||||
Responsive Button
|
||||
</Button>`}
|
||||
/>
|
||||
@@ -1,25 +0,0 @@
|
||||
import { classNamePropDefs, stylePropDefs } from '../../../../utils/propDefs';
|
||||
import type { PropDef } from '../../../../utils/propDefs';
|
||||
|
||||
export const buttonPropDefs: Record<string, PropDef> = {
|
||||
variant: {
|
||||
type: 'enum',
|
||||
values: ['primary', 'secondary'],
|
||||
default: 'primary',
|
||||
responsive: true,
|
||||
},
|
||||
size: {
|
||||
type: 'enum',
|
||||
values: ['small', 'medium'],
|
||||
default: 'medium',
|
||||
responsive: true,
|
||||
},
|
||||
render: {
|
||||
type: 'enum',
|
||||
values: ['ReactNode'],
|
||||
responsive: false,
|
||||
default: '<button />',
|
||||
},
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
@@ -1,66 +0,0 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { CheckboxSnippet } from '@/snippets/stories-snippets';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { Tabs } from '@/components/Tabs';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import { BaseUI } from '@/components/HeadlessBanners/BaseUI';
|
||||
import { checkboxPropDefs } from './props';
|
||||
|
||||
# Checkbox
|
||||
|
||||
A checkbox component that can be used to trigger actions.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
preview={<CheckboxSnippet story="Default" />}
|
||||
code={`<Checkbox label="Accept terms and conditions" />`}
|
||||
/>
|
||||
|
||||
<Tabs.Root>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab>Usage</Tabs.Tab>
|
||||
<Tabs.Tab>Theming</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
<Tabs.Panel>
|
||||
<CodeBlock
|
||||
code={`import { Checkbox } from '@backstage/canon';
|
||||
|
||||
<Checkbox />
|
||||
`}
|
||||
/>
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel>
|
||||
We recommend starting with our [global tokens](/theme/theming) 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.
|
||||
<CodeBlock
|
||||
code={`<Checkbox className="checkbox" />`}
|
||||
/>
|
||||
|
||||
</Tabs.Panel>
|
||||
</Tabs.Root>
|
||||
|
||||
## API reference
|
||||
|
||||
<BaseUI href="https://base-ui.com/react/components/checkbox" />
|
||||
|
||||
<PropsTable data={checkboxPropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
### All variants
|
||||
|
||||
Here's a view when checkboxes have different variants.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<CheckboxSnippet story="AllVariants" />}
|
||||
code={`<Inline alignY="center">
|
||||
<Checkbox />
|
||||
<Checkbox checked />
|
||||
<Checkbox label="Checkbox" />
|
||||
<Checkbox label="Checkbox" checked />
|
||||
</Inline>`}
|
||||
/>
|
||||
@@ -1,113 +0,0 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { Tabs } from '@/components/Tabs';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import { CollapsibleSnippet } from '@/snippets/stories-snippets';
|
||||
import {
|
||||
collapsibleRootPropDefs,
|
||||
collapsibleTriggerPropDefs,
|
||||
collapsiblePanelPropDefs,
|
||||
} from './props';
|
||||
|
||||
# Collapsible
|
||||
|
||||
An avatar component with a fallback for initials.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
height={240}
|
||||
preview={<CollapsibleSnippet story="Default" />}
|
||||
code={`<Collapsible.Root>
|
||||
<Collapsible.Trigger render={(props, state) => (
|
||||
<Button {...props}>
|
||||
{state.open ? 'Close Panel' : 'Open Panel'}
|
||||
</Button>
|
||||
)} />
|
||||
<Collapsible.Panel>
|
||||
<Box>
|
||||
<Text>It's the edge of the world and all of Western civilization</Text>
|
||||
<Text>The sun may rise in the East, at least it settled in a final location</Text>
|
||||
<Text>It's understood that Hollywood sells Californication</Text>
|
||||
</Box>
|
||||
</Collapsible.Panel>
|
||||
</Collapsible.Root>`}
|
||||
/>
|
||||
|
||||
<Tabs.Root>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab>Usage</Tabs.Tab>
|
||||
<Tabs.Tab>Theming</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
<Tabs.Panel>
|
||||
<CodeBlock
|
||||
code={`import { Collapsible } from '@backstage/canon';
|
||||
|
||||
<Collapsible.Root>
|
||||
<Collapsible.Trigger render={(props, state) => (
|
||||
<Button {...props}>
|
||||
{state.open ? 'Close Panel' : 'Open Panel'}
|
||||
</Button>
|
||||
)} />
|
||||
<Collapsible.Panel>Your content</Collapsible.Panel>
|
||||
</Collapsible.Root>`}
|
||||
/>
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel>
|
||||
We recommend starting with our [global tokens](/theme/theming) 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.
|
||||
- `canon-CollapsibleRoot`
|
||||
- `canon-CollapsibleTrigger`
|
||||
- `canon-CollapsiblePanel`
|
||||
</Tabs.Panel>
|
||||
</Tabs.Root>
|
||||
|
||||
## API reference
|
||||
|
||||
### Collapsible.Root
|
||||
|
||||
Groups all parts of the collapsible. Renders a `<div>` element.
|
||||
|
||||
<PropsTable data={collapsibleRootPropDefs} />
|
||||
|
||||
### Collapsible.Trigger
|
||||
|
||||
The trigger by default render a simple unstyled button. Because menus can be rendered in different ways, we recommend
|
||||
using the `render` prop to render a custom trigger.
|
||||
|
||||
<CodeBlock
|
||||
code={`<Collapsible.Trigger render={props => <Button {...props} />} />`}
|
||||
/>
|
||||
|
||||
<PropsTable data={collapsibleTriggerPropDefs} />
|
||||
|
||||
### Collapsible.Panel
|
||||
|
||||
A panel with the collapsible contents. Renders a `<div>` element.
|
||||
|
||||
<PropsTable data={collapsiblePanelPropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
Open the panel by default by setting the `defaultOpen` prop to `true`.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<CollapsibleSnippet story="Open" />}
|
||||
code={`<Collapsible.Root defaultOpen>
|
||||
<Collapsible.Trigger render={(props, state) => (
|
||||
<Button {...props}>
|
||||
{state.open ? 'Close Panel' : 'Open Panel'}
|
||||
</Button>
|
||||
)} />
|
||||
<Collapsible.Panel>
|
||||
<Box>
|
||||
<Text>It's the edge of the world and all of Western civilization</Text>
|
||||
<Text>The sun may rise in the East, at least it settled in a final location</Text>
|
||||
<Text>It's understood that Hollywood sells Californication</Text>
|
||||
</Box>
|
||||
</Collapsible.Panel>
|
||||
</Collapsible.Root>`}
|
||||
/>
|
||||
@@ -1,43 +0,0 @@
|
||||
import {
|
||||
classNamePropDefs,
|
||||
stylePropDefs,
|
||||
renderPropDefs,
|
||||
} from '@/utils/propDefs';
|
||||
import type { PropDef } from '@/utils/propDefs';
|
||||
|
||||
export const collapsibleRootPropDefs: Record<string, PropDef> = {
|
||||
defaultOpen: {
|
||||
type: 'boolean',
|
||||
default: 'false',
|
||||
},
|
||||
open: {
|
||||
type: 'boolean',
|
||||
},
|
||||
onOpenChange: {
|
||||
type: 'enum',
|
||||
values: ['(open) => void'],
|
||||
},
|
||||
...renderPropDefs,
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const collapsibleTriggerPropDefs: Record<string, PropDef> = {
|
||||
...renderPropDefs,
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const collapsiblePanelPropDefs: Record<string, PropDef> = {
|
||||
hiddenUntilFound: {
|
||||
type: 'boolean',
|
||||
default: 'false',
|
||||
},
|
||||
keepMounted: {
|
||||
type: 'boolean',
|
||||
default: 'false',
|
||||
},
|
||||
...renderPropDefs,
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
@@ -1,12 +0,0 @@
|
||||
import {
|
||||
classNamePropDefs,
|
||||
stylePropDefs,
|
||||
gapPropDefs,
|
||||
} from '../../../../utils/propDefs';
|
||||
import type { PropDef } from '../../../../utils/propDefs';
|
||||
|
||||
export const containerPropDefs: Record<string, PropDef> = {
|
||||
...gapPropDefs,
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
@@ -1,83 +0,0 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { Tabs } from '@/components/Tabs';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import {
|
||||
flexFAQ1,
|
||||
flexSimple,
|
||||
flexResponsive,
|
||||
flexAlign,
|
||||
} from '@/snippets/code-snippets';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { FlexSnippet } from '@/snippets/stories-snippets';
|
||||
import { flexPropDefs } from './props';
|
||||
import { spacingPropDefs } from '../../../../utils/propDefs';
|
||||
|
||||
# Flex
|
||||
|
||||
This is the flex container component. It will help to define the number of
|
||||
columns that will be used in the grid. You can also define the gap between the
|
||||
columns. All values are responsive.
|
||||
|
||||
<Snippet
|
||||
py={4}
|
||||
align="center"
|
||||
preview={<FlexSnippet story="Default" />}
|
||||
code={`<Flex>
|
||||
<DecorativeBox />
|
||||
<DecorativeBox />
|
||||
<DecorativeBox />
|
||||
</Flex>`}
|
||||
/>
|
||||
|
||||
<Tabs.Root>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab>Usage</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
<Tabs.Panel>
|
||||
<CodeBlock
|
||||
code={`import { Flex } from '@backstage/canon';
|
||||
|
||||
<Flex />
|
||||
`}
|
||||
/>
|
||||
</Tabs.Panel>
|
||||
</Tabs.Root>
|
||||
|
||||
## API reference
|
||||
|
||||
<PropsTable data={flexPropDefs} />
|
||||
|
||||
The grid component also accepts all the spacing props from the Box component.
|
||||
|
||||
<PropsTable data={spacingPropDefs} />
|
||||
|
||||
## Common questions
|
||||
|
||||
### Can I stack horizontally?
|
||||
|
||||
The Flex component only allows for stacking elements vertically. If you want
|
||||
to create a column layout, please use the Grid component.
|
||||
|
||||
<CodeBlock code={flexFAQ1} />
|
||||
|
||||
## Examples
|
||||
|
||||
### Simple
|
||||
|
||||
A simple example of how to use the Flex component.
|
||||
|
||||
<CodeBlock code={flexSimple} />
|
||||
|
||||
### Responsive
|
||||
|
||||
The Flex component also supports responsive values, making it easy to create
|
||||
responsive designs.
|
||||
|
||||
<CodeBlock code={flexResponsive} />
|
||||
|
||||
### Align
|
||||
|
||||
The Flex component also supports responsive alignment, making it easy to
|
||||
create responsive designs.
|
||||
|
||||
<CodeBlock code={flexAlign} />
|
||||
@@ -1,27 +0,0 @@
|
||||
import {
|
||||
PropDef,
|
||||
childrenPropDefs,
|
||||
classNamePropDefs,
|
||||
stylePropDefs,
|
||||
} from '../../../../utils/propDefs';
|
||||
|
||||
export const flexPropDefs: Record<string, PropDef> = {
|
||||
align: {
|
||||
type: 'enum',
|
||||
values: ['start', 'center', 'end', 'baseline', 'stretch'],
|
||||
responsive: true,
|
||||
},
|
||||
direction: {
|
||||
type: 'enum',
|
||||
values: ['row', 'column', 'row-reverse', 'column-reverse'],
|
||||
responsive: true,
|
||||
},
|
||||
justify: {
|
||||
type: 'enum',
|
||||
values: ['start', 'center', 'end', 'between'],
|
||||
responsive: true,
|
||||
},
|
||||
...childrenPropDefs,
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
@@ -1,59 +0,0 @@
|
||||
import {
|
||||
PropDef,
|
||||
childrenPropDefs,
|
||||
classNamePropDefs,
|
||||
stylePropDefs,
|
||||
} from '../../../../utils/propDefs';
|
||||
|
||||
const columnsValues = [
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'10',
|
||||
'11',
|
||||
'12',
|
||||
];
|
||||
|
||||
export const gridPropDefs: Record<string, PropDef> = {
|
||||
columns: {
|
||||
type: 'enum | string',
|
||||
values: [...columnsValues, 'auto'],
|
||||
responsive: true,
|
||||
default: 'auto',
|
||||
},
|
||||
...childrenPropDefs,
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const gridItemPropDefs: Record<string, PropDef> = {
|
||||
colSpan: {
|
||||
type: 'enum | string',
|
||||
values: [...columnsValues, 'full'],
|
||||
responsive: true,
|
||||
},
|
||||
rowSpan: {
|
||||
type: 'enum | string',
|
||||
values: [...columnsValues, 'full'],
|
||||
responsive: true,
|
||||
},
|
||||
start: {
|
||||
type: 'enum | string',
|
||||
values: [...columnsValues, 'auto'],
|
||||
responsive: true,
|
||||
},
|
||||
end: {
|
||||
type: 'enum | string',
|
||||
values: [...columnsValues, 'auto'],
|
||||
responsive: true,
|
||||
},
|
||||
...childrenPropDefs,
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
@@ -1,102 +0,0 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { HeadingSnippet } from '@/snippets/stories-snippets';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { Tabs } from '@/components/Tabs';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import { headingPropDefs } from './props';
|
||||
|
||||
# Heading
|
||||
|
||||
Headings are used to structure the content of your page.
|
||||
|
||||
<Snippet
|
||||
py={4}
|
||||
preview={<HeadingSnippet story="Title1" />}
|
||||
code={`<Heading variant="title1">Hello World!</Heading>`}
|
||||
/>
|
||||
|
||||
<Tabs.Root>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab>Usage</Tabs.Tab>
|
||||
<Tabs.Tab>Theming</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
<Tabs.Panel>
|
||||
<CodeBlock
|
||||
code={`import { Heading } from '@backstage/canon';
|
||||
|
||||
<Heading />
|
||||
`}
|
||||
/>
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel>
|
||||
We recommend starting with our [global tokens](/theme/theming) 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.
|
||||
<CodeBlock
|
||||
code={`<Heading className="heading" />`}
|
||||
/>
|
||||
|
||||
</Tabs.Panel>
|
||||
</Tabs.Root>
|
||||
|
||||
## API reference
|
||||
|
||||
<PropsTable data={headingPropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
### All variants
|
||||
|
||||
The `Heading` component has a `variant` prop that can be used to change the
|
||||
appearance of the heading.
|
||||
|
||||
<Snippet
|
||||
py={2}
|
||||
open
|
||||
preview={<HeadingSnippet story="AllVariants" />}
|
||||
code={`<Flex direction="column" gap="4">
|
||||
<Heading variant="display">Display</Heading>
|
||||
<Heading variant="title1">Title 1</Heading>
|
||||
<Heading variant="title2">Title 2</Heading>
|
||||
<Heading variant="title3">Title 3</Heading>
|
||||
<Heading variant="title4">Title 4</Heading>
|
||||
<Heading variant="title5">Title 5</Heading>
|
||||
</Flex>`}
|
||||
/>
|
||||
|
||||
### Truncate
|
||||
|
||||
The `Heading` component has a `truncate` prop that can be used to truncate the
|
||||
heading.
|
||||
|
||||
<Snippet
|
||||
py={2}
|
||||
open
|
||||
preview={<HeadingSnippet story="Truncate" />}
|
||||
code={`<Heading style={{ maxWidth: '400px' }} truncate>
|
||||
A man looks at a painting in a museum and says, “Brothers and sisters I
|
||||
have none, but that man's father is my father's son.” Who is
|
||||
in the painting?
|
||||
</Heading>`}
|
||||
/>
|
||||
|
||||
### Custom render
|
||||
|
||||
You can also use the `render` prop to render the heading as a different element.
|
||||
|
||||
<Snippet
|
||||
py={2}
|
||||
open
|
||||
preview={<HeadingSnippet story="CustomRender" />}
|
||||
code={`<Heading render={<h4 />}>Custom render</Heading>`}
|
||||
/>
|
||||
|
||||
### Responsive
|
||||
|
||||
You can also use the `variant` prop to change the appearance of the text based
|
||||
on the screen size.
|
||||
|
||||
<CodeBlock
|
||||
code={`<Heading variant={{ initial: 'title2', lg: 'title1' }}>
|
||||
Responsive heading
|
||||
</Heading>`}
|
||||
/>
|
||||
@@ -1,21 +0,0 @@
|
||||
import { classNamePropDefs, stylePropDefs } from '../../../../utils/propDefs';
|
||||
import type { PropDef } from '../../../../utils/propDefs';
|
||||
|
||||
export const headingPropDefs: Record<string, PropDef> = {
|
||||
variant: {
|
||||
type: 'enum',
|
||||
values: ['display', 'title1', 'title2', 'title3', 'title4', 'title5'],
|
||||
responsive: true,
|
||||
},
|
||||
children: {
|
||||
type: 'enum',
|
||||
values: ['ReactNode'],
|
||||
responsive: false,
|
||||
},
|
||||
truncate: {
|
||||
type: 'boolean',
|
||||
default: 'false',
|
||||
},
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
@@ -1,97 +0,0 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { Tabs } from '@/components/Tabs';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import { IconButtonSnippet } from '@/snippets/stories-snippets';
|
||||
import { iconButtonVariants } from '@/snippets/code-snippets';
|
||||
import { iconButtonPropDefs } from './props';
|
||||
|
||||
# Icon Button
|
||||
|
||||
A button component with a single icon that can be used to trigger actions.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
preview={<IconButtonSnippet story="Variants" />}
|
||||
code={`<Flex align="center">
|
||||
<IconButton icon="cloud" variant="primary" />
|
||||
<IconButton icon="cloud" variant="secondary" />
|
||||
</Flex>`}
|
||||
/>
|
||||
|
||||
<Tabs.Root>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab>Usage</Tabs.Tab>
|
||||
<Tabs.Tab>Theming</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
<Tabs.Panel>
|
||||
<CodeBlock
|
||||
code={`import { IconButton } from '@backstage/canon';
|
||||
|
||||
<IconButton />
|
||||
`}
|
||||
/>
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel>
|
||||
We recommend starting with our [global tokens](/theme/theming) 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.
|
||||
<CodeBlock
|
||||
code={`<IconButton className="canon-IconButton" />`}
|
||||
/>
|
||||
|
||||
</Tabs.Panel>
|
||||
</Tabs.Root>
|
||||
|
||||
## API reference
|
||||
|
||||
<PropsTable data={iconButtonPropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
### Variants
|
||||
|
||||
Here's a view when buttons have different variants.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<IconButtonSnippet story="Variants" />}
|
||||
code={iconButtonVariants}
|
||||
/>
|
||||
|
||||
### Sizes
|
||||
|
||||
Here's a view when buttons have different sizes.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<IconButtonSnippet story="Sizes" />}
|
||||
code={`<Flex align="center">
|
||||
<IconButton icon="cloud" size="small" />
|
||||
<IconButton icon="cloud" size="medium" />
|
||||
</Flex>`}
|
||||
/>
|
||||
|
||||
### Disabled
|
||||
|
||||
Here's a view when buttons are disabled.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<IconButtonSnippet story="Disabled" />}
|
||||
code={`<IconButton icon="cloud" disabled />`}
|
||||
/>
|
||||
|
||||
### Responsive
|
||||
|
||||
Here's a view when buttons are responsive.
|
||||
|
||||
<CodeBlock
|
||||
code={`<IconButton icon="cloud" variant={{ initial: 'primary', lg: 'secondary' }} />`}
|
||||
/>
|
||||
@@ -1,20 +0,0 @@
|
||||
import { classNamePropDefs, stylePropDefs } from '../../../../utils/propDefs';
|
||||
import type { PropDef } from '../../../../utils/propDefs';
|
||||
|
||||
export const iconButtonPropDefs: Record<string, PropDef> = {
|
||||
variant: {
|
||||
type: 'enum',
|
||||
values: ['primary', 'secondary'],
|
||||
default: 'primary',
|
||||
responsive: true,
|
||||
},
|
||||
size: {
|
||||
type: 'enum',
|
||||
values: ['small', 'medium'],
|
||||
default: 'medium',
|
||||
responsive: true,
|
||||
},
|
||||
icon: { type: 'enum', values: 'icon', responsive: false },
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
@@ -1,44 +0,0 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { IconSnippet } from '@/snippets/stories-snippets';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { Tabs } from '@/components/Tabs';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import { iconPropDefs } from './props';
|
||||
|
||||
# Icon
|
||||
|
||||
Icons are used to represent an action or a state.
|
||||
|
||||
<Snippet
|
||||
py={4}
|
||||
align="center"
|
||||
preview={<IconSnippet story="Default" />}
|
||||
code={`<Icon name="heart" />`}
|
||||
/>
|
||||
|
||||
<Tabs.Root>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab>Usage</Tabs.Tab>
|
||||
<Tabs.Tab>Theming</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
<Tabs.Panel>
|
||||
<CodeBlock
|
||||
code={`import { Icon } from '@backstage/canon';
|
||||
|
||||
<Icon />
|
||||
`}
|
||||
/>
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel>
|
||||
We recommend starting with our [global tokens](/theme/theming) 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.
|
||||
<CodeBlock
|
||||
code={`<Icon className="icon" />`}
|
||||
/>
|
||||
|
||||
</Tabs.Panel>
|
||||
</Tabs.Root>
|
||||
|
||||
## API reference
|
||||
|
||||
<PropsTable data={iconPropDefs} />
|
||||
@@ -1,84 +0,0 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { Tabs } from '@/components/Tabs';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import {
|
||||
MenuSnippet,
|
||||
ButtonSnippet,
|
||||
LinkSnippet,
|
||||
} from '@/snippets/stories-snippets';
|
||||
import { linkPropDefs } from './props';
|
||||
|
||||
# Link
|
||||
|
||||
A link component that renders a `<a>` element.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
preview={<LinkSnippet story="Default" />}
|
||||
code={`<Link href="https://backstage.io">Sign up for Backstage</Link>`}
|
||||
/>
|
||||
|
||||
<Tabs.Root>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab>Usage</Tabs.Tab>
|
||||
<Tabs.Tab>Theming</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
<Tabs.Panel>
|
||||
<CodeBlock
|
||||
code={`import { Link } from '@backstage/canon';
|
||||
|
||||
<Link href="https://backstage.io">Sign up for Backstage</Link>`}
|
||||
/>
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel>
|
||||
We recommend starting with our [global tokens](/theme/theming) 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.
|
||||
- `canon-Link`
|
||||
- `canon-Link[data-variant='body']`
|
||||
- `canon-Link[data-variant='subtitle']`
|
||||
- `canon-Link[data-variant='caption']`
|
||||
- `canon-Link[data-variant='label']`
|
||||
- `canon-Link[data-weight='regular']`
|
||||
- `canon-Link[data-weight='bold']`
|
||||
</Tabs.Panel>
|
||||
</Tabs.Root>
|
||||
|
||||
## API reference
|
||||
|
||||
<PropsTable data={linkPropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
### Variants
|
||||
|
||||
Here's a view when links have different variants.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<LinkSnippet story="AllVariants" />}
|
||||
code={`<Flex gap="4" direction="column">
|
||||
<Link href="https://canon.backstage.io" variant="subtitle" />
|
||||
<Link href="https://canon.backstage.io" variant="body" />
|
||||
<Link href="https://canon.backstage.io" variant="caption" />
|
||||
<Link href="https://canon.backstage.io" variant="label" />
|
||||
</Flex>`}
|
||||
/>
|
||||
|
||||
### Weights
|
||||
|
||||
Here's a view when links have different weights.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<LinkSnippet story="AllWeights" />}
|
||||
code={`<Flex gap="4" direction="column">
|
||||
<Link href="https://canon.backstage.io" weight="regular" />
|
||||
<Link href="https://canon.backstage.io" weight="bold" />
|
||||
</Flex>`}
|
||||
/>
|
||||
@@ -1,22 +0,0 @@
|
||||
import { classNamePropDefs, stylePropDefs } from '@/utils/propDefs';
|
||||
import type { PropDef } from '@/utils/propDefs';
|
||||
|
||||
export const linkPropDefs: Record<string, PropDef> = {
|
||||
to: {
|
||||
type: 'string',
|
||||
},
|
||||
variant: {
|
||||
type: 'enum',
|
||||
values: ['subtitle', 'body', 'caption', 'label'],
|
||||
default: 'body',
|
||||
responsive: true,
|
||||
},
|
||||
weight: {
|
||||
type: 'enum',
|
||||
values: ['regular', 'bold'],
|
||||
default: 'regular',
|
||||
responsive: true,
|
||||
},
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
@@ -1,202 +0,0 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { Tabs } from '@/components/Tabs';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import { MenuSnippet } from '@/snippets/stories-snippets';
|
||||
import { BaseUI } from '@/components/HeadlessBanners/BaseUI';
|
||||
import {
|
||||
menuRootPropDefs,
|
||||
menuTriggerPropDefs,
|
||||
menuPositionerPropDefs,
|
||||
menuItemPropDefs,
|
||||
} from './props';
|
||||
|
||||
# Menu
|
||||
|
||||
A list of actions in a dropdown, enhanced with keyboard navigation.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
preview={<MenuSnippet story="Default" />}
|
||||
code={`<Menu.Root>
|
||||
<Menu.Trigger
|
||||
render={props => (
|
||||
<Button
|
||||
{...props}
|
||||
size="medium"
|
||||
variant="secondary"
|
||||
iconEnd="chevron-down"
|
||||
>
|
||||
Menu
|
||||
</Button>
|
||||
)}
|
||||
/>
|
||||
<Menu.Portal>
|
||||
<Menu.Positioner sideOffset={8} align="start">
|
||||
<Menu.Popup>
|
||||
<Menu.Item>Settings</Menu.Item>
|
||||
<Menu.Item>Invite new members</Menu.Item>
|
||||
<Menu.Item>Download app</Menu.Item>
|
||||
<Menu.Item>Log out</Menu.Item>
|
||||
</Menu.Popup>
|
||||
</Menu.Positioner>
|
||||
</Menu.Portal>
|
||||
</Menu.Root>`}
|
||||
/>
|
||||
|
||||
<Tabs.Root>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab>Usage</Tabs.Tab>
|
||||
<Tabs.Tab>Theming</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
<Tabs.Panel>
|
||||
<CodeBlock
|
||||
code={`import { Menu } from '@backstage/canon';
|
||||
|
||||
<Menu.Root>
|
||||
<Menu.Trigger />
|
||||
<Menu.Portal>
|
||||
<Menu.Positioner>
|
||||
<Menu.Popup>
|
||||
<Menu.Item />
|
||||
</Menu.Popup>
|
||||
</Menu.Positioner>
|
||||
</Menu.Portal>
|
||||
</Menu.Root>`}
|
||||
/>
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel>
|
||||
We recommend starting with our [global tokens](/theme/theming) 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.
|
||||
- `canon-MenuTrigger`
|
||||
- `canon-MenuBackdrop`
|
||||
- `canon-MenuPositioner`
|
||||
- `canon-MenuPopup`
|
||||
- `canon-MenuArrow`
|
||||
- `canon-MenuItem`
|
||||
- `canon-MenuGroup`
|
||||
- `canon-MenuGroupLabel`
|
||||
- `canon-MenuRadioGroup`
|
||||
- `canon-MenuRadioItem`
|
||||
- `canon-MenuRadioItemIndicator`
|
||||
- `canon-MenuCheckboxItem`
|
||||
- `canon-MenuCheckboxItemIndicator`
|
||||
- `canon-MenuSubmenuTrigger`
|
||||
- `canon-MenuSeparator`
|
||||
</Tabs.Panel>
|
||||
</Tabs.Root>
|
||||
|
||||
## API reference
|
||||
|
||||
<BaseUI href="https://base-ui.com/react/components/menu" />
|
||||
|
||||
### Menu.Root
|
||||
|
||||
Groups all parts of the menu. Doesn't render its own HTML element.
|
||||
|
||||
<PropsTable data={menuRootPropDefs} />
|
||||
|
||||
### Menu.Trigger
|
||||
|
||||
The trigger by default render a simple unstyled button. Because menus can be rendered in different ways, we recommend
|
||||
using the `render` prop to render a custom trigger.
|
||||
|
||||
<CodeBlock code={`<Menu.Trigger render={props => <Button {...props} />} />`} />
|
||||
|
||||
<PropsTable data={menuTriggerPropDefs} />
|
||||
|
||||
### Menu.Positioner
|
||||
|
||||
Positions the menu popup against the trigger. Renders a `<div>` element.
|
||||
|
||||
<PropsTable data={menuPositionerPropDefs} />
|
||||
|
||||
### Menu.Item
|
||||
|
||||
An individual interactive item in the menu. Renders a `<div>` element.
|
||||
|
||||
<PropsTable data={menuItemPropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
### Open on hover
|
||||
|
||||
To create a menu that opens on hover, add the `openOnHover` prop to the Root part.
|
||||
You can additionally configure how quickly the menu opens on hover using the `delay` prop.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<MenuSnippet story="OpenOnHover" />}
|
||||
code={`<Menu.Root openOnHover delay={100}>
|
||||
<Menu.Trigger
|
||||
render={props => (
|
||||
<Button
|
||||
{...props}
|
||||
size="medium"
|
||||
variant="secondary"
|
||||
iconEnd="chevron-down"
|
||||
>
|
||||
Menu
|
||||
</Button>
|
||||
)}
|
||||
/>
|
||||
<Menu.Portal>
|
||||
<Menu.Positioner sideOffset={8} align="start">
|
||||
<Menu.Popup>
|
||||
<Menu.Item>Settings</Menu.Item>
|
||||
<Menu.Item>Invite new members</Menu.Item>
|
||||
<Menu.Item>Download app</Menu.Item>
|
||||
<Menu.Item>Log out</Menu.Item>
|
||||
</Menu.Popup>
|
||||
</Menu.Positioner>
|
||||
</Menu.Portal>
|
||||
</Menu.Root>`}
|
||||
/>
|
||||
|
||||
### Nested navigation
|
||||
|
||||
You can nest menus to create a more complex navigation structure.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<MenuSnippet story="Submenu" />}
|
||||
code={`<Menu.Trigger
|
||||
render={props => (
|
||||
<Button
|
||||
{...props}
|
||||
size="small"
|
||||
variant="secondary"
|
||||
iconEnd={<Icon name="chevron-down" />}
|
||||
>
|
||||
Menu
|
||||
</Button>
|
||||
)}
|
||||
/>
|
||||
<Menu.Portal>
|
||||
<Menu.Positioner sideOffset={8} align="start">
|
||||
<Menu.Popup>
|
||||
<Menu.Item>Settings</Menu.Item>
|
||||
<Menu.Item>Invite new members</Menu.Item>
|
||||
<Menu.Item>Download app</Menu.Item>
|
||||
<Menu.Item>Log out</Menu.Item>
|
||||
<Menu.Root>
|
||||
<Menu.SubmenuTrigger>Submenu</Menu.SubmenuTrigger>
|
||||
<Menu.Portal>
|
||||
<Menu.Positioner>
|
||||
<Menu.Popup>
|
||||
<Menu.Item>Submenu Item 1</Menu.Item>
|
||||
<Menu.Item>Submenu Item 2</Menu.Item>
|
||||
<Menu.Item>Submenu Item 3</Menu.Item>
|
||||
</Menu.Popup>
|
||||
</Menu.Positioner>
|
||||
</Menu.Portal>
|
||||
</Menu.Root>
|
||||
</Menu.Popup>
|
||||
</Menu.Positioner>
|
||||
</Menu.Portal>`}
|
||||
/>
|
||||
@@ -1,128 +0,0 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { Tabs } from '@/components/Tabs';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import { SelectSnippet } from '@/snippets/stories-snippets';
|
||||
import { selectPropDefs } from './props';
|
||||
|
||||
# Select
|
||||
|
||||
A common form component for choosing a predefined value in a dropdown menu.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
preview={<SelectSnippet story="Preview" />}
|
||||
code={`<Select name="font" label="Font Family" options={[
|
||||
{ value: 'sans', label: 'Sans-serif' },
|
||||
{ value: 'serif', label: 'Serif' },
|
||||
{ value: 'mono', label: 'Monospace' },
|
||||
{ value: 'cursive', label: 'Cursive' },
|
||||
]} />
|
||||
`}
|
||||
/>
|
||||
|
||||
<Tabs.Root>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab>Usage</Tabs.Tab>
|
||||
<Tabs.Tab>Theming</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
<Tabs.Panel>
|
||||
<CodeBlock
|
||||
code={`import { Select } from '@backstage/canon';
|
||||
|
||||
<Select
|
||||
name="font"
|
||||
options={[
|
||||
{ value: 'sans', label: 'Sans-serif' },
|
||||
{ value: 'serif', label: 'Serif' },
|
||||
{ value: 'mono', label: 'Monospace' },
|
||||
{ value: 'cursive', label: 'Cursive' },
|
||||
]}
|
||||
/>
|
||||
`}
|
||||
/>
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel>
|
||||
We recommend starting with our [global tokens](/theme/theming) 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.
|
||||
<CodeBlock
|
||||
code={`<Select className="canon-SelectFieldRoot" />`}
|
||||
/>
|
||||
|
||||
</Tabs.Panel>
|
||||
</Tabs.Root>
|
||||
|
||||
## API reference
|
||||
|
||||
<PropsTable data={selectPropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
### With Label and description
|
||||
|
||||
Select component with label and description.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<SelectSnippet story="WithDescription" />}
|
||||
code={`<Select
|
||||
name="font"
|
||||
label="Font Family"
|
||||
description="Choose a font family for your document"
|
||||
options={[ ... ]}
|
||||
/>`}
|
||||
/>
|
||||
|
||||
### Sizes
|
||||
|
||||
Here's a view when the selects have different sizes.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<SelectSnippet story="Sizes" />}
|
||||
code={`<Flex>
|
||||
<Select
|
||||
size="small"
|
||||
label="Font family"
|
||||
options={[ ... ]}
|
||||
/>
|
||||
<Select
|
||||
size="medium"
|
||||
label="Font family"
|
||||
options={[ ... ]}
|
||||
/>
|
||||
</Flex>`}
|
||||
/>
|
||||
|
||||
### Disabled
|
||||
|
||||
Here's a view when the select is disabled.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<SelectSnippet story="Disabled" />}
|
||||
code={`<Select
|
||||
disabled
|
||||
label="Font family"
|
||||
options={[ ... ]}
|
||||
/>`}
|
||||
/>
|
||||
|
||||
### Responsive
|
||||
|
||||
Here's a view when the select is responsive.
|
||||
|
||||
<CodeBlock
|
||||
code={`<Select
|
||||
size={{ initial: 'small', lg: 'medium' }}
|
||||
label="Font family"
|
||||
options={[ ... ]}
|
||||
/>`}
|
||||
/>
|
||||
@@ -1,54 +0,0 @@
|
||||
import { classNamePropDefs, stylePropDefs } from '../../../../utils/propDefs';
|
||||
import type { PropDef } from '../../../../utils/propDefs';
|
||||
|
||||
export const selectPropDefs: Record<string, PropDef> = {
|
||||
label: {
|
||||
type: 'string',
|
||||
default: 'Select an option',
|
||||
responsive: false,
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
responsive: false,
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
responsive: false,
|
||||
required: true,
|
||||
},
|
||||
options: {
|
||||
type: 'enum',
|
||||
values: ['Array<{ value: string, label: string }>'],
|
||||
required: true,
|
||||
},
|
||||
value: {
|
||||
type: 'string',
|
||||
responsive: false,
|
||||
},
|
||||
defaultValue: {
|
||||
type: 'string',
|
||||
responsive: false,
|
||||
},
|
||||
placeholder: {
|
||||
type: 'string',
|
||||
responsive: false,
|
||||
},
|
||||
size: {
|
||||
type: 'enum',
|
||||
values: ['small', 'medium'],
|
||||
default: 'medium',
|
||||
responsive: true,
|
||||
},
|
||||
onValueChange: {
|
||||
type: 'enum',
|
||||
values: ['(value: string) => void'],
|
||||
responsive: false,
|
||||
},
|
||||
onOpenChange: {
|
||||
type: 'enum',
|
||||
values: ['(open: boolean) => void'],
|
||||
responsive: false,
|
||||
},
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
@@ -1,92 +0,0 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { TabsSnippet } from '@/snippets/stories-snippets';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { Tabs } from '@/components/Tabs';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import {
|
||||
tabsRootPropDefs,
|
||||
tabsListPropDefs,
|
||||
tabsTabPropDefs,
|
||||
tabsPanelPropDefs,
|
||||
} from './props';
|
||||
import { BaseUI } from '@/components/HeadlessBanners/BaseUI';
|
||||
|
||||
# Tabs
|
||||
|
||||
A component for toggling between related panels on the same page.
|
||||
|
||||
<Snippet
|
||||
py={4}
|
||||
preview={<TabsSnippet story="Default" />}
|
||||
code={`<Tabs.Root>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab>Tab 1</Tabs.Tab>
|
||||
<Tabs.Tab>Tab 2</Tabs.Tab>
|
||||
<Tabs.Tab>Tab 3 With long title</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
<Tabs.Panel>Content for Tab 1</Tabs.Panel>
|
||||
<Tabs.Panel>Content for Tab 2</Tabs.Panel>
|
||||
<Tabs.Panel>Content for Tab 3</Tabs.Panel>
|
||||
</Tabs.Root>`}
|
||||
/>
|
||||
|
||||
<Tabs.Root>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab>Usage</Tabs.Tab>
|
||||
<Tabs.Tab>Theming</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
<Tabs.Panel>
|
||||
<CodeBlock
|
||||
code={`import { Tabs } from '@backstage/canon';
|
||||
|
||||
<Tabs.Root>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab>Tab 1</Tabs.Tab>
|
||||
<Tabs.Tab>Tab 2</Tabs.Tab>
|
||||
<Tabs.Tab>Tab 3</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
<Tabs.Panel>Content for Tab 1</Tabs.Panel>
|
||||
<Tabs.Panel>Content for Tab 2</Tabs.Panel>
|
||||
<Tabs.Panel>Content for Tab 3</Tabs.Panel>
|
||||
</Tabs.Root>
|
||||
`}
|
||||
/>
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel>
|
||||
We recommend starting with our [global tokens](/theme/theming) 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.
|
||||
- `canon-TabsRoot`
|
||||
- `canon-TabsList`
|
||||
- `canon-TabsTab`
|
||||
- `canon-TabsPanel`
|
||||
- `canon-TabsIndicator`
|
||||
</Tabs.Panel>
|
||||
</Tabs.Root>
|
||||
|
||||
## API reference
|
||||
|
||||
<BaseUI href="https://base-ui.com/react/components/menu" />
|
||||
|
||||
### Tabs.Root
|
||||
|
||||
Groups the tabs and the corresponding panels. Renders a `<div>` element.
|
||||
|
||||
<PropsTable data={tabsRootPropDefs} />
|
||||
|
||||
### Tabs.List
|
||||
|
||||
Groups the individual tab buttons. Renders a `<div>` element.
|
||||
|
||||
<PropsTable data={tabsListPropDefs} />
|
||||
|
||||
### Tabs.Tab
|
||||
|
||||
An individual interactive tab button that toggles the corresponding panel. Renders a `<button>` element.
|
||||
|
||||
<PropsTable data={tabsTabPropDefs} />
|
||||
|
||||
### Tabs.Panel
|
||||
|
||||
A panel displayed when the corresponding tab is active. Renders a `<div>` element.
|
||||
|
||||
<PropsTable data={tabsPanelPropDefs} />
|
||||
@@ -1,80 +0,0 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { Tabs } from '@/components/Tabs';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import { TextFieldSnippet } from '@/snippets/stories-snippets';
|
||||
import { BaseUI } from '@/components/HeadlessBanners/BaseUI';
|
||||
import { inputPropDefs } from './props';
|
||||
|
||||
# TextField
|
||||
|
||||
A text field component for your forms.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
preview={<TextFieldSnippet story="WithLabel" />}
|
||||
code={`<TextField label="Label" placeholder="Enter a URL" />`}
|
||||
/>
|
||||
|
||||
<Tabs.Root>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab>Usage</Tabs.Tab>
|
||||
<Tabs.Tab>Theming</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
<Tabs.Panel>
|
||||
<CodeBlock
|
||||
code={`import { TextField } from '@backstage/canon';
|
||||
|
||||
<TextField />
|
||||
`}
|
||||
/>
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel>
|
||||
We recommend starting with our [global tokens](/theme/theming) 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.
|
||||
- `canon-TextField`
|
||||
- `canon-TextFieldLabel`
|
||||
- `canon-TextFieldRequired`
|
||||
- `canon-TextFieldInputWrapper`
|
||||
- `canon-TextFieldIcon`
|
||||
- `canon-TextFieldInput`
|
||||
- `canon-TextFieldClearButton`
|
||||
- `canon-TextFieldClearButtonIcon`
|
||||
- `canon-TextFieldDescription`
|
||||
- `canon-TextFieldError`
|
||||
</Tabs.Panel>
|
||||
</Tabs.Root>
|
||||
|
||||
## API reference
|
||||
|
||||
<PropsTable data={inputPropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
### Sizes
|
||||
|
||||
We support two different sizes: `small`, `medium`.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<TextFieldSnippet story="Sizes" />}
|
||||
code={`<Flex direction="row" gap="4">
|
||||
<TextField size="small" placeholder="Small" icon={<Icon name="sparkling" />} />
|
||||
<TextField size="medium" placeholder="Medium" icon={<Icon name="sparkling" />} />
|
||||
</Flex>`}
|
||||
/>
|
||||
|
||||
### With description
|
||||
|
||||
Here's a simple TextField with a description.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<TextFieldSnippet story="WithDescription" />}
|
||||
code={`<TextField label="Label" description="Description" placeholder="Enter a URL" />`}
|
||||
/>
|
||||
@@ -1,27 +0,0 @@
|
||||
import { classNamePropDefs, stylePropDefs } from '../../../../utils/propDefs';
|
||||
import type { PropDef } from '../../../../utils/propDefs';
|
||||
|
||||
export const inputPropDefs: Record<string, PropDef> = {
|
||||
size: {
|
||||
type: 'enum',
|
||||
values: ['small', 'medium'],
|
||||
default: 'small',
|
||||
responsive: true,
|
||||
},
|
||||
label: {
|
||||
type: 'string',
|
||||
},
|
||||
icon: {
|
||||
type: 'enum',
|
||||
values: ['ReactNode'],
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
},
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
@@ -1,139 +0,0 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { TextSnippet } from '@/snippets/stories-snippets';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { Tabs } from '@/components/Tabs';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import { textPropDefs } from './props';
|
||||
|
||||
# Text
|
||||
|
||||
The `Text` component is used to display content on your page.
|
||||
|
||||
<Snippet
|
||||
py={4}
|
||||
preview={<TextSnippet story="Default" />}
|
||||
code={`<Text style={{ maxWidth: '600px' }}>
|
||||
A man looks at a painting in a museum and says, “Brothers and sisters I
|
||||
have none, but that man's father is my father's son.” Who is in
|
||||
the painting?
|
||||
</Text>`}
|
||||
/>
|
||||
|
||||
<Tabs.Root>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab>Usage</Tabs.Tab>
|
||||
<Tabs.Tab>Theming</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
<Tabs.Panel>
|
||||
<CodeBlock
|
||||
code={`import { Text } from '@backstage/canon';
|
||||
|
||||
<Text />
|
||||
`}
|
||||
/>
|
||||
</Tabs.Panel>
|
||||
<Tabs.Panel>
|
||||
We recommend starting with our [global tokens](/theme/theming) 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.
|
||||
<CodeBlock
|
||||
code={`<Text className="text" />`}
|
||||
/>
|
||||
|
||||
</Tabs.Panel>
|
||||
</Tabs.Root>
|
||||
|
||||
## API reference
|
||||
|
||||
<PropsTable data={textPropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
### All variants
|
||||
|
||||
The `Text` component has a `variant` prop that can be used to change the
|
||||
appearance of the text.
|
||||
|
||||
<Snippet
|
||||
open
|
||||
preview={<TextSnippet story="AllVariants" />}
|
||||
code={`<Flex direction="column" gap="4">
|
||||
<Text variant="subtitle" style={{ maxWidth: '600px' }}>
|
||||
A man looks at a painting in a museum and says, “Brothers and sisters I
|
||||
have none, but that man's father is my father's son.” Who is
|
||||
in the painting?
|
||||
</Text>
|
||||
<Text variant="body" style={{ maxWidth: '600px' }}>
|
||||
A man looks at a painting in a museum and says, “Brothers and sisters I
|
||||
have none, but that man's father is my father's son.” Who is
|
||||
in the painting?
|
||||
</Text>
|
||||
<Text variant="caption" style={{ maxWidth: '600px' }}>
|
||||
A man looks at a painting in a museum and says, “Brothers and sisters I
|
||||
have none, but that man's father is my father's son.” Who is
|
||||
in the painting?
|
||||
</Text>
|
||||
<Text variant="label" style={{ maxWidth: '600px' }}>
|
||||
A man looks at a painting in a museum and says, “Brothers and sisters I
|
||||
have none, but that man's father is my father's son.” Who is
|
||||
in the painting?
|
||||
</Text>
|
||||
</Flex>`}
|
||||
/>
|
||||
|
||||
### All weights
|
||||
|
||||
The `Text` component has a `weight` prop that can be used to change the
|
||||
appearance of the text.
|
||||
|
||||
<Snippet
|
||||
open
|
||||
preview={<TextSnippet story="AllWeights" />}
|
||||
code={`<Flex direction="column" gap="4">
|
||||
<Text weight="regular" style={{ maxWidth: '600px' }}>
|
||||
A man looks at a painting in a museum and says, “Brothers and sisters I
|
||||
have none, but that man's father is my father's son.” Who is
|
||||
in the painting?
|
||||
</Text>
|
||||
<Text weight="bold" style={{ maxWidth: '600px' }}>
|
||||
A man looks at a painting in a museum and says, “Brothers and sisters I
|
||||
have none, but that man's father is my father's son.” Who is
|
||||
in the painting?
|
||||
</Text>
|
||||
</Flex>`}
|
||||
/>
|
||||
|
||||
### Truncate
|
||||
|
||||
The `Text` component has a `truncate` prop that can be used to truncate the
|
||||
text.
|
||||
|
||||
<Snippet
|
||||
open
|
||||
preview={<TextSnippet story="Truncate" />}
|
||||
code={`<Text weight="regular" style={{ maxWidth: '600px' }} truncate>
|
||||
A man looks at a painting in a museum and says, “Brothers and sisters I
|
||||
have none, but that man's father is my father's son.” Who is
|
||||
in the painting?
|
||||
</Text>`}
|
||||
/>
|
||||
|
||||
### Custom render
|
||||
|
||||
You can also use the `render` prop to render the text as a different element.
|
||||
|
||||
<Snippet
|
||||
open
|
||||
preview={<TextSnippet story="CustomRender" />}
|
||||
code={`<Text render={<span />}>Custom render</Text>`}
|
||||
/>
|
||||
|
||||
### Responsive
|
||||
|
||||
You can also use the `variant` prop to change the appearance of the text based
|
||||
on the screen size.
|
||||
|
||||
<CodeBlock
|
||||
code={`<Text variant={{ initial: 'body', lg: 'subtitle' }}>
|
||||
Responsive text
|
||||
</Text>`}
|
||||
/>
|
||||
@@ -1,26 +0,0 @@
|
||||
import {
|
||||
childrenPropDefs,
|
||||
classNamePropDefs,
|
||||
stylePropDefs,
|
||||
} from '../../../../utils/propDefs';
|
||||
import type { PropDef } from '../../../../utils/propDefs';
|
||||
|
||||
export const textPropDefs: Record<string, PropDef> = {
|
||||
variant: {
|
||||
type: 'enum',
|
||||
values: ['display', 'title1', 'title2', 'title3', 'title4', 'title5'],
|
||||
responsive: true,
|
||||
},
|
||||
weight: {
|
||||
type: 'enum',
|
||||
values: ['regular', 'bold'],
|
||||
responsive: true,
|
||||
},
|
||||
truncate: {
|
||||
type: 'boolean',
|
||||
default: 'false',
|
||||
},
|
||||
...childrenPropDefs,
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
@@ -40,10 +40,6 @@ import { Flex, Button, Text } from '@backstage/canon';
|
||||
</Flex>;
|
||||
```
|
||||
|
||||
## Roadmap
|
||||
|
||||
You can check our roadmap [on GitHub](https://github.com/orgs/backstage/projects/10). We'll do our best to keep you updated on the progress.
|
||||
|
||||
## Next steps
|
||||
|
||||
Now that you have the basics down, you can start building your plugin using the new design system.
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
# Releases
|
||||
|
||||
## Version 0.4.0
|
||||
|
||||
### Main updates
|
||||
|
||||
- ✨ Add new `Tab` component - [#29996](https://github.com/backstage/backstage/pull/29996)
|
||||
- ✨ Add `truncate` prop to `Text` and `Heading` - [#29988](https://github.com/backstage/backstage/pull/29988)
|
||||
- ✨ Add combobox option to `Menu` - [#29986](https://github.com/backstage/backstage/pull/29986)
|
||||
- ✨ Add icon prop on `TextField` - [#29820](https://github.com/backstage/backstage/pull/29820)
|
||||
- Improve icon props on `Button` and `IconButton` - [#29667](https://github.com/backstage/backstage/pull/29667)
|
||||
- Improve the way we treat custom render on `Text` and `Heading` - [#29989](https://github.com/backstage/backstage/pull/29989)
|
||||
- Improve `Menu` styles - [#29986](https://github.com/backstage/backstage/pull/29986)
|
||||
- Improve `TextField` styles - [#29974](https://github.com/backstage/backstage/pull/29974)
|
||||
- Improve clear button on `TextField` - [#29878](https://github.com/backstage/backstage/pull/29878)
|
||||
|
||||
### Notable fixes
|
||||
|
||||
- Fix spacing props on all layout components - [#30013](https://github.com/backstage/backstage/pull/30013)
|
||||
- Fix - Pin Base UI version - [#29782](https://github.com/backstage/backstage/pull/29782)
|
||||
- Fix - Clicking `Select` label moves focus to trigger - [#29755](https://github.com/backstage/backstage/pull/29755)
|
||||
- Fix `DataTable.Pagination` count issue - [#29688](https://github.com/backstage/backstage/pull/29688)
|
||||
|
||||
## Version 0.3.0
|
||||
|
||||
### Main updates
|
||||
|
||||
- Add `DataTable` component - [#29484](https://github.com/backstage/backstage/pull/29484), [#29603](https://github.com/backstage/backstage/pull/29603)
|
||||
- Add `Select` component - [#29440](https://github.com/backstage/backstage/pull/29440)
|
||||
- Add `Avatar` component - [#29594](https://github.com/backstage/backstage/pull/29594)
|
||||
- Add `Collapsible` component - [#29617](https://github.com/backstage/backstage/pull/29617)
|
||||
- Add `TextField` component instead of `Field` + `Input` - [#29364](https://github.com/backstage/backstage/pull/29364)
|
||||
- Add `TableCellProfile` - [#29600](https://github.com/backstage/backstage/pull/29600)
|
||||
- Add breakpoint hooks - `up()` and `down()` - [#29564](https://github.com/backstage/backstage/pull/29564)
|
||||
- Add gray scale css tokens - [#29543](https://github.com/backstage/backstage/pull/29543)
|
||||
- Update CSS styling API using `[data-___]` instead of class names for props - [#29560](https://github.com/backstage/backstage/pull/29560)
|
||||
- Update `Checkbox` dark mode - [#29544](https://github.com/backstage/backstage/pull/29544)
|
||||
- Update `Container` styles - [#29475](https://github.com/backstage/backstage/pull/29475)
|
||||
- Update `Menu` styles - [#29351](https://github.com/backstage/backstage/pull/29351)
|
||||
- Fix `Select` styles on small sizes + with long option names - [#29545](https://github.com/backstage/backstage/pull/29545)
|
||||
- Fix render prop on `Link` - [#29247](https://github.com/backstage/backstage/pull/29247)
|
||||
- Remove `Field` from `TextField` + `Select` - [#29482](https://github.com/backstage/backstage/pull/29482)
|
||||
- Update `textDecoration` to `none` on `Text` / `Heading` - [#29357](https://github.com/backstage/backstage/pull/29357)
|
||||
|
||||
### Notable fixes
|
||||
|
||||
- Docs - Use stories from Storybook for all examples in Nextjs - [#29306](https://github.com/backstage/backstage/pull/29306)
|
||||
- Docs - Add release page (this one 🤗) - [#29461](https://github.com/backstage/backstage/pull/29461)
|
||||
- Docs - Add docs for Menu, Link - [#29576](https://github.com/backstage/backstage/pull/29576)
|
||||
- Fix CSS watch mode - [#29352](https://github.com/backstage/backstage/pull/29352)
|
||||
|
||||
## Version 0.2.0
|
||||
|
||||
### Main updates
|
||||
|
||||
- New `Tooltip` component - [#29241](https://github.com/backstage/backstage/pull/29241)
|
||||
- New `Menu` component - [#29151](https://github.com/backstage/backstage/pull/29151)
|
||||
- New `IconButton` component - [#29239](https://github.com/backstage/backstage/pull/29239)
|
||||
- New `ScrollArea` component - [#29240](https://github.com/backstage/backstage/pull/29240)
|
||||
- Improve `Button` & `Checkbox` styles - [#29127](https://github.com/backstage/backstage/pull/29127), [#28789](https://github.com/backstage/backstage/pull/28789)
|
||||
- Improve `Text` styles - [#29200](https://github.com/backstage/backstage/pull/29200)
|
||||
- Renamed `CanonProvider` to `IconProvider` - [#29002](https://github.com/backstage/backstage/pull/29002)
|
||||
- Added about 40+ new icons - [#29264](https://github.com/backstage/backstage/pull/29264)
|
||||
- Simplified styling into a unique styles.css file - [#29199](https://github.com/backstage/backstage/pull/29199)
|
||||
- Added Canon styles to Backstage - [#29137](https://github.com/backstage/backstage/pull/29137)
|
||||
- Update global CSS tokens - [#28804](https://github.com/backstage/backstage/pull/28804)
|
||||
- Merge Stack + Inline into Flex - [#28634](https://github.com/backstage/backstage/pull/28634)
|
||||
|
||||
### Notable fixes:
|
||||
|
||||
- Improve `Button` types - [#29205](https://github.com/backstage/backstage/pull/29205)
|
||||
- Move font weight and family back to each components - [#28972](https://github.com/backstage/backstage/pull/28972)
|
||||
- Fix custom values in spacing props - [#28770](https://github.com/backstage/backstage/pull/28770)
|
||||
- Multiple updates on the Canon Docs site - [#28760](https://github.com/backstage/backstage/pull/28760), [#28591](https://github.com/backstage/backstage/pull/28591)
|
||||
|
||||
## Version 0.1.0
|
||||
|
||||
We're excited to share the initial release of Canon 💚 In this first alpha version, you'll find the foundation of our design system:
|
||||
a set of versatile layout components and a handful of essential atomic elements to help you get started. While Canon is still in its
|
||||
early stages, it's ready for exploration and we'd love for you to give it a try and share your feedback.
|
||||
@@ -1,18 +1,3 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import styles from './styles.module.css';
|
||||
|
||||
export const Banner = ({
|
||||
|
||||
@@ -1,16 +1 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { Banner } from './Banner';
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { changelog } from '@/utils/changelog';
|
||||
import { MDXRemote } from 'next-mdx-remote-client/rsc';
|
||||
import { formattedMDXComponents } from '@/mdx-components';
|
||||
|
||||
export function Changelog() {
|
||||
// Group changelog entries by version
|
||||
const groupedChangelog = changelog.reduce((acc, entry) => {
|
||||
if (!acc[entry.version]) {
|
||||
acc[entry.version] = [];
|
||||
}
|
||||
acc[entry.version].push(entry);
|
||||
return acc;
|
||||
}, {} as Record<string, typeof changelog>);
|
||||
|
||||
// Sort versions in descending order
|
||||
const sortedVersions = Object.keys(groupedChangelog).sort((a, b) =>
|
||||
b.localeCompare(a),
|
||||
);
|
||||
|
||||
const content = sortedVersions
|
||||
.map(version => {
|
||||
const entries = groupedChangelog[version];
|
||||
|
||||
return `## Version ${version}
|
||||
|
||||
${entries
|
||||
.map(e => {
|
||||
const prs =
|
||||
e.prs.length > 0 &&
|
||||
e.prs
|
||||
.map(
|
||||
pr =>
|
||||
`[#${pr}](https://github.com/backstage/backstage/pull/${pr})`,
|
||||
)
|
||||
.join(', ');
|
||||
return `- ${e.description} ${prs}`;
|
||||
})
|
||||
.join('\n')}`;
|
||||
})
|
||||
.join('\n');
|
||||
|
||||
return <MDXRemote components={formattedMDXComponents} source={content} />;
|
||||
}
|
||||
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ReactNode } from 'react';
|
||||
import styles from './styles.module.css';
|
||||
|
||||
|
||||
@@ -1,16 +1 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { Chip } from './Chip';
|
||||
|
||||
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
.chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@@ -39,5 +23,5 @@
|
||||
}
|
||||
|
||||
[data-theme='dark'] .chip.head {
|
||||
background-color: #26417b;
|
||||
background-color: #33405b;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { CodeBlockProps } from '.';
|
||||
import { Text } from '../../../../packages/canon';
|
||||
import { Text } from '@backstage/canon';
|
||||
import styles from './styles.module.css';
|
||||
import parse from 'html-react-parser';
|
||||
|
||||
export const CodeBlockClient = ({
|
||||
out,
|
||||
@@ -18,7 +19,7 @@ export const CodeBlockClient = ({
|
||||
<Text variant="body">{title}</Text>
|
||||
</div>
|
||||
)}
|
||||
<div dangerouslySetInnerHTML={{ __html: out }} className={styles.code} />
|
||||
<div className={styles.code}>{parse(out)}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ReactNode, CSSProperties } from 'react';
|
||||
|
||||
export const Columns = ({
|
||||
|
||||
@@ -1,16 +1 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { Columns } from './Columns';
|
||||
|
||||
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
.columns {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export { ComponentInfos } from './ComponentInfos';
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { Component } from '@/utils/changelog';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
export interface ComponentInfosProps {
|
||||
usageCode?: string;
|
||||
classNames?: string[];
|
||||
component: Component;
|
||||
children: ReactNode;
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import { sass } from '@codemirror/lang-sass';
|
||||
import styles from './styles.module.css';
|
||||
import { usePlayground } from '@/utils/playground-context';
|
||||
import { AnimatePresence, motion } from 'motion/react';
|
||||
import { Icon } from '../../../../packages/canon';
|
||||
import { Icon } from '@backstage/canon';
|
||||
import { createTheme } from '@uiw/codemirror-themes';
|
||||
import { tags as t } from '@lezer/highlight';
|
||||
|
||||
|
||||
@@ -37,7 +37,9 @@
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 12px 0 16px;
|
||||
transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out;
|
||||
transition:
|
||||
background-color 0.2s ease-in-out,
|
||||
border-color 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.headerLeft {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable @next/next/no-css-tags */
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { Icon, Text } from '../../../../packages/canon';
|
||||
import { Icon, Text } from '@backstage/canon';
|
||||
import styles from './styles.module.css';
|
||||
|
||||
interface BaseUIProps {
|
||||
|
||||
@@ -1,22 +1,7 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
'use client';
|
||||
|
||||
import { Text, Icon, icons } from '../../../../packages/canon';
|
||||
import type { IconNames } from '../../../../packages/canon';
|
||||
import { Text, Icon, icons } from '@backstage/canon';
|
||||
import type { IconNames } from '@backstage/canon';
|
||||
import styles from './styles.module.css';
|
||||
|
||||
export const IconLibrary = () => {
|
||||
|
||||
@@ -1,16 +1 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { IconLibrary } from './IconLibrary';
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 80px;
|
||||
border: 1px solid #d3d3d3;
|
||||
border-radius: 0.5rem;
|
||||
background-color: var(--bg);
|
||||
border: 1px solid var(--border);
|
||||
background-color: var(--panel);
|
||||
transition: background-color 0.2s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--panel);
|
||||
background-color: var(--surface-1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +1,26 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
.layoutComponents {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 2rem;
|
||||
|
||||
& svg rect {
|
||||
transition: fill 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
& .box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: calc(33.33% - 0.67rem);
|
||||
width: calc(50% - 0.5rem);
|
||||
margin-bottom: 1rem;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
& .content {
|
||||
flex: none;
|
||||
background-color: #fff;
|
||||
background-color: var(--panel);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
height: 180px;
|
||||
@@ -53,6 +43,6 @@
|
||||
|
||||
& .description {
|
||||
font-size: 16px;
|
||||
color: #9e9e9e;
|
||||
color: var(--secondary);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { BoxSvg } from './svgs/box';
|
||||
import { FlexSvg } from './svgs/flex';
|
||||
import { GridSvg } from './svgs/grid';
|
||||
import { InlineSvg } from './svgs/inline';
|
||||
import { ContainerSvg } from './svgs/container';
|
||||
import styles from './LayoutComponents.module.css';
|
||||
import Link from 'next/link';
|
||||
@@ -36,15 +35,6 @@ export const LayoutComponents = () => {
|
||||
Arrange your components in a grid
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.box}>
|
||||
<Link className={styles.content} href="/components/inline">
|
||||
<InlineSvg />
|
||||
</Link>
|
||||
<div className={styles.title}>Inline</div>
|
||||
<div className={styles.description}>
|
||||
Arrange your components in a row
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.box}>
|
||||
<Link className={styles.content} href="/components/container">
|
||||
<ContainerSvg />
|
||||
|
||||
@@ -1,16 +1 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { LayoutComponents } from './LayoutComponents';
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export const BoxSvg = () => {
|
||||
return (
|
||||
<svg
|
||||
@@ -22,7 +7,7 @@ export const BoxSvg = () => {
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect width="100" height="60" rx="4" fill="black" fillOpacity="0.06" />
|
||||
<rect width="100" height="60" rx="4" fill="var(--surface-1)" />
|
||||
<path
|
||||
d="M94.5 0.5H96C97.933 0.5 99.5 2.067 99.5 4V5.5"
|
||||
stroke="#4765FF"
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export const ContainerSvg = () => {
|
||||
return (
|
||||
<svg
|
||||
@@ -178,8 +163,7 @@ export const ContainerSvg = () => {
|
||||
width="100"
|
||||
height="60"
|
||||
rx="4"
|
||||
fill="black"
|
||||
fillOpacity="0.06"
|
||||
fill="var(--surface-1)"
|
||||
/>
|
||||
<mask
|
||||
id="mask1_1922_1559"
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export const FlexSvg = () => {
|
||||
return (
|
||||
<svg
|
||||
@@ -22,7 +7,7 @@ export const FlexSvg = () => {
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect width="100" height="24" rx="4" fill="black" fillOpacity="0.06" />
|
||||
<rect width="100" height="24" rx="4" fill="var(--surface-1)" />
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
@@ -41,14 +26,7 @@ export const FlexSvg = () => {
|
||||
d="M44 36C43.7239 36 43.5 35.7761 43.5 35.5V35.5C43.5 35.2239 43.7239 35 44 35L56 35C56.2761 35 56.5 35.2239 56.5 35.5V35.5C56.5 35.7761 56.2761 36 56 36L44 36Z"
|
||||
fill="#4765FF"
|
||||
/>
|
||||
<rect
|
||||
y="36"
|
||||
width="100"
|
||||
height="24"
|
||||
rx="4"
|
||||
fill="black"
|
||||
fillOpacity="0.06"
|
||||
/>
|
||||
<rect y="36" width="100" height="24" rx="4" fill="var(--surface-1)" />
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
@@ -67,14 +45,7 @@ export const FlexSvg = () => {
|
||||
d="M44 72C43.7239 72 43.5 71.7761 43.5 71.5V71.5C43.5 71.2239 43.7239 71 44 71L56 71C56.2761 71 56.5 71.2239 56.5 71.5V71.5C56.5 71.7761 56.2761 72 56 72L44 72Z"
|
||||
fill="#4765FF"
|
||||
/>
|
||||
<rect
|
||||
y="72"
|
||||
width="100"
|
||||
height="24"
|
||||
rx="4"
|
||||
fill="black"
|
||||
fillOpacity="0.06"
|
||||
/>
|
||||
<rect y="72" width="100" height="24" rx="4" fill="var(--surface-1)" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export const GridSvg = () => {
|
||||
return (
|
||||
<svg
|
||||
@@ -22,14 +7,7 @@ export const GridSvg = () => {
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect
|
||||
x="0.5"
|
||||
width="52"
|
||||
height="61"
|
||||
rx="4"
|
||||
fill="black"
|
||||
fillOpacity="0.06"
|
||||
/>
|
||||
<rect x="0.5" width="52" height="61" rx="4" fill="var(--surface-1)" />
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
@@ -54,8 +32,7 @@ export const GridSvg = () => {
|
||||
width="100"
|
||||
height="24"
|
||||
rx="4"
|
||||
fill="black"
|
||||
fillOpacity="0.06"
|
||||
fill="var(--surface-1)"
|
||||
/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
@@ -81,8 +58,7 @@ export const GridSvg = () => {
|
||||
width="100"
|
||||
height="24"
|
||||
rx="4"
|
||||
fill="black"
|
||||
fillOpacity="0.06"
|
||||
fill="var(--surface-1)"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export const InlineSvg = () => {
|
||||
return (
|
||||
<svg
|
||||
width="159"
|
||||
height="56"
|
||||
viewBox="0 0 159 56"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect width="24" height="24" rx="4" fill="black" fillOpacity="0.06" />
|
||||
<rect
|
||||
x="32"
|
||||
width="24"
|
||||
height="24"
|
||||
rx="4"
|
||||
fill="black"
|
||||
fillOpacity="0.06"
|
||||
/>
|
||||
<rect
|
||||
x="64"
|
||||
width="24"
|
||||
height="24"
|
||||
rx="4"
|
||||
fill="black"
|
||||
fillOpacity="0.06"
|
||||
/>
|
||||
<rect
|
||||
x="96"
|
||||
width="24"
|
||||
height="24"
|
||||
rx="4"
|
||||
fill="black"
|
||||
fillOpacity="0.06"
|
||||
/>
|
||||
<rect
|
||||
x="128"
|
||||
width="24"
|
||||
height="24"
|
||||
rx="4"
|
||||
fill="black"
|
||||
fillOpacity="0.06"
|
||||
/>
|
||||
<rect
|
||||
y="32"
|
||||
width="24"
|
||||
height="24"
|
||||
rx="4"
|
||||
fill="black"
|
||||
fillOpacity="0.06"
|
||||
/>
|
||||
<rect
|
||||
x="32"
|
||||
y="32"
|
||||
width="24"
|
||||
height="24"
|
||||
rx="4"
|
||||
fill="black"
|
||||
fillOpacity="0.06"
|
||||
/>
|
||||
<rect
|
||||
x="64"
|
||||
y="32"
|
||||
width="24"
|
||||
height="24"
|
||||
rx="4"
|
||||
fill="black"
|
||||
fillOpacity="0.06"
|
||||
/>
|
||||
<path
|
||||
d="M12 12H138.811C141.238 12 141.569 15.5106 139.185 15.9647L12.8145 40.0353C10.4306 40.4894 10.762 44 13.1888 44H77"
|
||||
stroke="#4765FF"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import * as Table from '../Table';
|
||||
import { Chip } from '../Chip';
|
||||
import { icons } from '../../../../packages/canon';
|
||||
import { icons } from '@backstage/canon';
|
||||
|
||||
// Define a more specific type for the data object
|
||||
type PropData = {
|
||||
@@ -53,6 +53,12 @@ export const PropsTable = <T extends Record<string, PropData>>({
|
||||
{data[n].type === 'number' && <Chip>number</Chip>}
|
||||
{data[n].type === 'boolean' && <Chip>boolean</Chip>}
|
||||
{data[n].type === 'enum' && enumValues}
|
||||
{data[n].type === 'spacing' && (
|
||||
<>
|
||||
<Chip>0.5, 1, 1.5, 2, 3, ..., 14</Chip>
|
||||
<Chip>string</Chip>
|
||||
</>
|
||||
)}
|
||||
{data[n].type === 'enum | string' && (
|
||||
<>
|
||||
{enumValues}
|
||||
|
||||
@@ -1,16 +1 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { PropsTable } from './PropsTable';
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { RoadmapItem } from './list';
|
||||
|
||||
export const Roadmap = ({ list }: { list: RoadmapItem[] }) => {
|
||||
|
||||
@@ -1,16 +1 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { Roadmap } from './Roadmap';
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export type RoadmapItem = {
|
||||
title: string;
|
||||
status: 'notStarted' | 'inProgress' | 'inReview' | 'completed';
|
||||
|
||||
@@ -14,7 +14,10 @@
|
||||
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.025);
|
||||
color: var(--primary);
|
||||
background-color: var(--panel);
|
||||
transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
|
||||
border: 1px solid var(--border);
|
||||
transition:
|
||||
background-color 0.2s ease-in-out,
|
||||
color 0.2s ease-in-out;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
@@ -76,12 +79,12 @@
|
||||
transition: background-color 0.2s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--bg);
|
||||
background-color: var(--surface-1);
|
||||
}
|
||||
}
|
||||
|
||||
.line.active {
|
||||
background-color: var(--bg);
|
||||
background-color: var(--surface-1);
|
||||
}
|
||||
|
||||
.line.active .lineTitle {
|
||||
@@ -89,13 +92,13 @@
|
||||
}
|
||||
|
||||
.lineTitle {
|
||||
font-size: var(--canon-font-size-3);
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: var(--secondary);
|
||||
}
|
||||
|
||||
.lineStatus {
|
||||
font-size: var(--canon-font-size-3);
|
||||
font-size: 14px;
|
||||
color: var(--secondary);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { components } from '@/utils/data';
|
||||
import { Checkbox } from '../../../../packages/canon';
|
||||
import { Checkbox } from '@backstage/canon';
|
||||
import { motion } from 'motion/react';
|
||||
import styles from './Sidebar.module.css';
|
||||
import { usePathname } from 'next/navigation';
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
'use client';
|
||||
|
||||
import { CSSProperties, useState } from 'react';
|
||||
import { Collapsible } from '@base-ui-components/react/collapsible';
|
||||
import styles from './styles.module.css';
|
||||
|
||||
interface SnippetProps {
|
||||
preview: JSX.Element;
|
||||
codeContent: JSX.Element;
|
||||
align?: 'left' | 'center';
|
||||
px?: number;
|
||||
py?: number;
|
||||
open?: boolean;
|
||||
height?: CSSProperties['height'];
|
||||
}
|
||||
|
||||
export const SnippetClient = ({
|
||||
preview,
|
||||
codeContent,
|
||||
align = 'left',
|
||||
px = 2,
|
||||
py = 2,
|
||||
open = false,
|
||||
height = 'auto',
|
||||
}: SnippetProps) => {
|
||||
const [isOpen, setIsOpen] = useState(open);
|
||||
|
||||
return (
|
||||
<Collapsible.Root
|
||||
className={styles.container}
|
||||
defaultOpen={open}
|
||||
open={isOpen}
|
||||
onOpenChange={setIsOpen}
|
||||
>
|
||||
<div className={styles.preview} style={{ height }}>
|
||||
<div
|
||||
className={`${styles.previewContent} ${styles[align]}`}
|
||||
style={{ padding: `${py}rem ${px}rem` }}
|
||||
>
|
||||
{preview}
|
||||
</div>
|
||||
<Collapsible.Trigger className={styles.trigger}>
|
||||
{isOpen ? 'Hide code' : 'View code'}
|
||||
</Collapsible.Trigger>
|
||||
</div>
|
||||
<Collapsible.Panel className={styles.panel}>
|
||||
{codeContent}
|
||||
</Collapsible.Panel>
|
||||
</Collapsible.Root>
|
||||
);
|
||||
};
|
||||
@@ -1,10 +1,9 @@
|
||||
import { ReactNode, CSSProperties } from 'react';
|
||||
import { CSSProperties } from 'react';
|
||||
import { CodeBlock } from '../CodeBlock';
|
||||
import { Collapsible } from '@base-ui-components/react/collapsible';
|
||||
import styles from './styles.module.css';
|
||||
import { SnippetClient } from './client';
|
||||
|
||||
interface SnippetProps {
|
||||
preview: ReactNode;
|
||||
preview: JSX.Element;
|
||||
code: string;
|
||||
align?: 'left' | 'center';
|
||||
px?: number;
|
||||
@@ -23,21 +22,14 @@ export const Snippet = ({
|
||||
height = 'auto',
|
||||
}: SnippetProps) => {
|
||||
return (
|
||||
<Collapsible.Root className={styles.container} defaultOpen={open}>
|
||||
<div className={styles.preview} style={{ height }}>
|
||||
<div
|
||||
className={`${styles.previewContent} ${styles[align]}`}
|
||||
style={{ padding: `${py}rem ${px}rem` }}
|
||||
>
|
||||
{preview}
|
||||
</div>
|
||||
<Collapsible.Trigger className={styles.trigger}>
|
||||
View code
|
||||
</Collapsible.Trigger>
|
||||
</div>
|
||||
<Collapsible.Panel className={styles.panel}>
|
||||
<CodeBlock code={code} />
|
||||
</Collapsible.Panel>
|
||||
</Collapsible.Root>
|
||||
<SnippetClient
|
||||
preview={preview}
|
||||
codeContent={<CodeBlock code={code} />}
|
||||
align={align}
|
||||
px={px}
|
||||
py={py}
|
||||
open={open}
|
||||
height={height}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
[data-theme='dark'] .previewContent {
|
||||
background-image: radial-gradient(
|
||||
rgba(255, 255, 255, 0.14) 1px,
|
||||
rgba(255, 255, 255, 0.18) 1px,
|
||||
transparent 0
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,16 +1 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { Root, Header, Body, Row, Cell, HeaderRow, HeaderCell } from './Table';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { Tabs as TabsPrimitive } from '@base-ui-components/react/tabs';
|
||||
import { Text } from '../../../../packages/canon';
|
||||
import { Text } from '@backstage/canon';
|
||||
import styles from './styles.module.css';
|
||||
|
||||
export const Root = ({
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
width: 142px;
|
||||
border-radius: 0.375rem;
|
||||
background-color: var(--bg);
|
||||
transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
|
||||
transition:
|
||||
background-color 0.2s ease-in-out,
|
||||
color 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.list {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
padding: 0 var(--canon-space-6);
|
||||
transition: background-color 0.2s ease-in-out;
|
||||
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.025);
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.actions {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
color: var(--color-gray-900);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
background-color: var(--bg);
|
||||
background-color: var(--surface-1);
|
||||
transition: background-color 0.2s ease-in-out;
|
||||
|
||||
&:focus-visible {
|
||||
@@ -48,7 +48,9 @@
|
||||
border: 1px solid var(--border);
|
||||
padding-inline: 0.25rem;
|
||||
transform-origin: var(--transform-origin);
|
||||
transition: transform 150ms, opacity 150ms;
|
||||
transition:
|
||||
transform 150ms,
|
||||
opacity 150ms;
|
||||
|
||||
&[data-starting-style],
|
||||
&[data-ending-style] {
|
||||
@@ -64,7 +66,8 @@
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
outline: 1px solid var(--color-gray-200);
|
||||
box-shadow: 0px 10px 15px -3px var(--color-gray-200),
|
||||
box-shadow:
|
||||
0px 10px 15px -3px var(--color-gray-200),
|
||||
0px 4px 6px -4px var(--color-gray-200);
|
||||
}
|
||||
|
||||
@@ -134,4 +137,5 @@
|
||||
|
||||
.ItemText {
|
||||
grid-column-start: 2;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
.tabs {
|
||||
border-radius: 0.375rem;
|
||||
width: 100%;
|
||||
background-color: var(--bg);
|
||||
transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
|
||||
background-color: var(--surface-1);
|
||||
transition:
|
||||
background-color 0.2s ease-in-out,
|
||||
color 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.tabsTheme {
|
||||
width: 100px;
|
||||
border-radius: 0.375rem;
|
||||
background-color: var(--bg);
|
||||
transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
|
||||
background-color: var(--surface-1);
|
||||
transition:
|
||||
background-color 0.2s ease-in-out,
|
||||
color 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.list {
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import { AvatarSnippet } from '@/snippets/stories-snippets';
|
||||
import {
|
||||
avatarPropDefs,
|
||||
snippetUsage,
|
||||
snippetSizes,
|
||||
snippetFallback,
|
||||
} from './avatar.props';
|
||||
import { ComponentInfos } from '@/components/ComponentInfos';
|
||||
|
||||
# Avatar
|
||||
|
||||
An avatar component with a fallback for initials.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
preview={<AvatarSnippet story="Default" />}
|
||||
code={`<Avatar src="https://avatars.githubusercontent.com/u/1540635?v=4" name="Charles de Dreuille" />`}
|
||||
/>
|
||||
|
||||
<ComponentInfos
|
||||
component="avatar"
|
||||
usageCode={snippetUsage}
|
||||
classNames={[
|
||||
'canon-AvatarRoot',
|
||||
'canon-AvatarRoot[data-size="small"]',
|
||||
'canon-AvatarRoot[data-size="medium"]',
|
||||
'canon-AvatarRoot[data-size="large"]',
|
||||
'canon-AvatarImage',
|
||||
'canon-AvatarFallback',
|
||||
]}
|
||||
/>
|
||||
|
||||
## API reference
|
||||
|
||||
<PropsTable data={avatarPropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
### Sizes
|
||||
|
||||
Avatar sizes can be set using the `size` prop.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<AvatarSnippet story="Sizes" />}
|
||||
code={snippetSizes}
|
||||
/>
|
||||
|
||||
### Fallback
|
||||
|
||||
If the image is not available, the avatar will show the initials of the name.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<AvatarSnippet story="Fallback" />}
|
||||
code={snippetFallback}
|
||||
/>
|
||||
@@ -0,0 +1,46 @@
|
||||
import { classNamePropDefs, stylePropDefs } from '@/utils/propDefs';
|
||||
import type { PropDef } from '@/utils/propDefs';
|
||||
|
||||
export const avatarPropDefs: Record<string, PropDef> = {
|
||||
src: {
|
||||
type: 'string',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
},
|
||||
size: {
|
||||
type: 'enum',
|
||||
values: ['small', 'medium', 'large'],
|
||||
default: 'medium',
|
||||
responsive: true,
|
||||
},
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const snippetUsage = `import { Avatar } from '@backstage/canon';
|
||||
|
||||
<Avatar
|
||||
src="https://avatars.githubusercontent.com/u/1540635?v=4"
|
||||
name="Charles de Dreuille"
|
||||
/>`;
|
||||
|
||||
export const snippetSizes = `<Flex gap="4" direction="column">
|
||||
<Avatar
|
||||
src="https://avatars.githubusercontent.com/u/1540635?v=4"
|
||||
name="Charles de Dreuille" size="small"
|
||||
/>
|
||||
<Avatar
|
||||
src="https://avatars.githubusercontent.com/u/1540635?v=4"
|
||||
name="Charles de Dreuille" size="medium"
|
||||
/>
|
||||
<Avatar
|
||||
src="https://avatars.githubusercontent.com/u/1540635?v=4"
|
||||
name="Charles de Dreuille" size="large"
|
||||
/>
|
||||
</Flex>`;
|
||||
|
||||
export const snippetFallback = `<Avatar
|
||||
src="https://avatars.githubusercontent.com/u/15406AAAAAAAAA"
|
||||
name="Charles de Dreuille"
|
||||
/>`;
|
||||
+13
-24
@@ -1,10 +1,16 @@
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { Tabs } from '@/components/Tabs';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { BoxSnippet } from '@/snippets/stories-snippets';
|
||||
import { boxPropDefs } from './props';
|
||||
import { spacingPropDefs } from '../../../../utils/propDefs';
|
||||
import {
|
||||
boxPropDefs,
|
||||
snippetUsage,
|
||||
boxPreviewSnippet,
|
||||
boxSimpleSnippet,
|
||||
boxResponsiveSnippet,
|
||||
} from './box.props';
|
||||
import { spacingPropDefs } from '@/utils/propDefs';
|
||||
import { ComponentInfos } from '@/components/ComponentInfos';
|
||||
|
||||
# Box
|
||||
|
||||
@@ -13,22 +19,11 @@ Box is the lowest-level component in Canon. It provides a consistent API for sty
|
||||
<Snippet
|
||||
py={4}
|
||||
preview={<BoxSnippet story="Preview" />}
|
||||
code={`<Box>
|
||||
<DecorativeBox />
|
||||
</Box>`}
|
||||
code={boxPreviewSnippet}
|
||||
align="center"
|
||||
/>
|
||||
|
||||
<Tabs.Root>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab>Usage</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
<Tabs.Panel>
|
||||
<CodeBlock code={`import { Box } from "@backstage/canon";
|
||||
|
||||
<Box />`} />
|
||||
</Tabs.Panel>
|
||||
</Tabs.Root>
|
||||
<ComponentInfos component="box" usageCode={snippetUsage} />
|
||||
|
||||
## API reference
|
||||
|
||||
@@ -51,16 +46,10 @@ avoid collapsing margins but both are available.
|
||||
|
||||
A simple example of how to use the Box component.
|
||||
|
||||
<CodeBlock code={`<Box padding="md" borderRadius="md">Hello World</Box>`} />
|
||||
<CodeBlock code={boxSimpleSnippet} />
|
||||
|
||||
### Responsive
|
||||
|
||||
Here's a view when buttons are responsive.
|
||||
|
||||
<CodeBlock
|
||||
code={`<Box
|
||||
padding={{ xs: 'sm', md: 'md' }}
|
||||
borderRadius={{ xs: 'sm', md: 'md' }}>
|
||||
Hello World
|
||||
</Box>`}
|
||||
/>
|
||||
<CodeBlock code={boxResponsiveSnippet} />
|
||||
@@ -0,0 +1,40 @@
|
||||
import {
|
||||
classNamePropDefs,
|
||||
displayPropDefs,
|
||||
heightPropDefs,
|
||||
positionPropDefs,
|
||||
stylePropDefs,
|
||||
widthPropDefs,
|
||||
type PropDef,
|
||||
} from '@/utils/propDefs';
|
||||
|
||||
export const boxPropDefs: Record<string, PropDef> = {
|
||||
as: {
|
||||
type: 'enum',
|
||||
values: ['div', 'span'],
|
||||
default: 'div',
|
||||
responsive: true,
|
||||
},
|
||||
...widthPropDefs,
|
||||
...heightPropDefs,
|
||||
...positionPropDefs,
|
||||
...displayPropDefs,
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const snippetUsage = `import { Box } from '@backstage/canon';
|
||||
|
||||
<Box />`;
|
||||
|
||||
export const boxPreviewSnippet = `<Box>
|
||||
<DecorativeBox />
|
||||
</Box>`;
|
||||
|
||||
export const boxSimpleSnippet = `<Box padding="md" borderRadius="md">Hello World</Box>`;
|
||||
|
||||
export const boxResponsiveSnippet = `<Box
|
||||
padding={{ xs: 'sm', md: 'md' }}
|
||||
borderRadius={{ xs: 'sm', md: 'md' }}>
|
||||
Hello World
|
||||
</Box>`;
|
||||
@@ -0,0 +1,104 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import { ButtonSnippet } from '@/snippets/stories-snippets';
|
||||
import {
|
||||
buttonPropDefs,
|
||||
buttonSnippetUsage,
|
||||
buttonVariantsSnippet,
|
||||
buttonSizesSnippet,
|
||||
buttonIconsSnippet,
|
||||
buttonFullWidthSnippet,
|
||||
buttonDisabledSnippet,
|
||||
buttonResponsiveSnippet,
|
||||
} from './button.props';
|
||||
import { ComponentInfos } from '@/components/ComponentInfos';
|
||||
|
||||
# Button
|
||||
|
||||
A button component that can be used to trigger actions.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
preview={<ButtonSnippet story="Variants" />}
|
||||
code={buttonVariantsSnippet}
|
||||
/>
|
||||
|
||||
<ComponentInfos
|
||||
component="button"
|
||||
classNames={['canon-Button', 'canon-ButtonIcon']}
|
||||
usageCode={buttonSnippetUsage}
|
||||
/>
|
||||
|
||||
## API reference
|
||||
|
||||
<PropsTable data={buttonPropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
### Variants
|
||||
|
||||
Here's a view when buttons have different variants.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<ButtonSnippet story="Variants" />}
|
||||
code={buttonVariantsSnippet}
|
||||
/>
|
||||
|
||||
### Sizes
|
||||
|
||||
Here's a view when buttons have different sizes.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<ButtonSnippet story="Sizes" />}
|
||||
code={buttonSizesSnippet}
|
||||
/>
|
||||
|
||||
### With Icons
|
||||
|
||||
Here's a view when buttons have icons.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<ButtonSnippet story="WithIcons" />}
|
||||
code={buttonIconsSnippet}
|
||||
/>
|
||||
|
||||
### Full width
|
||||
|
||||
Here's a view when buttons are full width.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<ButtonSnippet story="FullWidth" />}
|
||||
code={buttonFullWidthSnippet}
|
||||
/>
|
||||
|
||||
### Disabled
|
||||
|
||||
Here's a view when buttons are disabled.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<ButtonSnippet story="Disabled" />}
|
||||
code={buttonDisabledSnippet}
|
||||
/>
|
||||
|
||||
### Responsive
|
||||
|
||||
Here's a view when buttons are responsive.
|
||||
|
||||
<CodeBlock code={buttonResponsiveSnippet} />
|
||||
@@ -0,0 +1,63 @@
|
||||
import { classNamePropDefs, stylePropDefs } from '../../utils/propDefs';
|
||||
import type { PropDef } from '../../utils/propDefs';
|
||||
|
||||
export const buttonPropDefs: Record<string, PropDef> = {
|
||||
variant: {
|
||||
type: 'enum',
|
||||
values: ['primary', 'secondary'],
|
||||
default: 'primary',
|
||||
responsive: true,
|
||||
},
|
||||
size: {
|
||||
type: 'enum',
|
||||
values: ['small', 'medium'],
|
||||
default: 'medium',
|
||||
responsive: true,
|
||||
},
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const buttonSnippetUsage = `import { Button } from '@backstage/canon';
|
||||
|
||||
<Button />`;
|
||||
|
||||
export const buttonVariantsSnippet = `<Flex align="center">
|
||||
<Button iconStart="cloud" variant="primary">
|
||||
Button
|
||||
</Button>
|
||||
<Button iconStart="cloud" variant="secondary">
|
||||
Button
|
||||
</Button>
|
||||
<Button iconStart="cloud" variant="tertiary">
|
||||
Button
|
||||
</Button>
|
||||
</Flex>`;
|
||||
|
||||
export const buttonSizesSnippet = `<Flex align="center">
|
||||
<Button size="small">Small</Button>
|
||||
<Button size="medium">Medium</Button>
|
||||
</Flex>`;
|
||||
|
||||
export const buttonIconsSnippet = `<Flex align="center">
|
||||
<Button iconStart="cloud">Button</Button>
|
||||
<Button iconEnd="chevronRight">Button</Button>
|
||||
<Button iconStart="cloud" iconEnd="chevronRight">Button</Button>
|
||||
</Flex>`;
|
||||
|
||||
export const buttonFullWidthSnippet = `<Flex direction="column" gap="4" style={{ width: '300px' }}>
|
||||
<Button fullWidth>Full width</Button>
|
||||
</Flex>`;
|
||||
|
||||
export const buttonDisabledSnippet = `<Flex gap="4">
|
||||
<Button variant="primary" disabled>
|
||||
Primary
|
||||
</Button>
|
||||
<Button variant="secondary" disabled>
|
||||
Secondary
|
||||
</Button>
|
||||
</Flex>`;
|
||||
|
||||
export const buttonResponsiveSnippet = `<Button variant={{ initial: 'primary', lg: 'secondary' }}>
|
||||
Responsive Button
|
||||
</Button>`;
|
||||
@@ -0,0 +1,46 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { CheckboxSnippet } from '@/snippets/stories-snippets';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import {
|
||||
checkboxPropDefs,
|
||||
checkboxUsageSnippet,
|
||||
checkboxDefaultSnippet,
|
||||
checkboxVariantsSnippet,
|
||||
} from './checkbox.props';
|
||||
import { ComponentInfos } from '@/components/ComponentInfos';
|
||||
|
||||
# Checkbox
|
||||
|
||||
A checkbox component that can be used to trigger actions.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
preview={<CheckboxSnippet story="Default" />}
|
||||
code={checkboxDefaultSnippet}
|
||||
/>
|
||||
|
||||
<ComponentInfos
|
||||
component="checkbox"
|
||||
classNames={['canon-Checkbox']}
|
||||
usageCode={checkboxUsageSnippet}
|
||||
/>
|
||||
|
||||
## API reference
|
||||
|
||||
<PropsTable data={checkboxPropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
### All variants
|
||||
|
||||
Here's a view when checkboxes have different variants.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<CheckboxSnippet story="AllVariants" />}
|
||||
code={checkboxVariantsSnippet}
|
||||
/>
|
||||
+18
-2
@@ -1,5 +1,8 @@
|
||||
import { classNamePropDefs, stylePropDefs } from '../../../../utils/propDefs';
|
||||
import type { PropDef } from '../../../../utils/propDefs';
|
||||
import {
|
||||
classNamePropDefs,
|
||||
stylePropDefs,
|
||||
type PropDef,
|
||||
} from '@/utils/propDefs';
|
||||
|
||||
export const checkboxPropDefs: Record<string, PropDef> = {
|
||||
label: {
|
||||
@@ -42,3 +45,16 @@ export const checkboxPropDefs: Record<string, PropDef> = {
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const checkboxUsageSnippet = `import { Checkbox } from '@backstage/canon';
|
||||
|
||||
<Checkbox />`;
|
||||
|
||||
export const checkboxDefaultSnippet = `<Checkbox label="Accept terms and conditions" />`;
|
||||
|
||||
export const checkboxVariantsSnippet = `<Inline alignY="center">
|
||||
<Checkbox />
|
||||
<Checkbox checked />
|
||||
<Checkbox label="Checkbox" />
|
||||
<Checkbox label="Checkbox" checked />
|
||||
</Inline>`;
|
||||
@@ -0,0 +1,71 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import { CollapsibleSnippet } from '@/snippets/stories-snippets';
|
||||
import {
|
||||
collapsibleRootPropDefs,
|
||||
collapsibleTriggerPropDefs,
|
||||
collapsiblePanelPropDefs,
|
||||
collapsibleUsageSnippet,
|
||||
collapsibleDefaultSnippet,
|
||||
collapsibleTriggerSnippet,
|
||||
collapsibleOpenSnippet,
|
||||
} from './collapsible.props';
|
||||
import { ComponentInfos } from '@/components/ComponentInfos';
|
||||
|
||||
# Collapsible
|
||||
|
||||
An avatar component with a fallback for initials.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
height={240}
|
||||
preview={<CollapsibleSnippet story="Default" />}
|
||||
code={collapsibleDefaultSnippet}
|
||||
/>
|
||||
|
||||
<ComponentInfos
|
||||
component="collapsible"
|
||||
classNames={[
|
||||
'canon-CollapsibleRoot',
|
||||
'canon-CollapsibleTrigger',
|
||||
'canon-CollapsiblePanel',
|
||||
]}
|
||||
usageCode={collapsibleUsageSnippet}
|
||||
/>
|
||||
|
||||
## API reference
|
||||
|
||||
### Collapsible.Root
|
||||
|
||||
Groups all parts of the collapsible. Renders a `<div>` element.
|
||||
|
||||
<PropsTable data={collapsibleRootPropDefs} />
|
||||
|
||||
### Collapsible.Trigger
|
||||
|
||||
The trigger by default render a simple unstyled button. Because menus can be rendered in different ways, we recommend
|
||||
using the `render` prop to render a custom trigger.
|
||||
|
||||
<CodeBlock code={collapsibleTriggerSnippet} />
|
||||
|
||||
<PropsTable data={collapsibleTriggerPropDefs} />
|
||||
|
||||
### Collapsible.Panel
|
||||
|
||||
A panel with the collapsible contents. Renders a `<div>` element.
|
||||
|
||||
<PropsTable data={collapsiblePanelPropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
Open the panel by default by setting the `defaultOpen` prop to `true`.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<CollapsibleSnippet story="Open" />}
|
||||
code={collapsibleOpenSnippet}
|
||||
/>
|
||||
@@ -0,0 +1,86 @@
|
||||
import {
|
||||
classNamePropDefs,
|
||||
stylePropDefs,
|
||||
renderPropDefs,
|
||||
type PropDef,
|
||||
} from '@/utils/propDefs';
|
||||
|
||||
export const collapsibleRootPropDefs: Record<string, PropDef> = {
|
||||
defaultOpen: {
|
||||
type: 'boolean',
|
||||
default: 'false',
|
||||
},
|
||||
open: {
|
||||
type: 'boolean',
|
||||
},
|
||||
onOpenChange: {
|
||||
type: 'enum',
|
||||
values: ['(open) => void'],
|
||||
},
|
||||
...renderPropDefs,
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const collapsibleTriggerPropDefs: Record<string, PropDef> = {
|
||||
...renderPropDefs,
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const collapsiblePanelPropDefs: Record<string, PropDef> = {
|
||||
hiddenUntilFound: {
|
||||
type: 'boolean',
|
||||
default: 'false',
|
||||
},
|
||||
keepMounted: {
|
||||
type: 'boolean',
|
||||
default: 'false',
|
||||
},
|
||||
...renderPropDefs,
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const collapsibleUsageSnippet = `import { Collapsible } from '@backstage/canon';
|
||||
|
||||
<Collapsible.Root>
|
||||
<Collapsible.Trigger render={(props, state) => (
|
||||
<Button {...props}>
|
||||
{state.open ? 'Close Panel' : 'Open Panel'}
|
||||
</Button>
|
||||
)} />
|
||||
<Collapsible.Panel>Your content</Collapsible.Panel>
|
||||
</Collapsible.Root>`;
|
||||
|
||||
export const collapsibleDefaultSnippet = `<Collapsible.Root>
|
||||
<Collapsible.Trigger render={(props, state) => (
|
||||
<Button {...props}>
|
||||
{state.open ? 'Close Panel' : 'Open Panel'}
|
||||
</Button>
|
||||
)} />
|
||||
<Collapsible.Panel>
|
||||
<Box>
|
||||
<Text>It's the edge of the world and all of Western civilization</Text>
|
||||
<Text>The sun may rise in the East, at least it settled in a final location</Text>
|
||||
<Text>It's understood that Hollywood sells Californication</Text>
|
||||
</Box>
|
||||
</Collapsible.Panel>
|
||||
</Collapsible.Root>`;
|
||||
|
||||
export const collapsibleTriggerSnippet = `<Collapsible.Trigger render={props => <Button {...props} />} />`;
|
||||
|
||||
export const collapsibleOpenSnippet = `<Collapsible.Root defaultOpen>
|
||||
<Collapsible.Trigger render={(props, state) => (
|
||||
<Button {...props}>
|
||||
{state.open ? 'Close Panel' : 'Open Panel'}
|
||||
</Button>
|
||||
)} />
|
||||
<Collapsible.Panel>
|
||||
<Box>
|
||||
<Text>It's the edge of the world and all of Western civilization</Text>
|
||||
<Text>The sun may rise in the East, at least it settled in a final location</Text>
|
||||
<Text>It's understood that Hollywood sells Californication</Text>
|
||||
</Box>
|
||||
</Collapsible.Panel>
|
||||
</Collapsible.Root>`;
|
||||
+16
-30
@@ -1,9 +1,15 @@
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { Tabs } from '@/components/Tabs';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { ContainerSnippet } from '@/snippets/stories-snippets';
|
||||
import { containerPropDefs } from './props';
|
||||
import {
|
||||
containerPropDefs,
|
||||
containerUsageSnippet,
|
||||
containerDefaultSnippet,
|
||||
containerSimpleSnippet,
|
||||
containerResponsiveSnippet,
|
||||
} from './container.props';
|
||||
import { ComponentInfos } from '@/components/ComponentInfos';
|
||||
|
||||
# Container
|
||||
|
||||
@@ -13,22 +19,14 @@ content on the page.
|
||||
<Snippet
|
||||
py={4}
|
||||
preview={<ContainerSnippet story="Preview" />}
|
||||
code={`<Container>
|
||||
<DecorativeBox />
|
||||
</Container>`}
|
||||
code={containerDefaultSnippet}
|
||||
/>
|
||||
|
||||
<Tabs.Root>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab>Usage</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
<Tabs.Panel>
|
||||
<CodeBlock code={`import { Container } from "@backstage/canon";
|
||||
|
||||
<Container>Hello World!</Container>
|
||||
`} />
|
||||
</Tabs.Panel>
|
||||
</Tabs.Root>
|
||||
<ComponentInfos
|
||||
component="container"
|
||||
classNames={['canon-Container']}
|
||||
usageCode={containerUsageSnippet}
|
||||
/>
|
||||
|
||||
## API reference
|
||||
|
||||
@@ -40,23 +38,11 @@ content on the page.
|
||||
|
||||
A simple example of how to use the Container component.
|
||||
|
||||
<CodeBlock
|
||||
code={`<Container>
|
||||
<Box>Hello World</Box>
|
||||
<Box>Hello World</Box>
|
||||
<Box>Hello World</Box>
|
||||
</Container>`}
|
||||
/>
|
||||
<CodeBlock code={containerSimpleSnippet} />
|
||||
|
||||
### Responsive padding & margin
|
||||
|
||||
The Container component also supports responsive values, making it easy to
|
||||
create responsive designs.
|
||||
|
||||
<CodeBlock
|
||||
code={`<Container paddingY={{ xs: 'sm', md: 'md' }}>
|
||||
<Box>Hello World</Box>
|
||||
<Box>Hello World</Box>
|
||||
<Box>Hello World</Box>
|
||||
</Container>`}
|
||||
/>
|
||||
<CodeBlock code={containerResponsiveSnippet} />
|
||||
@@ -0,0 +1,32 @@
|
||||
import {
|
||||
classNamePropDefs,
|
||||
stylePropDefs,
|
||||
gapPropDefs,
|
||||
type PropDef,
|
||||
} from '@/utils/propDefs';
|
||||
|
||||
export const containerPropDefs: Record<string, PropDef> = {
|
||||
...gapPropDefs,
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const containerUsageSnippet = `import { Container } from "@backstage/canon";
|
||||
|
||||
<Container>Hello World!</Container>`;
|
||||
|
||||
export const containerDefaultSnippet = `<Container>
|
||||
<DecorativeBox />
|
||||
</Container>`;
|
||||
|
||||
export const containerSimpleSnippet = `<Container>
|
||||
<Box>Hello World</Box>
|
||||
<Box>Hello World</Box>
|
||||
<Box>Hello World</Box>
|
||||
</Container>`;
|
||||
|
||||
export const containerResponsiveSnippet = `<Container paddingY={{ xs: 'sm', md: 'md' }}>
|
||||
<Box>Hello World</Box>
|
||||
<Box>Hello World</Box>
|
||||
<Box>Hello World</Box>
|
||||
</Container>`;
|
||||
@@ -0,0 +1,62 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { FlexSnippet } from '@/snippets/stories-snippets';
|
||||
import {
|
||||
flexPropDefs,
|
||||
flexUsageSnippet,
|
||||
flexDefaultSnippet,
|
||||
flexFAQ1Snippet,
|
||||
flexSimpleSnippet,
|
||||
flexResponsiveSnippet,
|
||||
flexAlignSnippet,
|
||||
} from './flex.props';
|
||||
import { spacingPropDefs } from '@/utils/propDefs';
|
||||
import { ComponentInfos } from '@/components/ComponentInfos';
|
||||
|
||||
# Flex
|
||||
|
||||
A responsive flex container component for vertical stacking with customizable gaps.
|
||||
|
||||
<Snippet
|
||||
py={4}
|
||||
align="center"
|
||||
preview={<FlexSnippet story="Default" />}
|
||||
code={flexDefaultSnippet}
|
||||
/>
|
||||
|
||||
<ComponentInfos
|
||||
component="flex"
|
||||
classNames={['canon-Flex']}
|
||||
usageCode={flexUsageSnippet}
|
||||
/>
|
||||
|
||||
## API reference
|
||||
|
||||
<PropsTable data={flexPropDefs} />
|
||||
|
||||
The grid component also accepts all the spacing props from the Box component.
|
||||
|
||||
<PropsTable data={spacingPropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
### Simple
|
||||
|
||||
A simple example of how to use the Flex component.
|
||||
|
||||
<CodeBlock code={flexSimpleSnippet} />
|
||||
|
||||
### Responsive
|
||||
|
||||
The Flex component also supports responsive values, making it easy to create
|
||||
responsive designs.
|
||||
|
||||
<CodeBlock code={flexResponsiveSnippet} />
|
||||
|
||||
### Align
|
||||
|
||||
The Flex component also supports responsive alignment, making it easy to
|
||||
create responsive designs.
|
||||
|
||||
<CodeBlock code={flexAlignSnippet} />
|
||||
@@ -0,0 +1,55 @@
|
||||
import {
|
||||
childrenPropDefs,
|
||||
classNamePropDefs,
|
||||
stylePropDefs,
|
||||
type PropDef,
|
||||
} from '@/utils/propDefs';
|
||||
|
||||
export const flexPropDefs: Record<string, PropDef> = {
|
||||
align: {
|
||||
type: 'enum',
|
||||
values: ['start', 'center', 'end', 'baseline', 'stretch'],
|
||||
responsive: true,
|
||||
},
|
||||
direction: {
|
||||
type: 'enum',
|
||||
values: ['row', 'column', 'row-reverse', 'column-reverse'],
|
||||
responsive: true,
|
||||
},
|
||||
justify: {
|
||||
type: 'enum',
|
||||
values: ['start', 'center', 'end', 'between'],
|
||||
responsive: true,
|
||||
},
|
||||
...childrenPropDefs,
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const flexUsageSnippet = `import { Flex } from '@backstage/canon';
|
||||
|
||||
<Flex />`;
|
||||
|
||||
export const flexDefaultSnippet = `<Flex>
|
||||
<DecorativeBox />
|
||||
<DecorativeBox />
|
||||
<DecorativeBox />
|
||||
</Flex>`;
|
||||
|
||||
export const flexSimpleSnippet = `<Flex gap="md">
|
||||
<Box>Hello World</Box>
|
||||
<Box>Hello World</Box>
|
||||
<Box>Hello World</Box>
|
||||
</Flex>`;
|
||||
|
||||
export const flexResponsiveSnippet = `<Flex gap={{ xs: 'xs', md: 'md' }}>
|
||||
<Box>Hello World</Box>
|
||||
<Box>Hello World</Box>
|
||||
<Box>Hello World</Box>
|
||||
</Flex>`;
|
||||
|
||||
export const flexAlignSnippet = `<Flex align={{ xs: 'start', md: 'center' }}>
|
||||
<Box>Hello World</Box>
|
||||
<Box>Hello World</Box>
|
||||
<Box>Hello World</Box>
|
||||
</Flex>`;
|
||||
+25
-70
@@ -1,11 +1,20 @@
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { Tabs } from '@/components/Tabs';
|
||||
import { grid } from '@/snippets/code-snippets';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { GridSnippet } from '@/snippets/stories-snippets';
|
||||
import { spacingPropDefs } from '../../../../utils/propDefs';
|
||||
import { gridPropDefs, gridItemPropDefs } from './props';
|
||||
import { spacingPropDefs } from '@/utils/propDefs';
|
||||
import {
|
||||
gridPropDefs,
|
||||
gridItemPropDefs,
|
||||
gridUsageSnippet,
|
||||
gridDefaultSnippet,
|
||||
gridSimpleSnippet,
|
||||
gridComplexSnippet,
|
||||
gridMixingRowsSnippet,
|
||||
gridResponsiveSnippet,
|
||||
gridStartEndSnippet,
|
||||
} from './grid.props';
|
||||
import { ComponentInfos } from '@/components/ComponentInfos';
|
||||
|
||||
# Grid
|
||||
|
||||
@@ -15,25 +24,18 @@ more complex ones.
|
||||
<Snippet
|
||||
py={4}
|
||||
preview={<GridSnippet story="Default" />}
|
||||
code={`<Grid>
|
||||
<DecorativeBox />
|
||||
<DecorativeBox />
|
||||
<DecorativeBox />
|
||||
</Grid>`}
|
||||
code={gridDefaultSnippet}
|
||||
/>
|
||||
|
||||
<Tabs.Root>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab>Usage</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
<Tabs.Panel>
|
||||
<CodeBlock code={grid} />
|
||||
</Tabs.Panel>
|
||||
</Tabs.Root>
|
||||
<ComponentInfos
|
||||
component="grid"
|
||||
classNames={['canon-Grid', 'canon-GridItem']}
|
||||
usageCode={gridUsageSnippet}
|
||||
/>
|
||||
|
||||
## API reference
|
||||
|
||||
### Grid
|
||||
### Grid.Root
|
||||
|
||||
This is the grid container component. It will help to define the number of
|
||||
columns that will be used in the grid. You can also define the gap between the
|
||||
@@ -60,31 +62,14 @@ elements directly if you prefer.
|
||||
|
||||
A simple grid with 3 columns and a gap of md.
|
||||
|
||||
<CodeBlock
|
||||
code={`<Grid columns={3} gap="md">
|
||||
<Box>Hello World</Box>
|
||||
<Box>Hello World</Box>
|
||||
<Box>Hello World</Box>
|
||||
</Grid>
|
||||
`}
|
||||
/>
|
||||
<CodeBlock code={gridSimpleSnippet} />
|
||||
|
||||
### Complex grid
|
||||
|
||||
You can also use the grid item to create more complex layouts. In this example
|
||||
the first column will span 1 column and the second column will span 2 columns.
|
||||
|
||||
<CodeBlock
|
||||
code={`<Grid columns={3} gap="md">
|
||||
<Grid.Item colSpan={1}>
|
||||
<Box>Hello World</Box>
|
||||
</Grid.Item>
|
||||
<Grid.Item colSpan={2}>
|
||||
<Box>Hello World</Box>
|
||||
</Grid.Item>
|
||||
</Grid>
|
||||
`}
|
||||
/>
|
||||
<CodeBlock code={gridComplexSnippet} />
|
||||
|
||||
### Mixing rows and columns
|
||||
|
||||
@@ -92,47 +77,17 @@ The grid item component also supports the `rowSpan` prop, which allows you to
|
||||
span multiple rows within the grid layout. In this example, the first item
|
||||
will span 2 rows to achieve a dynamic and flexible grid structure.
|
||||
|
||||
<CodeBlock
|
||||
code={`<Grid columns={3} gap="md">
|
||||
<Grid.Item colSpan={1} rowSpan={2}>
|
||||
<Box>Hello World</Box>
|
||||
</Grid.Item>
|
||||
<Grid.Item colSpan={2}>
|
||||
<Box>Hello World</Box>
|
||||
</Grid.Item>
|
||||
<Grid.Item colSpan={2}>
|
||||
<Box>Hello World</Box>
|
||||
</Grid.Item>
|
||||
</Grid>
|
||||
`}
|
||||
/>
|
||||
<CodeBlock code={gridMixingRowsSnippet} />
|
||||
|
||||
### Responsive grid
|
||||
|
||||
The grid component also supports responsive values, making it easy to create
|
||||
responsive designs.
|
||||
|
||||
<CodeBlock
|
||||
code={`<Grid columns={{ xs: 1, md: 3 }} gap={{ xs: 'xs', md: 'md' }}>
|
||||
<Grid.Item colSpan={{ xs: 1, md: 2 }}>
|
||||
<Box>Hello World</Box>
|
||||
</Grid.Item>
|
||||
<Grid.Item colSpan={{ xs: 1, md: 1 }}>
|
||||
<Box>Hello World</Box>
|
||||
</Grid.Item>
|
||||
</Grid>
|
||||
`}
|
||||
/>
|
||||
<CodeBlock code={gridResponsiveSnippet} />
|
||||
|
||||
### Start and End
|
||||
|
||||
The start and end props can be used to position the item in the grid.
|
||||
|
||||
<CodeBlock
|
||||
code={`<Grid columns={3} gap="md">
|
||||
<Grid.Item start={2} end={4}>
|
||||
<Box>Hello World</Box>
|
||||
</Grid.Item>
|
||||
</Grid>
|
||||
`}
|
||||
/>
|
||||
<CodeBlock code={gridStartEndSnippet} />
|
||||
@@ -0,0 +1,111 @@
|
||||
import {
|
||||
childrenPropDefs,
|
||||
classNamePropDefs,
|
||||
stylePropDefs,
|
||||
type PropDef,
|
||||
} from '@/utils/propDefs';
|
||||
|
||||
const columnsValues = [
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'10',
|
||||
'11',
|
||||
'12',
|
||||
];
|
||||
|
||||
export const gridPropDefs: Record<string, PropDef> = {
|
||||
columns: {
|
||||
type: 'enum | string',
|
||||
values: [...columnsValues, 'auto'],
|
||||
responsive: true,
|
||||
default: 'auto',
|
||||
},
|
||||
...childrenPropDefs,
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const gridItemPropDefs: Record<string, PropDef> = {
|
||||
colSpan: {
|
||||
type: 'enum | string',
|
||||
values: [...columnsValues, 'full'],
|
||||
responsive: true,
|
||||
},
|
||||
rowSpan: {
|
||||
type: 'enum | string',
|
||||
values: [...columnsValues, 'full'],
|
||||
responsive: true,
|
||||
},
|
||||
start: {
|
||||
type: 'enum | string',
|
||||
values: [...columnsValues, 'auto'],
|
||||
responsive: true,
|
||||
},
|
||||
end: {
|
||||
type: 'enum | string',
|
||||
values: [...columnsValues, 'auto'],
|
||||
responsive: true,
|
||||
},
|
||||
...childrenPropDefs,
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const gridUsageSnippet = `import { Grid } from '@backstage/canon';
|
||||
|
||||
<Grid />`;
|
||||
|
||||
export const gridDefaultSnippet = `<Grid.Root>
|
||||
<DecorativeBox />
|
||||
<DecorativeBox />
|
||||
<DecorativeBox />
|
||||
</Grid.Root>`;
|
||||
|
||||
export const gridSimpleSnippet = `<Grid columns={3} gap="md">
|
||||
<Box>Hello World</Box>
|
||||
<Box>Hello World</Box>
|
||||
<Box>Hello World</Box>
|
||||
</Grid>`;
|
||||
|
||||
export const gridComplexSnippet = `<Grid columns={3} gap="md">
|
||||
<Grid.Item colSpan={1}>
|
||||
<Box>Hello World</Box>
|
||||
</Grid.Item>
|
||||
<Grid.Item colSpan={2}>
|
||||
<Box>Hello World</Box>
|
||||
</Grid.Item>
|
||||
</Grid>`;
|
||||
|
||||
export const gridMixingRowsSnippet = `<Grid columns={3} gap="md">
|
||||
<Grid.Item colSpan={1} rowSpan={2}>
|
||||
<Box>Hello World</Box>
|
||||
</Grid.Item>
|
||||
<Grid.Item colSpan={2}>
|
||||
<Box>Hello World</Box>
|
||||
</Grid.Item>
|
||||
<Grid.Item colSpan={2}>
|
||||
<Box>Hello World</Box>
|
||||
</Grid.Item>
|
||||
</Grid>`;
|
||||
|
||||
export const gridResponsiveSnippet = `<Grid columns={{ xs: 1, md: 3 }} gap={{ xs: 'xs', md: 'md' }}>
|
||||
<Grid.Item colSpan={{ xs: 1, md: 2 }}>
|
||||
<Box>Hello World</Box>
|
||||
</Grid.Item>
|
||||
<Grid.Item colSpan={{ xs: 1, md: 1 }}>
|
||||
<Box>Hello World</Box>
|
||||
</Grid.Item>
|
||||
</Grid>`;
|
||||
|
||||
export const gridStartEndSnippet = `<Grid columns={3} gap="md">
|
||||
<Grid.Item start={2} end={4}>
|
||||
<Box>Hello World</Box>
|
||||
</Grid.Item>
|
||||
</Grid>`;
|
||||
@@ -0,0 +1,66 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { HeadingSnippet } from '@/snippets/stories-snippets';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import {
|
||||
headingPropDefs,
|
||||
headingUsageSnippet,
|
||||
headingDefaultSnippet,
|
||||
headingVariantsSnippet,
|
||||
headingTruncateSnippet,
|
||||
headingResponsiveSnippet,
|
||||
} from './heading.props';
|
||||
import { ComponentInfos } from '@/components/ComponentInfos';
|
||||
|
||||
# Heading
|
||||
|
||||
Headings are used to structure the content of your page.
|
||||
|
||||
<Snippet
|
||||
py={4}
|
||||
preview={<HeadingSnippet story="Title1" />}
|
||||
code={headingDefaultSnippet}
|
||||
/>
|
||||
|
||||
<ComponentInfos
|
||||
component="heading"
|
||||
classNames={['canon-Heading']}
|
||||
usageCode={headingUsageSnippet}
|
||||
/>
|
||||
|
||||
## API reference
|
||||
|
||||
<PropsTable data={headingPropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
### All variants
|
||||
|
||||
The `Heading` component has a `variant` prop that can be used to change the
|
||||
appearance of the heading.
|
||||
|
||||
<Snippet
|
||||
py={2}
|
||||
open
|
||||
preview={<HeadingSnippet story="AllVariants" />}
|
||||
code={headingVariantsSnippet}
|
||||
/>
|
||||
|
||||
### Truncate
|
||||
|
||||
The `Heading` component has a `truncate` prop that can be used to truncate the
|
||||
heading.
|
||||
|
||||
<Snippet
|
||||
py={2}
|
||||
open
|
||||
preview={<HeadingSnippet story="Truncate" />}
|
||||
code={headingTruncateSnippet}
|
||||
/>
|
||||
|
||||
### Responsive
|
||||
|
||||
You can also use the `variant` prop to change the appearance of the text based
|
||||
on the screen size.
|
||||
|
||||
<CodeBlock code={headingResponsiveSnippet} />
|
||||
@@ -0,0 +1,48 @@
|
||||
import {
|
||||
classNamePropDefs,
|
||||
stylePropDefs,
|
||||
type PropDef,
|
||||
} from '@/utils/propDefs';
|
||||
|
||||
export const headingPropDefs: Record<string, PropDef> = {
|
||||
variant: {
|
||||
type: 'enum',
|
||||
values: ['display', 'title1', 'title2', 'title3', 'title4', 'title5'],
|
||||
responsive: true,
|
||||
},
|
||||
children: {
|
||||
type: 'enum',
|
||||
values: ['ReactNode'],
|
||||
responsive: false,
|
||||
},
|
||||
truncate: {
|
||||
type: 'boolean',
|
||||
default: 'false',
|
||||
},
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const headingUsageSnippet = `import { Heading } from '@backstage/canon';
|
||||
|
||||
<Heading />`;
|
||||
|
||||
export const headingDefaultSnippet = `<Heading variant="title1">Hello World!</Heading>`;
|
||||
|
||||
export const headingVariantsSnippet = `<Flex direction="column" gap="4">
|
||||
<Heading variant="display">Display</Heading>
|
||||
<Heading variant="title1">Title 1</Heading>
|
||||
<Heading variant="title2">Title 2</Heading>
|
||||
<Heading variant="title3">Title 3</Heading>
|
||||
<Heading variant="title4">Title 4</Heading>
|
||||
</Flex>`;
|
||||
|
||||
export const headingTruncateSnippet = `<Heading style={{ maxWidth: '400px' }} truncate>
|
||||
A man looks at a painting in a museum and says, "Brothers and sisters I
|
||||
have none, but that man's father is my father's son." Who is
|
||||
in the painting?
|
||||
</Heading>`;
|
||||
|
||||
export const headingResponsiveSnippet = `<Heading variant={{ initial: 'title2', lg: 'title1' }}>
|
||||
Responsive heading
|
||||
</Heading>`;
|
||||
@@ -0,0 +1,79 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import { IconButtonSnippet } from '@/snippets/stories-snippets';
|
||||
import {
|
||||
iconButtonPropDefs,
|
||||
iconButtonUsageSnippet,
|
||||
iconButtonDefaultSnippet,
|
||||
iconButtonVariantsSnippet,
|
||||
iconButtonSizesSnippet,
|
||||
iconButtonDisabledSnippet,
|
||||
iconButtonResponsiveSnippet,
|
||||
} from './icon-button.props';
|
||||
import { ComponentInfos } from '@/components/ComponentInfos';
|
||||
|
||||
# Icon Button
|
||||
|
||||
A button component with a single icon that can be used to trigger actions.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
preview={<IconButtonSnippet story="Variants" />}
|
||||
code={iconButtonDefaultSnippet}
|
||||
/>
|
||||
|
||||
<ComponentInfos
|
||||
component="icon-button"
|
||||
classNames={['canon-IconButton']}
|
||||
usageCode={iconButtonUsageSnippet}
|
||||
/>
|
||||
|
||||
## API reference
|
||||
|
||||
<PropsTable data={iconButtonPropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
### Variants
|
||||
|
||||
Here's a view when buttons have different variants.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<IconButtonSnippet story="Variants" />}
|
||||
code={iconButtonVariantsSnippet}
|
||||
/>
|
||||
|
||||
### Sizes
|
||||
|
||||
Here's a view when buttons have different sizes.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<IconButtonSnippet story="Sizes" />}
|
||||
code={iconButtonSizesSnippet}
|
||||
/>
|
||||
|
||||
### Disabled
|
||||
|
||||
Here's a view when buttons are disabled.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<IconButtonSnippet story="Disabled" />}
|
||||
code={iconButtonDisabledSnippet}
|
||||
/>
|
||||
|
||||
### Responsive
|
||||
|
||||
Here's a view when buttons are responsive.
|
||||
|
||||
<CodeBlock code={iconButtonResponsiveSnippet} />
|
||||
@@ -0,0 +1,46 @@
|
||||
import {
|
||||
classNamePropDefs,
|
||||
stylePropDefs,
|
||||
type PropDef,
|
||||
} from '@/utils/propDefs';
|
||||
|
||||
export const iconButtonPropDefs: Record<string, PropDef> = {
|
||||
variant: {
|
||||
type: 'enum',
|
||||
values: ['primary', 'secondary'],
|
||||
default: 'primary',
|
||||
responsive: true,
|
||||
},
|
||||
size: {
|
||||
type: 'enum',
|
||||
values: ['small', 'medium'],
|
||||
default: 'medium',
|
||||
responsive: true,
|
||||
},
|
||||
icon: { type: 'enum', values: 'icon', responsive: false },
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const iconButtonUsageSnippet = `import { IconButton } from '@backstage/canon';
|
||||
|
||||
<IconButton />`;
|
||||
|
||||
export const iconButtonDefaultSnippet = `<Flex align="center">
|
||||
<IconButton icon="cloud" variant="primary" />
|
||||
<IconButton icon="cloud" variant="secondary" />
|
||||
</Flex>`;
|
||||
|
||||
export const iconButtonVariantsSnippet = `<Flex align="center">
|
||||
<IconButton icon="cloud" variant="primary" />
|
||||
<IconButton icon="cloud" variant="secondary" />
|
||||
</Flex>`;
|
||||
|
||||
export const iconButtonSizesSnippet = `<Flex align="center">
|
||||
<IconButton icon="cloud" size="small" />
|
||||
<IconButton icon="cloud" size="medium" />
|
||||
</Flex>`;
|
||||
|
||||
export const iconButtonDisabledSnippet = `<IconButton icon="cloud" disabled />`;
|
||||
|
||||
export const iconButtonResponsiveSnippet = `<IconButton icon="cloud" variant={{ initial: 'primary', lg: 'secondary' }} />`;
|
||||
@@ -0,0 +1,31 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { IconSnippet } from '@/snippets/stories-snippets';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import {
|
||||
iconPropDefs,
|
||||
iconUsageSnippet,
|
||||
iconDefaultSnippet,
|
||||
} from './icon.props';
|
||||
import { ComponentInfos } from '@/components/ComponentInfos';
|
||||
|
||||
# Icon
|
||||
|
||||
Icons are used to represent an action or a state.
|
||||
|
||||
<Snippet
|
||||
py={4}
|
||||
align="center"
|
||||
preview={<IconSnippet story="Default" />}
|
||||
code={iconDefaultSnippet}
|
||||
/>
|
||||
|
||||
<ComponentInfos
|
||||
component="icon"
|
||||
classNames={['canon-Icon']}
|
||||
usageCode={iconUsageSnippet}
|
||||
/>
|
||||
|
||||
## API reference
|
||||
|
||||
<PropsTable data={iconPropDefs} />
|
||||
+11
-2
@@ -1,5 +1,8 @@
|
||||
import { classNamePropDefs, stylePropDefs } from '../../../../utils/propDefs';
|
||||
import type { PropDef } from '../../../../utils/propDefs';
|
||||
import {
|
||||
classNamePropDefs,
|
||||
stylePropDefs,
|
||||
type PropDef,
|
||||
} from '@/utils/propDefs';
|
||||
|
||||
export const iconPropDefs: Record<string, PropDef> = {
|
||||
name: {
|
||||
@@ -14,3 +17,9 @@ export const iconPropDefs: Record<string, PropDef> = {
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const iconUsageSnippet = `import { Icon } from '@backstage/canon';
|
||||
|
||||
<Icon />`;
|
||||
|
||||
export const iconDefaultSnippet = `<Icon name="heart" />`;
|
||||
@@ -0,0 +1,71 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import {
|
||||
MenuSnippet,
|
||||
ButtonSnippet,
|
||||
LinkSnippet,
|
||||
} from '@/snippets/stories-snippets';
|
||||
import {
|
||||
linkPropDefs,
|
||||
linkUsageSnippet,
|
||||
linkDefaultSnippet,
|
||||
linkVariantsSnippet,
|
||||
linkWeightsSnippet,
|
||||
} from './link.props';
|
||||
import { ComponentInfos } from '@/components/ComponentInfos';
|
||||
|
||||
# Link
|
||||
|
||||
A link component that renders a `<a>` element.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
preview={<LinkSnippet story="Default" />}
|
||||
code={linkDefaultSnippet}
|
||||
/>
|
||||
|
||||
<ComponentInfos
|
||||
component="link"
|
||||
classNames={[
|
||||
'canon-Link',
|
||||
"canon-Link[data-variant='body']",
|
||||
"canon-Link[data-variant='subtitle']",
|
||||
"canon-Link[data-variant='caption']",
|
||||
"canon-Link[data-variant='label']",
|
||||
"canon-Link[data-weight='regular']",
|
||||
"canon-Link[data-weight='bold']",
|
||||
]}
|
||||
usageCode={linkUsageSnippet}
|
||||
/>
|
||||
|
||||
## API reference
|
||||
|
||||
<PropsTable data={linkPropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
### Variants
|
||||
|
||||
Here's a view when links have different variants.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<LinkSnippet story="AllVariants" />}
|
||||
code={linkVariantsSnippet}
|
||||
/>
|
||||
|
||||
### Weights
|
||||
|
||||
Here's a view when links have different weights.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
open
|
||||
preview={<LinkSnippet story="AllWeights" />}
|
||||
code={linkWeightsSnippet}
|
||||
/>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user