Merge pull request #29280 from backstage/canon-improve-props

Canon: Improve props docs
This commit is contained in:
Fredrik Adelöw
2025-03-19 13:17:17 +01:00
committed by GitHub
36 changed files with 669 additions and 526 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/canon': patch
---
Fix the Icon component when the name is not found to return null instead of an empty SVG.
@@ -1,9 +1,10 @@
import { CodeBlock } from '@/components/CodeBlock';
import { PropsTable } from '@/components/PropsTable';
import { spacePropsList } from '@/utils/spaceProps';
import { Tabs } from '@/components/Tabs';
import { Snippet } from '@/components/Snippet';
import { BoxPreview } from '@/snippets/box';
import { boxPropDefs } from './props';
import { spacingPropDefs } from '../../../../utils/propDefs';
# Box
@@ -36,60 +37,13 @@ Box is the lowest-level component in Canon. It provides a consistent API for sty
This is the Box component, our lowest-level component. Here are all the
available properties.
<PropsTable
data={{
alignItems: {
type: ['stretch', 'start', 'center', 'end'],
responsive: true,
},
border: {
type: ['none', 'base', 'error', 'warning', 'selected'],
responsive: true,
},
borderRadius: {
type: ['none', '2xs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl'],
responsive: true,
},
children: {
type: 'ReactNode',
responsive: false,
},
className: {
type: 'string',
responsive: false,
},
display: {
type: ['none', 'flex', 'block', 'inline'],
responsive: true,
},
flexDirection: {
type: ['row', 'column'],
responsive: true,
},
flexWrap: {
type: ['wrap', 'nowrap', 'wrap-reverse'],
responsive: true,
},
gap: {
type: ['2xs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl', '5xl'],
responsive: true,
},
justifyContent: {
type: ['stretch', 'start', 'center', 'end', 'around', 'between'],
responsive: true,
},
style: {
type: 'CSSProperties',
responsive: false,
},
}}
/>
<PropsTable data={boxPropDefs} />
Padding and margin are used to create space around your component using our
predefined spacing tokens. We would recommend to use padding over margin to
avoid collapsing margins but both are available.
<PropsTable data={spacePropsList} />
<PropsTable data={spacingPropDefs} />
## Examples
@@ -0,0 +1,24 @@
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,
};
@@ -11,7 +11,7 @@ import {
ButtonResponsive,
} from '@/snippets/button';
import { buttonVariants } from '@/snippets/_snippets';
import { buttonPropDefs } from '../../../../../../packages/canon/src/components/Button/Button.props';
import { buttonPropDefs } from './props';
# Button
@@ -0,0 +1,19 @@
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,
};
@@ -4,6 +4,7 @@ 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
@@ -42,50 +43,7 @@ A checkbox component that can be used to trigger actions.
<BaseUI href="https://base-ui.com/react/components/checkbox" />
<PropsTable
data={{
label: {
type: 'string',
responsive: false,
},
defaultChecked: {
type: ['boolean', "'indeterminate'"],
responsive: false,
},
checked: {
type: ['boolean', "'indeterminate'"],
responsive: false,
},
onChange: {
type: "(checked: boolean | 'indeterminate') => void",
responsive: false,
},
disabled: {
type: 'boolean',
responsive: false,
},
required: {
type: 'boolean',
responsive: false,
},
name: {
type: 'string',
responsive: false,
},
value: {
type: 'string',
responsive: false,
},
className: {
type: 'string',
responsive: false,
},
style: {
type: 'CSSProperties',
responsive: false,
},
}}
/>
<PropsTable data={checkboxPropDefs} />
## Examples
@@ -0,0 +1,44 @@
import { classNamePropDefs, stylePropDefs } from '../../../../utils/propDefs';
import type { PropDef } from '../../../../utils/propDefs';
export const checkboxPropDefs: Record<string, PropDef> = {
label: {
type: 'string',
responsive: false,
},
defaultChecked: {
type: 'enum',
values: ['boolean', "'indeterminate'"],
responsive: false,
},
checked: {
type: 'enum',
values: ['boolean', "'indeterminate'"],
responsive: false,
},
onChange: {
type: 'enum',
values: ["(checked: boolean | 'indeterminate') => void"],
responsive: false,
},
disabled: {
type: 'enum',
values: ['boolean'],
responsive: false,
},
required: {
type: 'enum',
values: ['boolean'],
responsive: false,
},
name: {
type: 'string',
responsive: false,
},
value: {
type: 'string',
responsive: false,
},
...classNamePropDefs,
...stylePropDefs,
};
@@ -1,9 +1,9 @@
import { CodeBlock } from '@/components/CodeBlock';
import { PropsTable } from '@/components/PropsTable';
import { spacePropsList } from '@/utils/spaceProps';
import { Tabs } from '@/components/Tabs';
import { Snippet } from '@/components/Snippet';
import { ContainerPreview } from '@/snippets/container';
import { containerPropDefs } from './props';
# Container
@@ -32,46 +32,7 @@ content on the page.
## API reference
<PropsTable
data={{
children: {
type: 'ReactNode',
responsive: false,
},
className: {
type: 'string',
responsive: false,
},
marginY: {
type: spacePropsList.marginY.type,
responsive: spacePropsList.marginY.responsive,
},
marginBottom: {
type: spacePropsList.marginBottom.type,
responsive: spacePropsList.marginBottom.responsive,
},
marginTop: {
type: spacePropsList.marginTop.type,
responsive: spacePropsList.marginTop.responsive,
},
paddingY: {
type: spacePropsList.paddingY.type,
responsive: spacePropsList.paddingY.responsive,
},
paddingBottom: {
type: spacePropsList.paddingBottom.type,
responsive: spacePropsList.paddingBottom.responsive,
},
paddingTop: {
type: spacePropsList.paddingTop.type,
responsive: spacePropsList.paddingTop.responsive,
},
style: {
type: 'CSSProperties',
responsive: false,
},
}}
/>
<PropsTable data={containerPropDefs} />
## Examples
@@ -0,0 +1,12 @@
import {
classNamePropDefs,
stylePropDefs,
gapPropDefs,
} from '../../../../utils/propDefs';
import type { PropDef } from '../../../../utils/propDefs';
export const containerPropDefs: Record<string, PropDef> = {
...gapPropDefs,
...classNamePropDefs,
...stylePropDefs,
};
@@ -4,6 +4,12 @@ import { Tabs } from '@/components/Tabs';
import { CodeBlock } from '@/components/CodeBlock';
import { FieldPreview } from '@/snippets/field';
import { BaseUI } from '@/components/HeadlessBanners/BaseUI';
import {
fieldRootPropDefs,
fieldLabelPropDefs,
fieldDescriptionPropDefs,
fieldErrorPropDefs,
} from './props';
# Field
@@ -49,113 +55,25 @@ A wrapper around `Input` or `Select` component to add label, description and err
Groups all parts of the field. Renders a `<div>` element.
<PropsTable
data={{
name: {
type: 'string',
responsive: false,
},
disabled: {
type: 'boolean',
responsive: false,
},
invalid: {
type: 'boolean',
responsive: false,
},
validate: {
type: '(value) => string | string[] | null | Promise',
responsive: false,
},
validationMode: {
type: ['onBlur', 'onChange'],
responsive: false,
},
validationDebounceTime: {
type: 'number',
responsive: false,
},
className: {
type: 'string',
responsive: false,
},
style: {
type: 'CSSProperties',
responsive: false,
},
}}
/>
<PropsTable data={fieldRootPropDefs} />
### Field.Label
An accessible label that is automatically associated with the field control. Renders a `<label>` element.
<PropsTable
data={{
className: {
type: 'string',
responsive: false,
},
style: {
type: 'CSSProperties',
responsive: false,
},
}}
/>
<PropsTable data={fieldLabelPropDefs} />
### Field.Description
A paragraph with additional information about the field. Renders a `<p>` element.
<PropsTable
data={{
className: {
type: 'string',
responsive: false,
},
style: {
type: 'CSSProperties',
responsive: false,
},
}}
/>
<PropsTable data={fieldDescriptionPropDefs} />
### Field.Error
An error message displayed if the field control fails validation. Renders a `<div>` element.
<PropsTable
data={{
match: {
type: [
'badInput',
'customError',
'patternMismatch',
'rangeOverflow',
'rangeUnderflow',
'stepMismatch',
'tooLong',
'tooShort',
'typeMismatch',
'valid',
'valueMissing',
],
responsive: false,
},
forceShow: {
type: 'boolean',
responsive: false,
},
className: {
type: 'string',
responsive: false,
},
style: {
type: 'CSSProperties',
responsive: false,
},
}}
/>
<PropsTable data={fieldErrorPropDefs} />
## Examples
@@ -0,0 +1,69 @@
import { classNamePropDefs, stylePropDefs } from '../../../../utils/propDefs';
import type { PropDef } from '../../../../utils/propDefs';
export const fieldRootPropDefs: Record<string, PropDef> = {
name: {
type: 'string',
responsive: false,
},
disabled: {
type: 'boolean',
responsive: false,
},
invalid: {
type: 'boolean',
responsive: false,
},
validate: {
type: 'enum',
values: ['(value) => string | string[] | null | Promise'],
responsive: false,
},
validationMode: {
type: 'enum',
values: ['onBlur', 'onChange'],
responsive: false,
},
validationDebounceTime: {
type: 'number',
responsive: false,
},
...classNamePropDefs,
...stylePropDefs,
};
export const fieldLabelPropDefs: Record<string, PropDef> = {
...classNamePropDefs,
...stylePropDefs,
};
export const fieldDescriptionPropDefs: Record<string, PropDef> = {
...classNamePropDefs,
...stylePropDefs,
};
export const fieldErrorPropDefs: Record<string, PropDef> = {
match: {
type: 'enum',
values: [
'badInput',
'customError',
'patternMismatch',
'rangeOverflow',
'rangeUnderflow',
'stepMismatch',
'tooLong',
'tooShort',
'typeMismatch',
'valid',
'valueMissing',
],
responsive: false,
},
forceShow: {
type: 'boolean',
responsive: false,
},
...classNamePropDefs,
...stylePropDefs,
};
@@ -1,5 +1,4 @@
import { PropsTable } from '@/components/PropsTable';
import { spacePropsList } from '@/utils/spaceProps';
import { Tabs } from '@/components/Tabs';
import { CodeBlock } from '@/components/CodeBlock';
import {
@@ -10,6 +9,8 @@ import {
} from '@/snippets/_snippets';
import { Snippet } from '@/components/Snippet';
import { FlexPreview } from '@/snippets/flex';
import { flexPropDefs } from './props';
import { spacingPropDefs } from '../../../../utils/propDefs';
# Flex
@@ -44,30 +45,11 @@ columns. All values are responsive.
## API reference
<PropsTable
data={{
align: {
type: ['start', 'center', 'end'],
responsive: true,
},
children: {
type: 'ReactNode',
required: false,
},
className: {
type: 'string',
required: false,
},
style: {
type: 'CSSProperties',
required: false,
},
}}
/>
<PropsTable data={flexPropDefs} />
The grid component also accepts all the spacing props from the Box component.
<PropsTable data={spacePropsList} />
<PropsTable data={spacingPropDefs} />
## Common questions
@@ -0,0 +1,27 @@
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,10 +1,11 @@
import { CodeBlock } from '@/components/CodeBlock';
import { PropsTable } from '@/components/PropsTable';
import { spacePropsList } from '@/utils/spaceProps';
import { Tabs } from '@/components/Tabs';
import { grid } from '@/snippets/_snippets';
import { Snippet } from '@/components/Snippet';
import { GridPreview } from '@/snippets/grid';
import { spacingPropDefs } from '../../../../utils/propDefs';
import { gridPropDefs, gridItemPropDefs } from './props';
# Grid
@@ -38,34 +39,11 @@ 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
columns. All values are responsive.
<PropsTable
data={{
columns: {
type: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 'auto'],
responsive: true,
},
gap: {
type: ['xs', 'sm', 'md', 'lg', 'xl'],
responsive: true,
},
children: {
type: 'ReactNode',
required: false,
},
className: {
type: 'string',
required: false,
},
style: {
type: 'CSSProperties',
required: false,
},
}}
/>
<PropsTable data={gridPropDefs} />
The grid component also accepts all the spacing props from the Box component.
<PropsTable data={spacePropsList} />
<PropsTable data={spacingPropDefs} />
### Grid.Item
@@ -74,38 +52,7 @@ component. This will give you access to `rowSpan`, `colSpan`, `start` and
`end`. All values are responsive. This component is optional, you can use any
elements directly if you prefer.
<PropsTable
data={{
colSpan: {
type: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 'full'],
responsive: true,
},
rowSpan: {
type: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 'full'],
responsive: true,
},
start: {
type: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 'auto'],
responsive: true,
},
end: {
type: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 'auto'],
responsive: true,
},
children: {
type: 'ReactNode',
required: false,
},
className: {
type: 'string',
required: false,
},
style: {
type: 'CSSProperties',
required: false,
},
}}
/>
<PropsTable data={gridItemPropDefs} />
## Examples
@@ -0,0 +1,59 @@
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,
};
@@ -7,6 +7,7 @@ import {
import { Snippet } from '@/components/Snippet';
import { Tabs } from '@/components/Tabs';
import { CodeBlock } from '@/components/CodeBlock';
import { headingPropDefs } from './props';
# Heading
@@ -43,26 +44,7 @@ Headings are used to structure the content of your page.
## API reference
<PropsTable
data={{
variant: {
type: ['display', 'title1', 'title2', 'title3', 'title4', 'title5'],
responsive: true,
},
children: {
type: 'ReactNode',
responsive: false,
},
className: {
type: 'string',
responsive: false,
},
style: {
type: 'CSSProperties',
responsive: false,
},
}}
/>
<PropsTable data={headingPropDefs} />
## Examples
@@ -0,0 +1,17 @@
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,
},
...classNamePropDefs,
...stylePropDefs,
};
@@ -9,7 +9,7 @@ import {
IconButtonResponsive,
} from '@/snippets/icon-button';
import { iconButtonVariants } from '@/snippets/_snippets';
import { iconButtonPropDefs } from '../../../../../../packages/canon/src/components/IconButton/IconButton.props';
import { iconButtonPropDefs } from './props';
# Icon Button
@@ -50,12 +50,7 @@ A button component with a single icon that can be used to trigger actions.
## API reference
<PropsTable
data={{
...iconButtonPropDefs,
icon: { values: 'icon', responsive: false },
}}
/>
<PropsTable data={iconButtonPropDefs} />
## Examples
@@ -0,0 +1,20 @@
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,
};
@@ -3,6 +3,7 @@ import { IconPreview } from '@/snippets/icon';
import { Snippet } from '@/components/Snippet';
import { Tabs } from '@/components/Tabs';
import { CodeBlock } from '@/components/CodeBlock';
import { iconPropDefs } from './props';
# Icon
@@ -40,23 +41,4 @@ Icons are used to represent an action or a state.
## API reference
<PropsTable
data={{
name: {
type: 'icon',
responsive: false,
},
size: {
type: 'number',
responsive: false,
},
className: {
type: 'string',
responsive: false,
},
style: {
type: 'CSSProperties',
responsive: false,
},
}}
/>
<PropsTable data={iconPropDefs} />
@@ -0,0 +1,16 @@
import { classNamePropDefs, stylePropDefs } from '../../../../utils/propDefs';
import type { PropDef } from '../../../../utils/propDefs';
export const iconPropDefs: Record<string, PropDef> = {
name: {
type: 'enum',
values: 'icon',
responsive: false,
},
size: {
type: 'number',
responsive: false,
},
...classNamePropDefs,
...stylePropDefs,
};
@@ -4,6 +4,7 @@ import { Tabs } from '@/components/Tabs';
import { CodeBlock } from '@/components/CodeBlock';
import { InputPreview, InputSizes } from '@/snippets/input';
import { BaseUI } from '@/components/HeadlessBanners/BaseUI';
import { inputPropDefs } from './props';
# Input
@@ -42,22 +43,7 @@ A input component tfor your forms.
<BaseUI href="https://base-ui.com/react/components/input" />
<PropsTable
data={{
size: {
type: ['sm', 'md'],
responsive: false,
},
className: {
type: 'string',
responsive: false,
},
style: {
type: 'CSSProperties',
responsive: false,
},
}}
/>
<PropsTable data={inputPropDefs} />
## Examples
@@ -0,0 +1,13 @@
import { classNamePropDefs, stylePropDefs } from '../../../../utils/propDefs';
import type { PropDef } from '../../../../utils/propDefs';
export const inputPropDefs: Record<string, PropDef> = {
size: {
type: 'enum',
values: ['sm', 'md'],
default: 'md',
responsive: false,
},
...classNamePropDefs,
...stylePropDefs,
};
@@ -8,6 +8,7 @@ import {
import { Snippet } from '@/components/Snippet';
import { Tabs } from '@/components/Tabs';
import { CodeBlock } from '@/components/CodeBlock';
import { textPropDefs } from './props';
# Text
@@ -48,30 +49,7 @@ The `Text` component is used to display content on your page.
## API reference
<PropsTable
data={{
variant: {
type: ['display', 'title1', 'title2', 'title3', 'title4', 'title5'],
responsive: true,
},
weight: {
type: ['regular', 'bold'],
responsive: true,
},
children: {
type: 'ReactNode',
responsive: false,
},
className: {
type: 'string',
responsive: false,
},
style: {
type: 'CSSProperties',
responsive: false,
},
}}
/>
<PropsTable data={textPropDefs} />
## Examples
@@ -0,0 +1,22 @@
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,
},
...childrenPropDefs,
...classNamePropDefs,
...stylePropDefs,
};
@@ -125,7 +125,7 @@ export const CustomTheme = () => {
className={styles.buttonClose}
onClick={() => setOpen(!open)}
>
<Icon name={open ? 'chevronDown' : 'chevronUp'} />
<Icon name={open ? 'chevron-down' : 'chevron-up'} />
</button>
</div>
</div>
@@ -35,7 +35,7 @@ export const BaseUI = ({ href }: BaseUIProps) => {
{href && (
<a className={styles.button} href={href} target="_blank">
Discover more
<Icon name="externalLink" />
<Icon name="external-link" />
</a>
)}
</div>
@@ -9,6 +9,7 @@ type PropData = {
values?: string | string[];
responsive?: boolean;
default?: string;
type?: string;
};
// Modify the PropsTable component to use the new type
@@ -17,57 +18,58 @@ export const PropsTable = <T extends Record<string, PropData>>({
}: {
data: T;
}) => {
const completeData = {
...data,
className: {
values: 'string',
responsive: false,
},
style: {
values: 'CSSProperties',
responsive: false,
},
};
if (!data) return null;
return (
<Table.Root>
<Table.Header>
<Table.HeaderRow>
<Table.HeaderCell>Prop</Table.HeaderCell>
<Table.HeaderCell>Type</Table.HeaderCell>
<Table.HeaderCell>Default</Table.HeaderCell>
<Table.HeaderCell>Responsive</Table.HeaderCell>
<Table.HeaderCell style={{ width: '16%' }}>Prop</Table.HeaderCell>
<Table.HeaderCell style={{ width: '56%' }}>Type</Table.HeaderCell>
<Table.HeaderCell style={{ width: '14%' }}>Default</Table.HeaderCell>
<Table.HeaderCell style={{ width: '14%' }}>
Responsive
</Table.HeaderCell>
</Table.HeaderRow>
</Table.Header>
<Table.Body>
{Object.keys(completeData).map(n => (
<Table.Row key={n}>
<Table.Cell>
<Chip head>{n}</Chip>
</Table.Cell>
<Table.Cell>
<div
style={{ display: 'flex', flexWrap: 'wrap', gap: '0.375rem' }}
>
{completeData[n].values === 'icon' ? (
Object.keys(icons).map(icon => <Chip key={icon}>{icon}</Chip>)
) : Array.isArray(completeData[n].values) ? (
completeData[n].values.map(t => <Chip key={t}>{t}</Chip>)
) : (
<Chip>{completeData[n].values}</Chip>
)}
</div>
</Table.Cell>
<Table.Cell>
<Chip>
{completeData[n].default ? completeData[n].default : '-'}
</Chip>
</Table.Cell>
<Table.Cell>
<Chip>{completeData[n].responsive ? 'Yes' : 'No'}</Chip>
</Table.Cell>
</Table.Row>
))}
{Object.keys(data).map(n => {
const enumValues =
data[n].values === 'icon'
? Object.keys(icons).map(icon => <Chip key={icon}>{icon}</Chip>)
: Array.isArray(data[n].values) &&
data[n].values.map(t => <Chip key={t}>{t}</Chip>);
return (
<Table.Row key={n}>
<Table.Cell style={{ width: '16%' }}>
<Chip head>{n}</Chip>
</Table.Cell>
<Table.Cell style={{ width: '56%' }}>
<div
style={{ display: 'flex', flexWrap: 'wrap', gap: '0.375rem' }}
>
{data[n].type === 'string' && <Chip>string</Chip>}
{data[n].type === 'number' && <Chip>number</Chip>}
{data[n].type === 'boolean' && <Chip>boolean</Chip>}
{data[n].type === 'enum' && enumValues}
{data[n].type === 'enum | string' && (
<>
{enumValues}
<Chip>string</Chip>
</>
)}
</div>
</Table.Cell>
<Table.Cell style={{ width: '14%' }}>
<Chip>{data[n].default ? data[n].default : '-'}</Chip>
</Table.Cell>
<Table.Cell style={{ width: '14%' }}>
<Chip>{data[n].responsive ? 'Yes' : 'No'}</Chip>
</Table.Cell>
</Table.Row>
);
})}
</Table.Body>
</Table.Root>
);
+23 -20
View File
@@ -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 React from 'react';
import styles from './styles.module.css';
@@ -37,9 +21,18 @@ export const HeaderRow = ({ children }: { children: React.ReactNode }) => {
return <tr>{children}</tr>;
};
export const HeaderCell = ({ children }: { children: React.ReactNode }) => {
export const HeaderCell = ({
children,
style,
}: {
children: React.ReactNode;
style?: React.CSSProperties;
}) => {
return (
<th className={`${styles.tableCell} ${styles.tableHeaderCell}`}>
<th
className={`${styles.tableCell} ${styles.tableHeaderCell}`}
style={style}
>
{children}
</th>
);
@@ -49,6 +42,16 @@ export const Row = ({ children }: { children: React.ReactNode }) => {
return <tr className={styles.tableRow}>{children}</tr>;
};
export const Cell = ({ children }: { children: React.ReactNode }) => {
return <td className={styles.tableCell}>{children}</td>;
export const Cell = ({
children,
style,
}: {
children: React.ReactNode;
style?: React.CSSProperties;
}) => {
return (
<td className={styles.tableCell} style={style}>
{children}
</td>
);
};
@@ -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.
*/
.wrapper {
border: 1px solid var(--border);
border-radius: 4px;
@@ -24,7 +24,7 @@ export const ThemeNameSelector = () => {
placeholder="Select a theme"
/>
<Select.Icon className={styles.SelectIcon}>
<Icon name="chevronDown" />
<Icon name="chevron-down" />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
+6 -6
View File
@@ -28,8 +28,8 @@ export const ButtonWithIcons = () => {
return (
<Flex align="center">
<Button iconStart="cloud">Button</Button>
<Button iconEnd="chevronRight">Button</Button>
<Button iconStart="cloud" iconEnd="chevronRight">
<Button iconEnd="chevron-right">Button</Button>
<Button iconStart="cloud" iconEnd="chevron-right">
Button
</Button>
</Flex>
@@ -40,8 +40,8 @@ export const ButtonFullWidth = () => {
return (
<Flex direction="column" style={{ width: '300px' }}>
<Button iconStart="cloud">Button</Button>
<Button iconEnd="chevronRight">Button</Button>
<Button iconStart="cloud" iconEnd="chevronRight">
<Button iconEnd="chevron-right">Button</Button>
<Button iconStart="cloud" iconEnd="chevron-right">
Button
</Button>
</Flex>
@@ -78,7 +78,7 @@ export const ButtonPlayground = () => {
Button
</Button>
<Button
iconEnd="chevronRight"
iconEnd="chevron-right"
variant={variant as ButtonProps['variant']}
size={size as ButtonProps['size']}
>
@@ -86,7 +86,7 @@ export const ButtonPlayground = () => {
</Button>
<Button
iconStart="cloud"
iconEnd="chevronRight"
iconEnd="chevron-right"
style={{ width: '200px' }}
variant={variant as ButtonProps['variant']}
size={size as ButtonProps['size']}
+205
View File
@@ -0,0 +1,205 @@
import type { Breakpoint } from '@backstage/canon/src/types';
const breakpoints = ['initial', 'xs', 'sm', 'md', 'lg', 'xl'] as Breakpoint[];
export type PropDef = {
type: 'string' | 'enum' | 'enum | string' | 'number' | 'boolean';
values?: string | string[];
default?: string;
required?: boolean;
responsive?: boolean;
};
export { breakpoints };
export type { Breakpoint };
export const spacingValues = [
'0.5',
'1',
'1.5',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'10',
'11',
'12',
'13',
'14',
];
export const paddingPropDefs = (
spacingValues: string[],
): Record<string, PropDef> => ({
p: {
type: 'enum | string',
values: spacingValues,
responsive: true,
},
px: {
type: 'enum | string',
values: spacingValues,
responsive: true,
},
py: {
type: 'enum | string',
values: spacingValues,
responsive: true,
},
pt: {
type: 'enum | string',
values: spacingValues,
responsive: true,
},
pr: {
type: 'enum | string',
values: spacingValues,
responsive: true,
},
pb: {
type: 'enum | string',
values: spacingValues,
responsive: true,
},
pl: {
type: 'enum | string',
values: spacingValues,
responsive: true,
},
});
export const marginPropDefs = (
spacingValues: string[],
): Record<string, PropDef> => ({
m: {
type: 'enum | string',
values: spacingValues,
responsive: true,
},
mx: {
type: 'enum | string',
values: spacingValues,
responsive: true,
},
my: {
type: 'enum | string',
values: spacingValues,
responsive: true,
},
mt: {
type: 'enum | string',
values: spacingValues,
responsive: true,
},
mr: {
type: 'enum | string',
values: spacingValues,
responsive: true,
},
mb: {
type: 'enum | string',
values: spacingValues,
responsive: true,
},
ml: {
type: 'enum | string',
values: spacingValues,
responsive: true,
},
});
export const spacingPropDefs = {
...paddingPropDefs(spacingValues),
...marginPropDefs(spacingValues),
};
export const displayPropDefs: Record<string, PropDef> = {
display: {
type: 'enum',
values: ['none', 'inline', 'inline-block', 'block'],
default: 'block',
responsive: true,
},
};
export const gapPropDefs: Record<string, PropDef> = {
gap: {
type: 'enum | string',
values: spacingValues,
responsive: true,
default: '4',
},
};
export const widthPropDefs: Record<string, PropDef> = {
width: {
type: 'string',
default: '0',
responsive: true,
},
minWidth: {
type: 'string',
default: '0',
responsive: true,
},
maxWidth: {
type: 'string',
default: '0',
responsive: true,
},
};
export const heightPropDefs: Record<string, PropDef> = {
height: {
type: 'string',
default: '0',
responsive: true,
},
minHeight: {
type: 'string',
default: '0',
responsive: true,
},
maxHeight: {
type: 'string',
default: '0',
responsive: true,
},
};
export const positionPropDefs: Record<string, PropDef> = {
position: {
type: 'enum',
values: ['static', 'relative', 'absolute', 'fixed', 'sticky'],
default: 'static',
responsive: true,
},
};
export const classNamePropDefs: Record<string, PropDef> = {
className: {
type: 'string',
responsive: false,
},
};
export const stylePropDefs: Record<string, PropDef> = {
style: {
type: 'enum',
values: ['CSSProperties'],
responsive: false,
},
};
export const childrenPropDefs: Record<string, PropDef> = {
children: {
type: 'enum',
values: ['ReactNode'],
required: true,
responsive: false,
},
};
-41
View File
@@ -1,41 +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 spacePropsList = [
'margin',
'marginBottom',
'marginLeft',
'marginRight',
'marginTop',
'marginX',
'marginY',
'padding',
'paddingBottom',
'paddingLeft',
'paddingRight',
'paddingTop',
'paddingX',
'paddingY',
].reduce(
(acc: { [key: string]: { type: string[]; responsive: boolean } }, prop) => {
acc[prop] = {
type: ['2xs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl', '5xl'],
responsive: true,
};
return acc;
},
{},
);
+1 -1
View File
@@ -590,7 +590,7 @@ export const heightPropDefs: {
export type HeightProps = GetPropDefTypes<typeof heightPropDefs>;
// @public (undocumented)
export const Icon: (props: IconProps) => React_2.JSX.Element;
export const Icon: (props: IconProps) => React_2.JSX.Element | null;
// @public (undocumented)
export const IconButton: React_2.ForwardRefExoticComponent<
+1 -1
View File
@@ -28,7 +28,7 @@ export const Icon = (props: IconProps) => {
if (!CanonIcon) {
console.error(`Icon "${name}" not found or is not a valid component.`);
return <svg />; // Return a default icon or handle the error appropriately
return null;
}
return (