Commit 014e7d92 by Alex Khomenko Committed by GitHub

Granfana ui/tag components (#22964)

* Add Tag component

* Add Tag story

* Add TagList

* Group Tab and TabList

* Fix typechecks

* Remove Meta

* Use forwardRef for the Tag

* Add actions instead of console.log

* Add previews
parent 289a5fb8
import { Story, Preview, Props } from '@storybook/addon-docs/blocks';
import { Tag } from './Tag';
# Tag
Used for displaying metadata, for example to add more details to search results. Background and border colors are generated from the tag name.
<Preview>
<div>
<Tag name='Tag' onClick={(name) => console.log(name)} />
</div>
</Preview>
### Usage
```jsx
import { Tag } from '@grafana/ui';
<Tag name='Tag' onClick={(name) => console.log(name)} />
```
### Props
<Props of={Tag} />
import React from 'react';
import { action } from '@storybook/addon-actions';
import { Tag } from './Tag';
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
import mdx from './Tag.mdx';
export default {
title: 'General/Tags/Tag',
component: Tag,
decorators: [withCenteredStory],
parameters: {
docs: {
page: mdx,
},
},
};
export const single = () => {
return <Tag name="Tag" onClick={action('Tag clicked')} />;
};
import React, { forwardRef, HTMLAttributes } from 'react';
import { cx, css } from 'emotion';
import { GrafanaTheme } from '@grafana/data';
import { useTheme } from '../../themes';
import { getTagColorsFromName } from '../../utils';
export interface Props extends Omit<HTMLAttributes<HTMLElement>, 'onClick'> {
/** Name of the tag to display */
name: string;
onClick?: (name: string) => any;
}
export const Tag = forwardRef<HTMLElement, Props>(({ name, onClick, className, ...rest }, ref) => {
const theme = useTheme();
const styles = getTagStyles(theme, name);
const onTagClick = () => {
if (onClick) {
onClick(name);
}
};
return (
<span key={name} ref={ref} onClick={onTagClick} className={cx(styles.wrapper, className)} {...rest}>
{name}
</span>
);
});
const getTagStyles = (theme: GrafanaTheme, name: string) => {
const { borderColor, color } = getTagColorsFromName(name);
return {
wrapper: css`
font-weight: ${theme.typography.weight.semibold};
font-size: ${theme.typography.size.sm};
line-height: ${theme.typography.lineHeight.xs};
vertical-align: baseline;
background-color: ${color};
color: ${theme.colors.white};
white-space: nowrap;
text-shadow: none;
padding: 3px 6px;
border: 1px solid ${borderColor};
border-radius: ${theme.border.radius.md};
:hover {
opacity: 0.85;
cursor: pointer;
}
`,
};
};
import { Story, Preview, Props } from '@storybook/addon-docs/blocks';
import { TagList } from './TagList';
# TagList
List of tags with predefined margins and positioning.
<Preview>
<TagList tags={['datasource-test', 'gdev', 'mysql', 'mssql']} />
</Preview>
### Usage
```jsx
import { TagList } from '@grafana/ui';
const tags = ['datasource-test', 'gdev', 'mysql', 'mssql'];
<TagList tags={tags} onClick={tag => console.log(tag)} />
```
### Props
<Props of={TagList} />
import React from 'react';
import { action } from '@storybook/addon-actions';
import { TagList } from './TagList';
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
import mdx from './TagList.mdx';
export default {
title: 'General/Tags/TagList',
component: TagList,
decorators: [withCenteredStory],
parameters: {
docs: {
page: mdx,
},
},
};
const tags = ['datasource-test', 'gdev', 'mysql', 'mssql'];
export const list = () => {
return (
<div style={{ width: 300 }}>
<TagList tags={tags} onClick={action('Tag clicked')} />
</div>
);
};
import React, { FC } from 'react';
import { cx, css } from 'emotion';
import { Tag } from './Tag';
export interface Props {
tags: string[];
onClick?: (name: string) => any;
/** Custom styles for the wrapper component */
className?: string;
}
export const TagList: FC<Props> = ({ tags, onClick, className }) => {
const styles = getStyles();
return (
<span className={cx(styles.wrapper, className)}>
{tags.map(tag => (
<Tag key={tag} name={tag} onClick={onClick} className={styles.tag} />
))}
</span>
);
};
const getStyles = () => {
return {
wrapper: css`
display: flex;
flex: 1 1 auto;
flex-wrap: wrap;
padding: 10px;
`,
tag: css`
margin-left: 6px;
font-size: 11px;
padding: 2px 6px;
`,
};
};
......@@ -41,6 +41,8 @@ export { TimeOfDayPicker } from './TimePicker/TimeOfDayPicker';
export { List } from './List/List';
export { TagsInput } from './TagsInput/TagsInput';
export { Pagination } from './Pagination/Pagination';
export { Tag } from './Tags/Tag';
export { TagList } from './Tags/TagList';
export { ConfirmModal } from './ConfirmModal/ConfirmModal';
export { QueryField } from './QueryField/QueryField';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment