UNPKG

@gitlab/ui

Version:
266 lines (257 loc) • 11.4 kB
import { GL_FONT_FAMILY_REGULAR, GL_COLOR_NEUTRAL_100, GL_COLOR_DATA_BLUE_500, GL_COLOR_DATA_BLUE_600, GL_COLOR_DATA_BLUE_800, GL_COLOR_DATA_BLUE_950, GL_COLOR_NEUTRAL_800, GL_COLOR_DATA_BLUE_400, GL_COLOR_DATA_BLUE_200, GL_COLOR_NEUTRAL_0, GL_COLOR_NEUTRAL_950, GL_COLOR_DATA_BLUE_900, GL_COLOR_DATA_ORANGE_500, GL_COLOR_DATA_ORANGE_600, GL_COLOR_DATA_AQUA_500, GL_COLOR_DATA_GREEN_600, GL_COLOR_DATA_MAGENTA_500, GL_COLOR_DATA_BLUE_700, GL_COLOR_DATA_ORANGE_800, GL_COLOR_DATA_AQUA_700, GL_COLOR_DATA_GREEN_800, GL_COLOR_DATA_MAGENTA_700, GL_COLOR_DATA_ORANGE_950, GL_COLOR_DATA_AQUA_900, GL_COLOR_DATA_GREEN_950, GL_COLOR_DATA_MAGENTA_900, GL_COLOR_DATA_ORANGE_700, GL_COLOR_DATA_AQUA_600, GL_COLOR_DATA_GREEN_700, GL_COLOR_DATA_MAGENTA_600, GL_COLOR_DATA_ORANGE_900, GL_COLOR_DATA_AQUA_800, GL_COLOR_DATA_GREEN_900, GL_COLOR_DATA_MAGENTA_800, GL_COLOR_DATA_AQUA_950, GL_COLOR_DATA_GREEN_500, GL_COLOR_DATA_MAGENTA_950, GL_COLOR_DATA_ORANGE_400, GL_COLOR_DATA_GREEN_400, GL_COLOR_DATA_BLUE_300, GL_COLOR_DATA_ORANGE_200, GL_COLOR_DATA_AQUA_300, GL_COLOR_DATA_GREEN_200, GL_COLOR_DATA_MAGENTA_300, GL_COLOR_DATA_BLUE_100, GL_COLOR_DATA_ORANGE_50, GL_COLOR_DATA_AQUA_100, GL_COLOR_DATA_GREEN_50, GL_COLOR_DATA_MAGENTA_100, GL_COLOR_DATA_ORANGE_300, GL_COLOR_DATA_AQUA_400, GL_COLOR_DATA_GREEN_300, GL_COLOR_DATA_MAGENTA_400, GL_COLOR_DATA_ORANGE_100, GL_COLOR_DATA_AQUA_200, GL_COLOR_DATA_GREEN_100, GL_COLOR_DATA_MAGENTA_200, GL_COLOR_DATA_BLUE_50, GL_COLOR_DATA_AQUA_50, GL_COLOR_DATA_MAGENTA_50, GL_COLOR_NEUTRAL_50 } from '../../tokens/build/js/tokens'; import { scrollHandleSvgPath, marqueeSelectionSvgPath, redoSvgPath, clearAllSvgPath, downloadSvgPath } from '../svgs/svg_paths'; import { defaultFontSize } from './config'; const GL_BORDER_RADIUS_BASE = '0.25rem'; const themeName = 'gitlab'; /** * Sequential scales step away from the surface so that higher values gain contrast against it: * darker on a light surface, lighter on a dark one. The lowest step is neutral rather than blue, so * that "no data" reads as absence instead of as the bottom of the data range. * * https://design.gitlab.com/data-visualization/color#sequential-data */ const heatmapHues = [GL_COLOR_NEUTRAL_100, GL_COLOR_DATA_BLUE_500, GL_COLOR_DATA_BLUE_600, GL_COLOR_DATA_BLUE_800, GL_COLOR_DATA_BLUE_950]; const heatmapHuesDark = [GL_COLOR_NEUTRAL_800, GL_COLOR_DATA_BLUE_600, GL_COLOR_DATA_BLUE_500, GL_COLOR_DATA_BLUE_400, GL_COLOR_DATA_BLUE_200]; /** * The plate behind the cells, and the separators between them. Separators match the surface so that * neighbouring cells, which are only guaranteed to contrast with the surface and not with each * other, stay distinguishable. * * https://design.gitlab.com/data-visualization/color#visual-separators */ const heatmapSurface = { plate: GL_COLOR_NEUTRAL_100, separator: GL_COLOR_NEUTRAL_0 }; const heatmapSurfaceDark = { plate: GL_COLOR_NEUTRAL_800, separator: GL_COLOR_NEUTRAL_950 }; const gaugeSafeHues = [GL_COLOR_DATA_BLUE_500, GL_COLOR_DATA_BLUE_900]; const gaugeWarningHue = GL_COLOR_DATA_ORANGE_500; /** * The default palette is based on the Categorical data palette * Categorical data (also known as qualitative or thematic) uses hue to * differentiate qualitative data, and lightness to differentiate quantitive data. * More info: https://design.gitlab.com/data-visualization/color#categorical-data */ const colorPaletteDefault = [GL_COLOR_DATA_BLUE_500, GL_COLOR_DATA_ORANGE_600, GL_COLOR_DATA_AQUA_500, GL_COLOR_DATA_GREEN_600, GL_COLOR_DATA_MAGENTA_500, GL_COLOR_DATA_BLUE_700, GL_COLOR_DATA_ORANGE_800, GL_COLOR_DATA_AQUA_700, GL_COLOR_DATA_GREEN_800, GL_COLOR_DATA_MAGENTA_700, GL_COLOR_DATA_BLUE_900, GL_COLOR_DATA_ORANGE_950, GL_COLOR_DATA_AQUA_900, GL_COLOR_DATA_GREEN_950, GL_COLOR_DATA_MAGENTA_900, GL_COLOR_DATA_BLUE_600, GL_COLOR_DATA_ORANGE_700, GL_COLOR_DATA_AQUA_600, GL_COLOR_DATA_GREEN_700, GL_COLOR_DATA_MAGENTA_600, GL_COLOR_DATA_BLUE_800, GL_COLOR_DATA_ORANGE_900, GL_COLOR_DATA_AQUA_800, GL_COLOR_DATA_GREEN_900, GL_COLOR_DATA_MAGENTA_800, GL_COLOR_DATA_BLUE_950, GL_COLOR_DATA_ORANGE_500, GL_COLOR_DATA_AQUA_950, GL_COLOR_DATA_GREEN_500, GL_COLOR_DATA_MAGENTA_950]; const colorFromDefaultPalette = index => colorPaletteDefault[index % colorPaletteDefault.length]; const colorPaletteDark = [GL_COLOR_DATA_BLUE_500, GL_COLOR_DATA_ORANGE_400, GL_COLOR_DATA_AQUA_500, GL_COLOR_DATA_GREEN_400, GL_COLOR_DATA_MAGENTA_500, GL_COLOR_DATA_BLUE_300, GL_COLOR_DATA_ORANGE_200, GL_COLOR_DATA_AQUA_300, GL_COLOR_DATA_GREEN_200, GL_COLOR_DATA_MAGENTA_300, GL_COLOR_DATA_BLUE_100, GL_COLOR_DATA_ORANGE_50, GL_COLOR_DATA_AQUA_100, GL_COLOR_DATA_GREEN_50, GL_COLOR_DATA_MAGENTA_100, GL_COLOR_DATA_BLUE_400, GL_COLOR_DATA_ORANGE_300, GL_COLOR_DATA_AQUA_400, GL_COLOR_DATA_GREEN_300, GL_COLOR_DATA_MAGENTA_400, GL_COLOR_DATA_BLUE_200, GL_COLOR_DATA_ORANGE_100, GL_COLOR_DATA_AQUA_200, GL_COLOR_DATA_GREEN_100, GL_COLOR_DATA_MAGENTA_200, GL_COLOR_DATA_BLUE_50, GL_COLOR_DATA_ORANGE_500, GL_COLOR_DATA_AQUA_50, GL_COLOR_DATA_GREEN_500, GL_COLOR_DATA_MAGENTA_50]; const colorFromDarkPalette = index => colorPaletteDark[index % colorPaletteDark.length]; // ECharts lays out text by assigning a CSS font shorthand to a canvas context and calling // `measureText`, even under the SVG renderer. Canvas does not substitute CSS custom properties, // and an unparseable shorthand is rejected wholesale, leaving text measured at the canvas default // of 10px sans-serif. So the chart font stack must be concrete: drop the leading // `var(--default-regular-font, 'GitLab Sans')` consumer override, whose own fallback is the // 'GitLab Sans' that follows it. const defaultFontFamily = GL_FONT_FAMILY_REGULAR.filter(family => !family.startsWith('var(')).join(', '); /** * Chart font sizes are concrete pixel numbers rather than the rem-based font.size tokens they * mirror. zrender measures text on a detached canvas, which always resolves 1rem as 16px however * the document root is set, so rem sizes render scaled while being laid out at the wrong width. * * `defaultFontSize` (12, font.size.100) is set per component in the theme below, because ECharts * pins fontSize in its own component defaults (axis labels at 12, title at 18, gauge detail at 30) * and those shadow `textStyle`. */ const axes = { axisLabel: { margin: 8, show: true, color: 'var(--gl-chart-axis-text-color)', hideOverlap: true, fontSize: defaultFontSize }, axisLine: { show: false }, axisPointer: { lineStyle: { type: 'solid', color: 'var(--gl-chart-axis-pointer-color)' }, label: { show: false } }, axisTick: { show: true, alignWithLabel: true, lineStyle: { color: 'var(--gl-chart-axis-line-color)' } }, nameGap: 30, nameTextStyle: { fontWeight: 'bold', fontSize: defaultFontSize }, splitLine: { lineStyle: { color: ['var(--gl-chart-axis-line-color)'] } }, splitArea: { show: false } }; const isLineChartWithoutArea = options => Array.isArray(options === null || options === void 0 ? void 0 : options.series) && options.series.some(series => series.type === 'line' && !series.areaStyle); const createTheme = function () { let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return { color: colorPaletteDefault, backgroundColor: 'transparent', textStyle: { color: 'var(--gl-text-color-default)', fontFamily: defaultFontFamily, fontSize: defaultFontSize }, title: { textStyle: { fontSize: 18 // font.size.500-fixed, 1.125rem } }, gauge: { axisLabel: { fontSize: 14, // font.size.300, 0.875rem, the default body size color: 'var(--gl-chart-axis-text-color)' }, detail: { fontSize: 30, fontWeight: 'bold', color: 'var(--gl-text-color-default)' } }, markLine: { silent: true, symbol: 'none', label: { show: false }, lineStyle: { color: 'var(--gl-chart-threshold-line-color)', width: 1, type: 'dashed' } }, markArea: { silent: true, itemStyle: { color: 'var(--gl-chart-threshold-area-color)' } }, dataZoom: { borderColor: 'transparent', filterMode: 'none', brushSelect: false, dataBackground: { lineStyle: { width: 2, color: 'var(--gl-chart-axis-line-color)', opacity: 1 }, // render unfilled zoom-graph if the series is a line chart without area styles // more details: https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/2364#note_666637306 areaStyle: isLineChartWithoutArea(options) ? {} // Use empty object instead of null, see https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/2185#note_707711029 for more context : { color: 'var(--gl-background-color-strong)', opacity: 1 } }, fillerColor: 'var(--gl-chart-zoom-filler-color)', handleIcon: scrollHandleSvgPath, emphasis: { handleStyle: { color: 'var(--gl-chart-zoom-handle-color)' } }, handleStyle: { borderColor: 'transparent', color: 'var(--gl-chart-zoom-handle-color)' }, handleSize: '50%', labelFormatter: () => null, textStyle: { color: 'var(--gl-chart-axis-text-color)' } }, toolbox: { top: '-5', left: 'center', itemSize: 14, emphasis: { iconStyle: { borderWidth: 0, color: 'var(--gl-icon-color-default)', textFill: 'var(--gl-feedback-strong-text-color)', textBackgroundColor: 'var(--gl-feedback-strong-background-color)', textBorderRadius: GL_BORDER_RADIUS_BASE, textPadding: [8, 12] } }, iconStyle: { color: 'var(--gl-icon-color-default)', borderWidth: 0 }, itemGap: 8, feature: { dataZoom: { title: { zoom: 'Click to zoom in on a portion of the graph', back: 'Remove selection' }, icon: { zoom: marqueeSelectionSvgPath, back: redoSvgPath } }, restore: { title: 'Remove all selections and return chart to default state', icon: clearAllSvgPath }, saveAsImage: { title: 'Save chart as an image', name: 'graph', icon: downloadSvgPath } } }, markPoint: { label: { normal: { textStyle: { color: GL_COLOR_NEUTRAL_50 } }, emphasis: { textStyle: { color: GL_COLOR_NEUTRAL_50 } } } }, line: { itemStyle: { normal: { borderWidth: 1 } }, lineStyle: { normal: { width: 2 } }, symbolSize: '6', symbol: 'circle', showSymbol: false, smooth: false }, categoryAxis: axes, valueAxis: axes, logAxis: axes, timeAxis: axes }; }; export { colorFromDarkPalette, colorFromDefaultPalette, colorPaletteDark, colorPaletteDefault, createTheme, defaultFontFamily, gaugeSafeHues, gaugeWarningHue, heatmapHues, heatmapHuesDark, heatmapSurface, heatmapSurfaceDark, themeName };