From 47f70bdb000b286fa1798902775c239c0fea31cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Fern=C3=A1ndez?= Date: Thu, 20 Jul 2023 12:59:42 +0200 Subject: [PATCH] GLDS: Text component (#71439) --- .../src/components/Drawer/Drawer.tsx | 2 +- .../src/components/Link/TextLink.story.tsx | 10 +- .../components/Text/Text.internal.story.tsx | 110 +++++++----------- .../src/components/Text/Text.test.tsx | 6 +- .../grafana-ui/src/components/Text/Text.tsx | 28 +++-- .../src/components/Text/TextElements.tsx | 75 ------------ .../grafana-ui/src/components/Text/utils.ts | 31 ++++- packages/grafana-ui/src/unstable.ts | 2 +- .../AppChrome/News/NewsContainer.tsx | 4 +- .../NestedFolderPicker/NestedFolderList.tsx | 5 +- .../NestedFolderPicker/NestedFolderPicker.tsx | 4 +- .../core/components/Page/EditableTitle.tsx | 6 +- .../alerting/unified/components/MetaText.tsx | 8 +- .../contact-points/ContactPoints.v2.tsx | 16 +-- .../notification-policies/Policy.tsx | 10 +- .../NotificationPreview.tsx | 4 +- .../QueryAndExpressionsStep.tsx | 6 +- .../rule-viewer/v2/RuleViewer.v2.tsx | 26 ++--- .../components/BrowseActions/DeleteModal.tsx | 6 +- .../BrowseActions/DescendantCount.tsx | 6 +- .../components/BrowseActions/MoveModal.tsx | 6 +- .../browse-dashboards/components/NameCell.tsx | 10 +- .../dashboard/dashgrid/DashboardEmpty.tsx | 34 +++--- .../search/page/components/columns.tsx | 6 +- .../datasource/alertmanager/ConfigEditor.tsx | 6 +- 25 files changed, 185 insertions(+), 242 deletions(-) delete mode 100644 packages/grafana-ui/src/components/Text/TextElements.tsx diff --git a/packages/grafana-ui/src/components/Drawer/Drawer.tsx b/packages/grafana-ui/src/components/Drawer/Drawer.tsx index 7171caac2e8..265fff11e97 100644 --- a/packages/grafana-ui/src/components/Drawer/Drawer.tsx +++ b/packages/grafana-ui/src/components/Drawer/Drawer.tsx @@ -125,7 +125,7 @@ export function Drawer({ />
- + {title} {subtitle &&
{subtitle}
} diff --git a/packages/grafana-ui/src/components/Link/TextLink.story.tsx b/packages/grafana-ui/src/components/Link/TextLink.story.tsx index d6d826e2274..a4dcdc74a31 100644 --- a/packages/grafana-ui/src/components/Link/TextLink.story.tsx +++ b/packages/grafana-ui/src/components/Link/TextLink.story.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { StoryExample } from '../../utils/storybook/StoryExample'; import { VerticalGroup } from '../Layout/Layout'; -import { P } from '../Text/TextElements'; +import { Text } from '../Text/Text'; import { TextLink } from './TextLink'; import mdx from './TextLink.mdx'; @@ -44,13 +44,13 @@ export const Example: StoryFn = (args) => { return ( -

+ To get started with a forever free Grafana Cloud account, sign up at   grafana.com . -

+
@@ -58,7 +58,9 @@ export const Example: StoryFn = (args) => {
-

*The examples cannot contemplate an internal link due to conflicts between Storybook and React Router

+ + *The examples cannot contemplate an internal link due to conflicts between Storybook and React Router + ); }; diff --git a/packages/grafana-ui/src/components/Text/Text.internal.story.tsx b/packages/grafana-ui/src/components/Text/Text.internal.story.tsx index 14367f713df..e3ea5b5eea9 100644 --- a/packages/grafana-ui/src/components/Text/Text.internal.story.tsx +++ b/packages/grafana-ui/src/components/Text/Text.internal.story.tsx @@ -6,7 +6,6 @@ import { VerticalGroup } from '../Layout/Layout'; import { Text } from './Text'; import mdx from './Text.mdx'; -import { H1, H2, H3, H4, H5, H6, Span, P, Legend, TextModifier } from './TextElements'; const meta: Meta = { title: 'General/Text', @@ -15,7 +14,6 @@ const meta: Meta = { docs: { page: mdx, }, - controls: { exclude: ['as'] }, }, argTypes: { variant: { control: 'select', options: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'body', 'bodySmall', undefined] }, @@ -39,93 +37,73 @@ const meta: Meta = { ], }, truncate: { control: 'boolean' }, + italic: { control: 'boolean' }, textAlignment: { control: 'select', options: ['inherit', 'initial', 'left', 'right', 'center', 'justify', undefined], }, }, + args: { + element: 'h1', + variant: undefined, + weight: 'light', + textAlignment: 'left', + truncate: false, + italic: false, + color: 'primary', + children: `This is an example of a Text component`, + }, }; -export const Example: StoryFn = () => { +export const Example: StoryFn = (args) => { return ( - -

h1. Heading

-

h2. Heading

-

h3. Heading

-

h4. Heading

-
h5. Heading
-
h6. Heading
-

This is a paragraph

- This is a legend - This is a span + + + This is a header + + + This is a paragraph that contains + + {' '} + a span element with different color and style{' '} + + but is comprised within the same block text + + + + + This is a paragraph that contains + + {' '} + a span element{' '} + + but has truncate set to true +
); }; Example.parameters = { controls: { - exclude: ['variant', 'weight', 'textAlignment', 'truncate', 'color', 'children'], + exclude: ['element', 'variant', 'weight', 'textAlignment', 'truncate', 'italic', 'color', 'children'], }, }; -export const HeadingComponent: StoryFn = (args) => { +export const Basic: StoryFn = (args) => { return (
-

+ {args.children} -

+
); }; -HeadingComponent.args = { - variant: undefined, - weight: 'light', - textAlignment: 'center', - truncate: false, - color: 'primary', - children: 'This is a H1 component', -}; - -export const LegendComponent: StoryFn = (args) => { - return ( -
- - {args.children} - -
- ); -}; - -LegendComponent.args = { - variant: undefined, - weight: 'bold', - textAlignment: 'center', - truncate: false, - color: 'error', - children: 'This is a lengend component', -}; - -export const TextModifierComponent: StoryFn = (args) => { - return ( -
-
- {args.children}{' '} - - {' '} - with a part of its text modified{' '} - -
-
- ); -}; -TextModifierComponent.args = { - variant: undefined, - weight: 'light', - textAlignment: 'center', - truncate: false, - color: 'maxContrast', - children: 'This is a H6 component', -}; export default meta; diff --git a/packages/grafana-ui/src/components/Text/Text.test.tsx b/packages/grafana-ui/src/components/Text/Text.test.tsx index 591211db265..f05d37d06a6 100644 --- a/packages/grafana-ui/src/components/Text/Text.test.tsx +++ b/packages/grafana-ui/src/components/Text/Text.test.tsx @@ -7,13 +7,13 @@ import { Text } from './Text'; describe('Text', () => { it('renders correctly', () => { - render(This is a text component); + render(This is a text component); expect(screen.getByText('This is a text component')).toBeInTheDocument(); }); it('keeps the element type but changes its styles', () => { const customVariant: keyof ThemeTypographyVariantTypes = 'body'; render( - + This is a text component ); @@ -26,7 +26,7 @@ describe('Text', () => { const customColor = 'info'; const theme = createTheme(); render( - + This is a text component ); diff --git a/packages/grafana-ui/src/components/Text/Text.tsx b/packages/grafana-ui/src/components/Text/Text.tsx index d8e7d460c4f..ffcc98fc090 100644 --- a/packages/grafana-ui/src/components/Text/Text.tsx +++ b/packages/grafana-ui/src/components/Text/Text.tsx @@ -5,11 +5,11 @@ import { GrafanaTheme2, ThemeTypographyVariantTypes } from '@grafana/data'; import { useStyles2 } from '../../themes'; -import { customWeight, customColor } from './utils'; +import { customWeight, customColor, customVariant } from './utils'; export interface TextProps { - /** Defines what HTML element is defined underneath */ - as: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'span' | 'p' | 'legend'; + /** Defines what HTML element is defined underneath. "span" by default */ + element?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'span' | 'p'; /** What typograpy variant should be used for the component. Only use if default variant for the defined element is not what is needed */ variant?: keyof ThemeTypographyVariantTypes; /** Override the default weight for the used variant */ @@ -18,22 +18,24 @@ export interface TextProps { color?: keyof GrafanaTheme2['colors']['text'] | 'error' | 'success' | 'warning' | 'info'; /** Use to cut the text off with ellipsis if there isn't space to show all of it. On hover shows the rest of the text */ truncate?: boolean; + /** If true, show the text as italic. False by default */ + italic?: boolean; /** Whether to align the text to left, center or right */ textAlignment?: CSSProperties['textAlign']; children: React.ReactNode; } export const Text = React.forwardRef( - ({ as, variant, weight, color, truncate, textAlignment, children }, ref) => { + ({ element = 'span', variant, weight, color, truncate, italic, textAlignment, children }, ref) => { const styles = useStyles2( useCallback( - (theme) => getTextStyles(theme, variant, color, weight, truncate, textAlignment), - [color, textAlignment, truncate, weight, variant] + (theme) => getTextStyles(theme, element, variant, color, weight, truncate, italic, textAlignment), + [color, textAlignment, truncate, italic, weight, variant, element] ) ); return createElement( - as, + element, { className: styles, ref, @@ -47,19 +49,22 @@ Text.displayName = 'Text'; const getTextStyles = ( theme: GrafanaTheme2, + element?: TextProps['element'], variant?: keyof ThemeTypographyVariantTypes, color?: TextProps['color'], weight?: TextProps['weight'], truncate?: TextProps['truncate'], + italic?: TextProps['italic'], textAlignment?: TextProps['textAlignment'] ) => { return css([ - variant && { - ...theme.typography[variant], - }, { margin: 0, padding: 0, + ...customVariant(theme, element, variant), + }, + variant && { + ...theme.typography[variant], }, color && { color: customColor(color, theme), @@ -72,6 +77,9 @@ const getTextStyles = ( textOverflow: 'ellipsis', whiteSpace: 'nowrap', }, + italic && { + fontStyle: 'italic', + }, textAlignment && { textAlign: textAlignment, }, diff --git a/packages/grafana-ui/src/components/Text/TextElements.tsx b/packages/grafana-ui/src/components/Text/TextElements.tsx deleted file mode 100644 index f0569f9b376..00000000000 --- a/packages/grafana-ui/src/components/Text/TextElements.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import React from 'react'; - -import { GrafanaTheme2 } from '@grafana/data'; - -import { Text, TextProps } from './Text'; - -interface TextElementsProps extends Omit {} - -interface TextModifierProps { - /** Override the default weight for the used variant */ - weight?: 'light' | 'regular' | 'medium' | 'bold'; - /** Color to use for text */ - color?: keyof GrafanaTheme2['colors']['text'] | 'error' | 'success' | 'warning' | 'info'; - children: React.ReactNode; -} - -export const H1 = React.forwardRef((props, ref) => { - return ; -}); - -H1.displayName = 'H1'; - -export const H2 = React.forwardRef((props, ref) => { - return ; -}); - -H2.displayName = 'H2'; - -export const H3 = React.forwardRef((props, ref) => { - return ; -}); - -H3.displayName = 'H3'; - -export const H4 = React.forwardRef((props, ref) => { - return ; -}); - -H4.displayName = 'H4'; - -export const H5 = React.forwardRef((props, ref) => { - return ; -}); - -H5.displayName = 'H5'; - -export const H6 = React.forwardRef((props, ref) => { - return ; -}); - -H6.displayName = 'H6'; - -export const P = React.forwardRef((props, ref) => { - return ; -}); - -P.displayName = 'P'; - -export const Span = React.forwardRef((props, ref) => { - return ; -}); - -Span.displayName = 'Span'; - -export const Legend = React.forwardRef((props, ref) => { - return ; -}); - -Legend.displayName = 'Legend'; - -export const TextModifier = React.forwardRef((props, ref) => { - return ; -}); - -TextModifier.displayName = 'TextModifier'; diff --git a/packages/grafana-ui/src/components/Text/utils.ts b/packages/grafana-ui/src/components/Text/utils.ts index 650e6ecae74..5e28195e1a9 100644 --- a/packages/grafana-ui/src/components/Text/utils.ts +++ b/packages/grafana-ui/src/components/Text/utils.ts @@ -1,4 +1,4 @@ -import { GrafanaTheme2 } from '@grafana/data'; +import { GrafanaTheme2, ThemeTypographyVariantTypes } from '@grafana/data'; import { TextProps } from './Text'; @@ -30,3 +30,32 @@ export const customColor = (color: TextProps['color'], theme: GrafanaTheme2): st return color ? theme.colors.text[color] : undefined; } }; + +export const customVariant = ( + theme: GrafanaTheme2, + element: TextProps['element'], + variant?: keyof ThemeTypographyVariantTypes +) => { + if (variant) { + return theme.typography[variant]; + } + switch (element) { + //Span elements does not have a default variant to be able to take the parents style + case 'span': + return; + case 'h1': + return theme.typography.h1; + case 'h2': + return theme.typography.h2; + case 'h3': + return theme.typography.h3; + case 'h4': + return theme.typography.h4; + case 'h5': + return theme.typography.h5; + case 'h6': + return theme.typography.h6; + default: + return theme.typography.body; + } +}; diff --git a/packages/grafana-ui/src/unstable.ts b/packages/grafana-ui/src/unstable.ts index 7941d6a0e6d..3a2dd5f6632 100644 --- a/packages/grafana-ui/src/unstable.ts +++ b/packages/grafana-ui/src/unstable.ts @@ -9,4 +9,4 @@ * be subject to the standard policies */ -export * from './components/Text/TextElements'; +export * from './components/Text/Text'; diff --git a/public/app/core/components/AppChrome/News/NewsContainer.tsx b/public/app/core/components/AppChrome/News/NewsContainer.tsx index da7c096702b..56227837b09 100644 --- a/public/app/core/components/AppChrome/News/NewsContainer.tsx +++ b/public/app/core/components/AppChrome/News/NewsContainer.tsx @@ -5,7 +5,7 @@ import { useToggle } from 'react-use'; import { GrafanaTheme2 } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; import { Button, Drawer, ToolbarButton, useStyles2 } from '@grafana/ui'; -import { H3 } from '@grafana/ui/src/unstable'; +import { Text } from '@grafana/ui/src/unstable'; import { t } from 'app/core/internationalization'; import { DEFAULT_FEED_URL } from 'app/plugins/panel/news/constants'; @@ -26,7 +26,7 @@ export function NewsContainer({ className }: NewsContainerProps) { -

{t('news.title', 'Latest from the blog')}

+ {t('news.title', 'Latest from the blog')} - - {item.title} - + {/* TODO: text is not truncated properly, it still overflows the container */} + {item.title}
diff --git a/public/app/core/components/NestedFolderPicker/NestedFolderPicker.tsx b/public/app/core/components/NestedFolderPicker/NestedFolderPicker.tsx index 1ba8b3fbd75..eaa737f69e6 100644 --- a/public/app/core/components/NestedFolderPicker/NestedFolderPicker.tsx +++ b/public/app/core/components/NestedFolderPicker/NestedFolderPicker.tsx @@ -7,7 +7,7 @@ import { useAsync } from 'react-use'; import { GrafanaTheme2 } from '@grafana/data'; import { Alert, Button, Icon, Input, LoadingBar, useStyles2 } from '@grafana/ui'; import { Text } from '@grafana/ui/src/components/Text/Text'; -import { Trans, t } from 'app/core/internationalization'; +import { t, Trans } from 'app/core/internationalization'; import { skipToken, useGetFolderQuery } from 'app/features/browse-dashboards/api/browseDashboardsAPI'; import { PAGE_SIZE } from 'app/features/browse-dashboards/api/services'; import { @@ -209,7 +209,7 @@ export function NestedFolderPicker({ value, onChange }: NestedFolderPickerProps) {selectedFolder.isLoading ? ( ) : ( - + {label ?? Select folder} )} diff --git a/public/app/core/components/Page/EditableTitle.tsx b/public/app/core/components/Page/EditableTitle.tsx index caf051ddd5a..dc07826075d 100644 --- a/public/app/core/components/Page/EditableTitle.tsx +++ b/public/app/core/components/Page/EditableTitle.tsx @@ -4,7 +4,7 @@ import React, { useCallback, useEffect, useState } from 'react'; import { GrafanaTheme2 } from '@grafana/data'; import { isFetchError } from '@grafana/runtime'; import { Field, IconButton, Input, useStyles2 } from '@grafana/ui'; -import { H1 } from '@grafana/ui/src/unstable'; +import { Text } from '@grafana/ui/src/unstable'; export interface Props { value: string; @@ -61,7 +61,9 @@ export const EditableTitle = ({ value, onEdit }: Props) => { this is to prevent the title from flickering back to the old value after the user has edited caused by the delay between the save completing and the new value being refetched */} -

{localValue}

+ + {localValue} + setIsEditing(true)} /> diff --git a/public/app/features/alerting/unified/components/MetaText.tsx b/public/app/features/alerting/unified/components/MetaText.tsx index 3c1ed4a348a..d74d9bfd604 100644 --- a/public/app/features/alerting/unified/components/MetaText.tsx +++ b/public/app/features/alerting/unified/components/MetaText.tsx @@ -3,11 +3,11 @@ import React, { ComponentProps, HTMLAttributes } from 'react'; import { Stack } from '@grafana/experimental'; import { Icon, IconName, useStyles2 } from '@grafana/ui'; -import { Span } from '@grafana/ui/src/unstable'; +import { Text } from '@grafana/ui/src/unstable'; interface Props extends HTMLAttributes { icon?: IconName; - color?: ComponentProps['color']; + color?: ComponentProps['color']; } const MetaText = ({ children, icon, color = 'secondary', ...rest }: Props) => { @@ -22,12 +22,12 @@ const MetaText = ({ children, icon, color = 'secondary', ...rest }: Props) => { // allow passing ARIA and data- attributes {...rest} > - + {icon && } {children} - +
); }; diff --git a/public/app/features/alerting/unified/components/contact-points/ContactPoints.v2.tsx b/public/app/features/alerting/unified/components/contact-points/ContactPoints.v2.tsx index 77582420a80..4c10828a51a 100644 --- a/public/app/features/alerting/unified/components/contact-points/ContactPoints.v2.tsx +++ b/public/app/features/alerting/unified/components/contact-points/ContactPoints.v2.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { GrafanaTheme2 } from '@grafana/data'; import { Stack } from '@grafana/experimental'; import { Button, Dropdown, Icon, Menu, Tooltip, useStyles2 } from '@grafana/ui'; -import { Span } from '@grafana/ui/src/unstable'; +import { Text } from '@grafana/ui/src/unstable'; import ConditionalWrap from 'app/features/alerting/components/ConditionalWrap'; import { GrafanaNotifierType } from 'app/types/alerting'; @@ -104,7 +104,7 @@ const ContactPointHeader = (props: ContactPointHeaderProps) => {
- {name} + {name} {policies.length > 0 ? ( @@ -179,14 +179,14 @@ const ContactPointReceiver = (props: ContactPointReceiverProps) => { {iconName && } - + {type} - + {description && ( - + {description} - + )}
@@ -196,7 +196,7 @@ const ContactPointReceiver = (props: ContactPointReceiverProps) => { <> {/* TODO we might need an error variant for MetaText, dito for success */} {/* TODO show error details on hover or elsewhere */} - + { - + ) : ( <> diff --git a/public/app/features/alerting/unified/components/notification-policies/Policy.tsx b/public/app/features/alerting/unified/components/notification-policies/Policy.tsx index 3c49262aa22..b01f16ef53d 100644 --- a/public/app/features/alerting/unified/components/notification-policies/Policy.tsx +++ b/public/app/features/alerting/unified/components/notification-policies/Policy.tsx @@ -7,7 +7,7 @@ import { Link } from 'react-router-dom'; import { GrafanaTheme2 } from '@grafana/data'; import { Stack } from '@grafana/experimental'; import { Badge, Button, Dropdown, getTagColorsFromName, Icon, Menu, Tooltip, useStyles2 } from '@grafana/ui'; -import { Span } from '@grafana/ui/src/unstable'; +import { Text } from '@grafana/ui/src/unstable'; import { contextSrv } from 'app/core/core'; import ConditionalWrap from 'app/features/alerting/components/ConditionalWrap'; import { RouteWithID, Receiver, ObjectMatcher, AlertmanagerGroup } from 'app/plugins/datasource/alertmanager/types'; @@ -554,17 +554,17 @@ const routePropertyToValue = ( if (isNotGrouping) { return ( - + Not grouping - + ); } if (isSingleGroup) { return ( - + Single group - + ); } diff --git a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPreview.tsx b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPreview.tsx index b625e659b98..68cc401bb90 100644 --- a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPreview.tsx +++ b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPreview.tsx @@ -4,7 +4,7 @@ import React, { lazy, Suspense } from 'react'; import { GrafanaTheme2 } from '@grafana/data'; import { Button, LoadingPlaceholder, useStyles2 } from '@grafana/ui'; -import { H4 } from '@grafana/ui/src/unstable'; +import { Text } from '@grafana/ui/src/unstable'; import { alertRuleApi } from 'app/features/alerting/unified/api/alertRuleApi'; import { Stack } from 'app/plugins/datasource/parca/QueryEditor/Stack'; import { AlertQuery } from 'app/types/unified-alerting-dto'; @@ -67,7 +67,7 @@ export const NotificationPreview = ({
-

Alert instance routing preview

+ Alert instance routing preview
-

+ Import panel -

+
-

+ Import visualizations that are shared with other dashboards. -

+
{options.jsonData.handleGrafanaManagedAlerts && ( - + Make sure to enable the alert forwarding on the admin page. - + )}