diff --git a/packages/grafana-ui/src/components/LoadingBar/LoadingBar.mdx b/packages/grafana-ui/src/components/LoadingBar/LoadingBar.mdx new file mode 100644 index 00000000000..563adb0662a --- /dev/null +++ b/packages/grafana-ui/src/components/LoadingBar/LoadingBar.mdx @@ -0,0 +1,22 @@ +import { Meta, Preview, ArgsTable } from '@storybook/addon-docs/blocks'; +import { LoadingBar } from './LoadingBar'; + + + +# LoadingBar + +The LoadingBar is used as a simple loading slider animation in the top of its container. + + +
+ +
+
+ +```jsx +
+ +
+``` + + diff --git a/packages/grafana-ui/src/components/LoadingBar/LoadingBar.story.tsx b/packages/grafana-ui/src/components/LoadingBar/LoadingBar.story.tsx new file mode 100644 index 00000000000..f839a8d71a0 --- /dev/null +++ b/packages/grafana-ui/src/components/LoadingBar/LoadingBar.story.tsx @@ -0,0 +1,56 @@ +import { css } from '@emotion/css'; +import { ComponentMeta, ComponentStory } from '@storybook/react'; +import React from 'react'; + +import { GrafanaTheme2 } from '@grafana/data'; +import { LoadingBar, LoadingBarProps, useStyles2 } from '@grafana/ui'; + +import { DashboardStoryCanvas } from '../../utils/storybook/DashboardStoryCanvas'; +import { withCenteredStory } from '../../utils/storybook/withCenteredStory'; + +import mdx from './LoadingBar.mdx'; + +const meta: ComponentMeta = { + title: 'General/LoadingBar', + component: LoadingBar, + decorators: [withCenteredStory], + parameters: { + controls: {}, + docs: { + page: mdx, + }, + }, +}; + +const getStyles = (theme: GrafanaTheme2) => { + const { borderColor } = theme.components.panel; + + return { + container: css({ + label: 'placeholder-container', + width: '400px', + height: '200px', + border: `1px solid ${borderColor}`, + borderRadius: '3px', + }), + }; +}; + +export const Basic: ComponentStory = (args: LoadingBarProps) => { + const styles = useStyles2(getStyles); + + return ( + +
+ +
+
+ ); +}; + +Basic.args = { + width: '128px', + height: '2px', +}; + +export default meta; diff --git a/packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx b/packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx new file mode 100644 index 00000000000..dd3fbcd272c --- /dev/null +++ b/packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx @@ -0,0 +1,49 @@ +import { css, keyframes } from '@emotion/css'; +import React from 'react'; + +import { GrafanaTheme2 } from '@grafana/data'; + +import { useStyles2 } from '../../themes'; + +export interface LoadingBarProps { + width?: string; + height?: string; + ariaLabel?: string; +} + +export function LoadingBar({ width, height, ariaLabel = 'Loading bar' }: LoadingBarProps) { + const styles = useStyles2(getStyles(width, height)); + + return ( +
+
+
+ ); +} + +const getStyles = (width?: string, height?: string) => (_: GrafanaTheme2) => { + const barWidth = width ?? '128px'; + const loadingHeigth = height ?? '2px'; + + const loadingAnimation = keyframes({ + '0%': { + transform: 'translateX(0)', + }, + '100%': { + transform: `translateX(calc(100% - ${barWidth}))`, + }, + }); + + return { + container: css({ + width: '100%', + animation: `${loadingAnimation} 1s infinite linear`, + willChange: 'transform', + }), + bar: css({ + width: barWidth, + height: loadingHeigth, + background: 'linear-gradient(90deg, rgba(110, 159, 255, 0) 0%, #6E9FFF 80.75%, rgba(110, 159, 255, 0) 100%)', + }), + }; +}; diff --git a/packages/grafana-ui/src/components/index.ts b/packages/grafana-ui/src/components/index.ts index 8497191c78f..f50b4610d48 100644 --- a/packages/grafana-ui/src/components/index.ts +++ b/packages/grafana-ui/src/components/index.ts @@ -24,6 +24,7 @@ export { ButtonCascader } from './ButtonCascader/ButtonCascader'; export { InlineToast } from './InlineToast/InlineToast'; export { LoadingPlaceholder, type LoadingPlaceholderProps } from './LoadingPlaceholder/LoadingPlaceholder'; +export { LoadingBar, type LoadingBarProps } from './LoadingBar/LoadingBar'; export { ColorPicker, SeriesColorPicker } from './ColorPicker/ColorPicker'; export { ColorPickerInput } from './ColorPicker/ColorPickerInput'; export { SeriesColorPickerPopover, SeriesColorPickerPopoverWithTheme } from './ColorPicker/SeriesColorPickerPopover';