grafana/ui: Add noMargin prop to Card (#105604)

grafana/ui: Add noMargin to Card
This commit is contained in:
Alex Khomenko
2025-05-22 12:03:58 +03:00
committed by GitHub
parent 5299602211
commit ec48b0dfcb
4 changed files with 32 additions and 32 deletions

View File

@ -100,7 +100,7 @@ export const Examples: StoryFn<typeof Button> = () => {
<Button variant="secondary" icon="angle-down" /> <Button variant="secondary" icon="angle-down" />
</ButtonGroup> </ButtonGroup>
</Stack> </Stack>
<Card> <Card noMargin>
<Card.Heading>Button inside card</Card.Heading> <Card.Heading>Button inside card</Card.Heading>
<Card.Actions> <Card.Actions>
{allButtonVariants.map((variant) => ( {allButtonVariants.map((variant) => (

View File

@ -15,7 +15,7 @@ const meta: Meta<typeof Card> = {
tags: ['autodocs', 'nosort'], tags: ['autodocs', 'nosort'],
parameters: { parameters: {
controls: { controls: {
exclude: ['onClick', 'href', 'heading', 'description', 'className'], exclude: ['onClick', 'href', 'heading', 'description', 'className', 'noMargin'],
}, },
}, },
}; };
@ -25,7 +25,7 @@ const meta: Meta<typeof Card> = {
*/ */
export const Basic: StoryFn<typeof Card> = (args) => { export const Basic: StoryFn<typeof Card> = (args) => {
return ( return (
<Card {...args}> <Card noMargin {...args}>
<Card.Heading>Filter by name</Card.Heading> <Card.Heading>Filter by name</Card.Heading>
<Card.Description> <Card.Description>
Filter data by query. This is useful if you are sharing the results from a different panel that has many queries Filter data by query. This is useful if you are sharing the results from a different panel that has many queries
@ -41,7 +41,7 @@ export const Basic: StoryFn<typeof Card> = (args) => {
*/ */
export const MultipleMetadataElements: StoryFn<typeof Card> = (args) => { export const MultipleMetadataElements: StoryFn<typeof Card> = (args) => {
return ( return (
<Card> <Card noMargin>
<Card.Heading>Test dashboard</Card.Heading> <Card.Heading>Test dashboard</Card.Heading>
<Card.Meta>{['Folder: Test', 'Views: 100']}</Card.Meta> <Card.Meta>{['Folder: Test', 'Views: 100']}</Card.Meta>
</Card> </Card>
@ -54,7 +54,7 @@ export const MultipleMetadataElements: StoryFn<typeof Card> = (args) => {
*/ */
export const ComplexMetadataElements: StoryFn<typeof Card> = (args) => { export const ComplexMetadataElements: StoryFn<typeof Card> = (args) => {
return ( return (
<Card> <Card noMargin>
<Card.Heading>Test dashboard</Card.Heading> <Card.Heading>Test dashboard</Card.Heading>
<Card.Meta> <Card.Meta>
<>Grafana</> <>Grafana</>
@ -71,7 +71,7 @@ export const ComplexMetadataElements: StoryFn<typeof Card> = (args) => {
*/ */
export const MultipleMetadataWithCustomSeparator: StoryFn<typeof Card> = (args) => { export const MultipleMetadataWithCustomSeparator: StoryFn<typeof Card> = (args) => {
return ( return (
<Card> <Card noMargin>
<Card.Heading>Test dashboard</Card.Heading> <Card.Heading>Test dashboard</Card.Heading>
<Card.Meta separator={'-'}> <Card.Meta separator={'-'}>
Grafana Grafana
@ -90,7 +90,7 @@ export const MultipleMetadataWithCustomSeparator: StoryFn<typeof Card> = (args)
*/ */
export const Tags: StoryFn<typeof Card> = (args) => { export const Tags: StoryFn<typeof Card> = (args) => {
return ( return (
<Card> <Card noMargin>
<Card.Heading>Test dashboard</Card.Heading> <Card.Heading>Test dashboard</Card.Heading>
<Card.Description>Card with a list of tags</Card.Description> <Card.Description>Card with a list of tags</Card.Description>
<Card.Tags> <Card.Tags>
@ -105,7 +105,7 @@ export const Tags: StoryFn<typeof Card> = (args) => {
*/ */
export const AsALink: StoryFn<typeof Card> = (args) => { export const AsALink: StoryFn<typeof Card> = (args) => {
return ( return (
<Card href="https://grafana.com"> <Card noMargin href="https://grafana.com">
<Card.Heading>Redirect to Grafana</Card.Heading> <Card.Heading>Redirect to Grafana</Card.Heading>
<Card.Description>Clicking this card will redirect to grafana website</Card.Description> <Card.Description>Clicking this card will redirect to grafana website</Card.Description>
</Card> </Card>
@ -119,7 +119,7 @@ export const AsALink: StoryFn<typeof Card> = (args) => {
*/ */
export const AsAButton: StoryFn<typeof Card> = (args) => { export const AsAButton: StoryFn<typeof Card> = (args) => {
return ( return (
<Card onClick={() => alert('Hello, Grafana!')}> <Card noMargin onClick={() => alert('Hello, Grafana!')}>
<Card.Heading>Hello, Grafana</Card.Heading> <Card.Heading>Hello, Grafana</Card.Heading>
<Card.Description>Clicking this card will create an alert</Card.Description> <Card.Description>Clicking this card will create an alert</Card.Description>
</Card> </Card>
@ -131,27 +131,27 @@ export const AsAButton: StoryFn<typeof Card> = (args) => {
*/ */
export const InsideAListItem: StoryFn<typeof Card> = (args) => { export const InsideAListItem: StoryFn<typeof Card> = (args) => {
return ( return (
<ul style={{ padding: '20px', listStyle: 'none', display: 'grid' }}> <ul style={{ padding: '20px', listStyle: 'none', display: 'grid', gap: '8px' }}>
<li> <li>
<Card> <Card noMargin>
<Card.Heading>List card item</Card.Heading> <Card.Heading>List card item</Card.Heading>
<Card.Description>Card that is rendered inside li element.</Card.Description> <Card.Description>Card that is rendered inside li element.</Card.Description>
</Card> </Card>
</li> </li>
<li> <li>
<Card> <Card noMargin>
<Card.Heading>List card item</Card.Heading> <Card.Heading>List card item</Card.Heading>
<Card.Description>Card that is rendered inside li element.</Card.Description> <Card.Description>Card that is rendered inside li element.</Card.Description>
</Card> </Card>
</li> </li>
<li> <li>
<Card> <Card noMargin>
<Card.Heading>List card item</Card.Heading> <Card.Heading>List card item</Card.Heading>
<Card.Description>Card that is rendered inside li element.</Card.Description> <Card.Description>Card that is rendered inside li element.</Card.Description>
</Card> </Card>
</li> </li>
<li> <li>
<Card> <Card noMargin>
<Card.Heading>List card item</Card.Heading> <Card.Heading>List card item</Card.Heading>
<Card.Description>Card that is rendered inside li element.</Card.Description> <Card.Description>Card that is rendered inside li element.</Card.Description>
</Card> </Card>
@ -161,11 +161,11 @@ export const InsideAListItem: StoryFn<typeof Card> = (args) => {
}; };
/** /**
* Cards can also be rendered with media content such icons or images. Such elements need to be wrapped in `Card.Figure` component. * Cards can also be rendered with media content such as icons or images. Such elements need to be wrapped in `Card.Figure` component.
*/ */
export const WithMediaElements: StoryFn<typeof Card> = (args) => { export const WithMediaElements: StoryFn<typeof Card> = (args) => {
return ( return (
<Card> <Card noMargin>
<Card.Heading>1-ops-tools1-fallback</Card.Heading> <Card.Heading>1-ops-tools1-fallback</Card.Heading>
<Card.Figure> <Card.Figure>
<img src={logo} alt="Grafana Logo" width="40" height="40" /> <img src={logo} alt="Grafana Logo" width="40" height="40" />
@ -187,7 +187,7 @@ export const WithMediaElements: StoryFn<typeof Card> = (args) => {
*/ */
export const ActionCards: StoryFn<typeof Card> = (args) => { export const ActionCards: StoryFn<typeof Card> = (args) => {
return ( return (
<Card {...args}> <Card noMargin {...args}>
<Card.Heading>1-ops-tools1-fallback</Card.Heading> <Card.Heading>1-ops-tools1-fallback</Card.Heading>
<Card.Meta> <Card.Meta>
Prometheus Prometheus
@ -220,7 +220,7 @@ export const ActionCards: StoryFn<typeof Card> = (args) => {
*/ */
export const DisabledState: StoryFn<typeof Card> = (args) => { export const DisabledState: StoryFn<typeof Card> = (args) => {
return ( return (
<Card disabled> <Card noMargin disabled>
<Card.Heading>1-ops-tools1-fallback</Card.Heading> <Card.Heading>1-ops-tools1-fallback</Card.Heading>
<Card.Meta> <Card.Meta>
Grafana Grafana
@ -249,7 +249,7 @@ export const DisabledState: StoryFn<typeof Card> = (args) => {
export const Selectable: StoryFn<typeof Card> = () => { export const Selectable: StoryFn<typeof Card> = () => {
return ( return (
<Card isSelected disabled> <Card noMargin isSelected disabled>
<Card.Heading>Option #1</Card.Heading> <Card.Heading>Option #1</Card.Heading>
<Card.Description>This is a really great option, you will not regret it.</Card.Description> <Card.Description>This is a really great option, you will not regret it.</Card.Description>
<Card.Figure> <Card.Figure>
@ -261,7 +261,7 @@ export const Selectable: StoryFn<typeof Card> = () => {
export const Full: StoryFn<typeof Card> = (args) => { export const Full: StoryFn<typeof Card> = (args) => {
return ( return (
<Card {...args}> <Card noMargin {...args}>
<Card.Heading>Card title</Card.Heading> <Card.Heading>Card title</Card.Heading>
<Card.Description> <Card.Description>
Description, body text. Greetings! Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod Description, body text. Greetings! Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod

View File

@ -11,7 +11,7 @@ describe('Card', () => {
const user = userEvent.setup(); const user = userEvent.setup();
const callback = jest.fn(); const callback = jest.fn();
render( render(
<Card onClick={callback}> <Card noMargin onClick={callback}>
<Card.Heading>Test Heading</Card.Heading> <Card.Heading>Test Heading</Card.Heading>
</Card> </Card>
); );
@ -22,7 +22,7 @@ describe('Card', () => {
describe('Card Actions', () => { describe('Card Actions', () => {
it('Children should be disabled or enabled according to Card disabled prop', () => { it('Children should be disabled or enabled according to Card disabled prop', () => {
const { rerender } = render( const { rerender } = render(
<Card> <Card noMargin>
<Card.Heading>Test Heading</Card.Heading> <Card.Heading>Test Heading</Card.Heading>
<Card.Actions> <Card.Actions>
<Button>Click Me</Button> <Button>Click Me</Button>
@ -37,7 +37,7 @@ describe('Card', () => {
expect(screen.getByRole('button', { name: 'Delete' })).toBeEnabled(); expect(screen.getByRole('button', { name: 'Delete' })).toBeEnabled();
rerender( rerender(
<Card disabled> <Card noMargin disabled>
<Card.Heading>Test Heading</Card.Heading> <Card.Heading>Test Heading</Card.Heading>
<Card.Actions> <Card.Actions>
<Button>Click Me</Button> <Button>Click Me</Button>
@ -54,7 +54,7 @@ describe('Card', () => {
it('Children should be independently enabled or disabled if explicitly set', () => { it('Children should be independently enabled or disabled if explicitly set', () => {
const { rerender } = render( const { rerender } = render(
<Card> <Card noMargin>
<Card.Heading>Test Heading</Card.Heading> <Card.Heading>Test Heading</Card.Heading>
<Card.Actions> <Card.Actions>
<Button disabled>Click Me</Button> <Button disabled>Click Me</Button>
@ -69,7 +69,7 @@ describe('Card', () => {
expect(screen.getByRole('button', { name: 'Delete' })).toBeDisabled(); expect(screen.getByRole('button', { name: 'Delete' })).toBeDisabled();
rerender( rerender(
<Card disabled> <Card noMargin disabled>
<Card.Heading>Test Heading</Card.Heading> <Card.Heading>Test Heading</Card.Heading>
<Card.Actions> <Card.Actions>
<Button disabled={false}>Click Me</Button> <Button disabled={false}>Click Me</Button>
@ -87,7 +87,7 @@ describe('Card', () => {
it('Children should be conditional', () => { it('Children should be conditional', () => {
const shouldNotRender = false; const shouldNotRender = false;
render( render(
<Card> <Card noMargin>
<Card.Heading>Test Heading</Card.Heading> <Card.Heading>Test Heading</Card.Heading>
<Card.Actions> <Card.Actions>
<Button>Click Me</Button> <Button>Click Me</Button>
@ -105,7 +105,7 @@ describe('Card', () => {
it('Should allow selectable cards', () => { it('Should allow selectable cards', () => {
const { rerender } = render( const { rerender } = render(
<Card isSelected={true}> <Card noMargin isSelected={true}>
<Card.Heading>My Option</Card.Heading> <Card.Heading>My Option</Card.Heading>
</Card> </Card>
); );
@ -114,7 +114,7 @@ describe('Card', () => {
expect(screen.getByRole('radio')).toBeChecked(); expect(screen.getByRole('radio')).toBeChecked();
rerender( rerender(
<Card isSelected={false}> <Card noMargin isSelected={false}>
<Card.Heading>My Option</Card.Heading> <Card.Heading>My Option</Card.Heading>
</Card> </Card>
); );
@ -123,7 +123,7 @@ describe('Card', () => {
expect(screen.getByRole('radio')).not.toBeChecked(); expect(screen.getByRole('radio')).not.toBeChecked();
rerender( rerender(
<Card> <Card noMargin>
<Card.Heading>My Option</Card.Heading> <Card.Heading>My Option</Card.Heading>
</Card> </Card>
); );

View File

@ -226,7 +226,7 @@ export const ThemeDemo = () => {
Disabled Disabled
</Button> </Button>
</Stack> </Stack>
<Card> <Card noMargin>
<Card.Heading>Button inside card</Card.Heading> <Card.Heading>Button inside card</Card.Heading>
<Card.Actions> <Card.Actions>
{allButtonVariants.map((variant) => ( {allButtonVariants.map((variant) => (
@ -259,8 +259,8 @@ export function VizHuesDemo({ theme, color }: VizHuesDemoProps) {
return ( return (
<tr> <tr>
<td>{color.name}</td> <td>{color.name}</td>
{color.shades.map((shade) => ( {color.shades.map((shade, index) => (
<td> <td key={index}>
<div <div
className={css({ className={css({
background: shade.color, background: shade.color,