diff --git a/packages/grafana-ui/src/components/VizLayout/VizLayout.story.tsx b/packages/grafana-ui/src/components/VizLayout/VizLayout.story.tsx new file mode 100644 index 00000000000..94d2cd8bb9b --- /dev/null +++ b/packages/grafana-ui/src/components/VizLayout/VizLayout.story.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { withCenteredStory } from '../../utils/storybook/withCenteredStory'; +import { number } from '@storybook/addon-knobs'; +import { VizLayout } from './VizLayout'; + +export default { + title: 'Visualizations/VizLayout', + component: VizLayout, + decorators: [withCenteredStory], + parameters: { + docs: {}, + }, +}; + +const getKnobs = () => { + return { + legendWidth: number('legendWidth', 100), + legendItems: number('legendItems', 2), + }; +}; + +export const BottomLegend = () => { + const { legendItems } = getKnobs(); + const items = Array.from({ length: legendItems }, (_, i) => i + 1); + + const legend = ( + + {items.map((_, index) => ( +
+ Legend item {index} +
+ ))} +
+ ); + + return ( + + {(vizWidth: number, vizHeight: number) => { + return
; + }} + + ); +}; + +export const RightLegend = () => { + const { legendItems, legendWidth } = getKnobs(); + const items = Array.from({ length: legendItems }, (_, i) => i + 1); + + const legend = ( + + {items.map((_, index) => ( +
+ Legend item {index} +
+ ))} +
+ ); + + return ( + + {(vizWidth: number, vizHeight: number) => { + return
; + }} + + ); +}; diff --git a/packages/grafana-ui/src/components/VizLayout/VizLayout.tsx b/packages/grafana-ui/src/components/VizLayout/VizLayout.tsx new file mode 100644 index 00000000000..692757540b4 --- /dev/null +++ b/packages/grafana-ui/src/components/VizLayout/VizLayout.tsx @@ -0,0 +1,99 @@ +import React, { FC, CSSProperties, ComponentType } from 'react'; +import { useMeasure } from 'react-use'; +import CustomScrollbar from '../CustomScrollbar/CustomScrollbar'; + +/** + * @beta + */ +export interface VizLayoutProps { + width: number; + height: number; + legend?: React.ReactElement; + children: (width: number, height: number) => React.ReactNode; +} + +/** + * @beta + */ +export interface VizLayoutComponentType extends FC { + Legend: ComponentType; +} + +/** + * @beta + */ +export const VizLayout: VizLayoutComponentType = ({ width, height, legend, children }) => { + const containerStyle: CSSProperties = { + display: 'flex', + width: `${width}px`, + height: `${height}px`, + }; + + if (!legend) { + return
{children(width, height)}
; + } + + const { position, maxHeight, maxWidth } = legend.props; + const [legendRef, legendMeasure] = useMeasure(); + let size: VizSize | null = null; + + const vizStyle: CSSProperties = { + flexGrow: 1, + }; + + const legendStyle: CSSProperties = { + flexGrow: 1, + }; + + switch (position) { + case 'bottom': + containerStyle.flexDirection = 'column'; + legendStyle.maxHeight = maxHeight; + + if (legendMeasure) { + size = { width, height: height - legendMeasure.height }; + } + break; + case 'right': + containerStyle.flexDirection = 'row'; + legendStyle.maxWidth = maxWidth; + + if (legendMeasure) { + size = { width: width - legendMeasure.width, height }; + } + break; + } + + return ( +
+
{size && children(size.width, size.height)}
+
+ {legend} +
+
+ ); +}; + +interface VizSize { + width: number; + height: number; +} + +/** + * @beta + */ +export interface VizLayoutLegendProps { + position: 'bottom' | 'right'; + maxHeight?: string; + maxWidth?: string; + children: React.ReactNode; +} + +/** + * @beta + */ +export const VizLayoutLegend: FC = ({ children }) => { + return <>{children}; +}; + +VizLayout.Legend = VizLayoutLegend; diff --git a/packages/grafana-ui/src/components/index.ts b/packages/grafana-ui/src/components/index.ts index 0c6d2421375..0a0def694c8 100644 --- a/packages/grafana-ui/src/components/index.ts +++ b/packages/grafana-ui/src/components/index.ts @@ -78,6 +78,7 @@ export { BarGauge, BarGaugeDisplayMode } from './BarGauge/BarGauge'; export { GraphTooltipOptions } from './Graph/GraphTooltip/types'; export { VizRepeater, VizRepeaterRenderValueProps } from './VizRepeater/VizRepeater'; export { graphTimeFormat, graphTickFormatter } from './Graph/utils'; +export { VizLayout, VizLayoutComponentType, VizLayoutLegendProps, VizLayoutProps } from './VizLayout/VizLayout'; export { LegendOptions,