From 9d61985fcc4139db4bb13598bdb66c9ba8b47fa4 Mon Sep 17 00:00:00 2001 From: Phoomparin Mano <poom@metabase.com> Date: Wed, 5 Jun 2024 03:36:49 +0700 Subject: [PATCH] feat(sdk): font size scaling and adjustment for visualizations (#43264) * support test utilities in sdk import * add relative unit default chart font size in embedding defaults * make font size follow sdk root * feat(sdk): add font size settings to axis ticks * feat(sdk): add font size settings to series labels * re-add hasTimelineEvents from merge commits * apply default font size at the theme level * add table header cell font size * calculate cell font size based on 12.5px * rename theme.chart to theme.cartesian * refactor visualization theme * refactor default viz theme * remove chart style config * add goal line * pass font size to chart measurements * use px as reference unit * support row chart viz * add missing echarts font size * add table cell font sizes * use css variables for funnel color * fix theme type in smart scalar story * add bar chart to storybook for visual test * add line chart to storybook for visual test * add loki reference images * add loki reference images for row chart * add loki shared reference images to stories filter * update loki reference image * synchronize base font size * add theme provider to funnel test setup * add missing default visualization theme * add unit test for get size in px * update loki reference image * fix static viz build error --- ...Visualizations_shared_RowChart_Default.png | Bin 0 -> 15371 bytes ...sualizations_shared_RowChart_Huge_Font.png | Bin 0 -> 21774 bytes .../chrome_laptop_viz_BarChart_Default.png | Bin 0 -> 9272 bytes ...aptop_viz_BarChart_Embedding_Huge_Font.png | Bin 0 -> 11208 bytes .../chrome_laptop_viz_LineChart_Default.png | Bin 0 -> 23592 bytes ...ptop_viz_LineChart_Embedding_Huge_Font.png | Bin 0 -> 25582 bytes .../components/private/SdkContentWrapper.tsx | 2 +- .../lib/theme/default-component-theme.ts | 37 ++++++++- .../lib/theme/get-embedding-theme.ts | 5 +- .../src/embedding-sdk/types/theme/index.ts | 24 +++++- .../src/embedding-sdk/types/theme/private.ts | 8 +- .../ComboChart/ComboChart.stories.tsx | 2 + .../FunnelBarChart/FunnelBarChart.stories.tsx | 2 + .../ScalarChart/ScalarChart.stories.tsx | 2 + .../ScatterPlot/ScatterPlot.stories.tsx | 2 + .../SmartScalar/SmartScalar.stories.tsx | 2 + .../WaterfallChart/WaterfallChart.stories.tsx | 2 + frontend/src/metabase/static-viz/index.js | 2 + frontend/src/metabase/ui/index.ts | 1 + .../components/FunnelNormal.styled.tsx | 5 +- .../TableInteractive/TableInteractive.jsx | 17 +++- .../TableInteractive.module.css | 2 - .../TableInteractive/table-theme-utils.ts | 5 +- .../cartesian/chart-measurements/index.ts | 58 ++++++++----- .../echarts/cartesian/constants/style.ts | 2 - .../cartesian/model/series.unit.spec.ts | 2 + .../echarts/cartesian/option/axis.ts | 23 ++++-- .../echarts/cartesian/option/goal-line.ts | 6 +- .../echarts/cartesian/option/series.ts | 4 +- .../cartesian/timeline-events/model.ts | 1 + .../cartesian/timeline-events/option.ts | 6 +- .../hooks/use-browser-rendering-context.ts | 23 ++++-- .../components/RowChart/RowChart.stories.tsx | 29 ++++++- .../visualizations/shared/utils/size-in-px.ts | 33 ++++++++ .../shared/utils/size-in-px.unit.spec.ts | 24 ++++++ .../visualizations/shared/utils/theme.ts | 34 ++++++++ .../visualizations/types/visualization.ts | 19 +++++ .../BarChart/BarChart.stories.tsx | 59 ++++++++++++++ .../CartesianChart/use-models-and-option.ts | 4 +- .../visualizations/Funnel/Funnel.tsx | 2 +- .../Funnel/Funnel.unit.spec.jsx | 20 +++-- .../LineChart/LineChart.stories.tsx | 66 +++++++++++++++ .../visualizations/RowChart/RowChart.tsx | 4 +- .../visualizations/RowChart/utils/theme.ts | 77 +++++++++++------- .../SmartScalar/SmartScalar.stories.tsx | 3 +- loki.config.js | 2 +- webpack.static-viz.config.js | 2 + 47 files changed, 510 insertions(+), 113 deletions(-) create mode 100644 .loki/reference/chrome_laptop_Visualizations_shared_RowChart_Default.png create mode 100644 .loki/reference/chrome_laptop_Visualizations_shared_RowChart_Huge_Font.png create mode 100644 .loki/reference/chrome_laptop_viz_BarChart_Default.png create mode 100644 .loki/reference/chrome_laptop_viz_BarChart_Embedding_Huge_Font.png create mode 100644 .loki/reference/chrome_laptop_viz_LineChart_Default.png create mode 100644 .loki/reference/chrome_laptop_viz_LineChart_Embedding_Huge_Font.png create mode 100644 frontend/src/metabase/visualizations/shared/utils/size-in-px.ts create mode 100644 frontend/src/metabase/visualizations/shared/utils/size-in-px.unit.spec.ts create mode 100644 frontend/src/metabase/visualizations/shared/utils/theme.ts create mode 100644 frontend/src/metabase/visualizations/visualizations/BarChart/BarChart.stories.tsx create mode 100644 frontend/src/metabase/visualizations/visualizations/LineChart/LineChart.stories.tsx diff --git a/.loki/reference/chrome_laptop_Visualizations_shared_RowChart_Default.png b/.loki/reference/chrome_laptop_Visualizations_shared_RowChart_Default.png new file mode 100644 index 0000000000000000000000000000000000000000..e72364925bb137208fc5cf84660e055e1fdff75c GIT binary patch literal 15371 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 literal 0 HcmV?d00001 diff --git a/.loki/reference/chrome_laptop_Visualizations_shared_RowChart_Huge_Font.png b/.loki/reference/chrome_laptop_Visualizations_shared_RowChart_Huge_Font.png new file mode 100644 index 0000000000000000000000000000000000000000..77d1f501970fdd7fcd7c4d1fb4f606e6666de397 GIT binary patch literal 21774 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 literal 0 HcmV?d00001 diff --git a/.loki/reference/chrome_laptop_viz_BarChart_Default.png b/.loki/reference/chrome_laptop_viz_BarChart_Default.png new file mode 100644 index 0000000000000000000000000000000000000000..2310a1d2c8647c13b8caf3fb8080b50f0307b128 GIT binary patch literal 9272 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 It5fIy2ihFi;s5{u literal 0 HcmV?d00001 diff --git a/.loki/reference/chrome_laptop_viz_BarChart_Embedding_Huge_Font.png b/.loki/reference/chrome_laptop_viz_BarChart_Embedding_Huge_Font.png new file mode 100644 index 0000000000000000000000000000000000000000..dbb039e45a4617176ebf5d12f204ff9e02ec35db GIT binary patch literal 11208 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 L_Z8m-{QSQF=uI{` literal 0 HcmV?d00001 diff --git a/.loki/reference/chrome_laptop_viz_LineChart_Default.png b/.loki/reference/chrome_laptop_viz_LineChart_Default.png new file mode 100644 index 0000000000000000000000000000000000000000..4d3030b04f80cd3f1fdd96d57c7287896f1cea1b GIT binary patch literal 23592 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�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 OmI8fE`AWI(Owm8cPl%NO literal 0 HcmV?d00001 diff --git a/.loki/reference/chrome_laptop_viz_LineChart_Embedding_Huge_Font.png b/.loki/reference/chrome_laptop_viz_LineChart_Embedding_Huge_Font.png new file mode 100644 index 0000000000000000000000000000000000000000..14b197ab2b87b64bd1a0aaa417f41c5bd90814f0 GIT binary patch literal 25582 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 literal 0 HcmV?d00001 diff --git a/enterprise/frontend/src/embedding-sdk/components/private/SdkContentWrapper.tsx b/enterprise/frontend/src/embedding-sdk/components/private/SdkContentWrapper.tsx index 809c574a869..26b84241360 100644 --- a/enterprise/frontend/src/embedding-sdk/components/private/SdkContentWrapper.tsx +++ b/enterprise/frontend/src/embedding-sdk/components/private/SdkContentWrapper.tsx @@ -52,7 +52,7 @@ const SdkContentWrapperInner = styled.div< --mb-color-text-medium: ${({ theme }) => theme.fn.themeColor("text-medium")}; --mb-color-text-light: ${({ theme }) => theme.fn.themeColor("text-light")}; - font-size: ${({ theme }) => theme.other.fontSize ?? "0.875em"}; + font-size: ${({ theme }) => theme.other.fontSize}; ${aceEditorStyles} ${saveDomImageStyles} diff --git a/enterprise/frontend/src/embedding-sdk/lib/theme/default-component-theme.ts b/enterprise/frontend/src/embedding-sdk/lib/theme/default-component-theme.ts index 722effc2efd..09a6b9f5d26 100644 --- a/enterprise/frontend/src/embedding-sdk/lib/theme/default-component-theme.ts +++ b/enterprise/frontend/src/embedding-sdk/lib/theme/default-component-theme.ts @@ -1,8 +1,23 @@ -import type { MantineThemeOverride } from "@mantine/core"; import { merge } from "icepick"; import type { MetabaseComponentTheme } from "embedding-sdk"; import { EMBEDDING_SDK_ROOT_ELEMENT_ID } from "embedding-sdk/config"; +import type { MantineThemeOverride } from "metabase/ui"; + +export const DEFAULT_SDK_FONT_SIZE = 14; + +// Use em units to scale font sizes relative to the base font size. +// The em unit is used by default in the embedding SDK. +const units = (px: number) => ({ + px: `${px}px`, + em: `${px / DEFAULT_SDK_FONT_SIZE}em`, +}); + +export const FONT_SIZES = { + tableCell: units(12.5), + label: units(12), + goalLabel: units(14), +}; /** * Default theme options for Metabase components. @@ -14,12 +29,13 @@ import { EMBEDDING_SDK_ROOT_ELEMENT_ID } from "embedding-sdk/config"; */ export const DEFAULT_METABASE_COMPONENT_THEME: MetabaseComponentTheme = { table: { - idColumn: { - textColor: "brand", - }, cell: { + fontSize: FONT_SIZES.tableCell.px, textColor: "text-dark", }, + idColumn: { + textColor: "brand", + }, }, pivotTable: { rowToggle: { @@ -27,6 +43,12 @@ export const DEFAULT_METABASE_COMPONENT_THEME: MetabaseComponentTheme = { backgroundColor: "text-light", }, }, + cartesian: { + label: { fontSize: FONT_SIZES.label.px }, + goalLine: { + label: { fontSize: FONT_SIZES.goalLabel.px }, + }, + }, }; /** @@ -38,9 +60,16 @@ export const DEFAULT_EMBEDDED_COMPONENT_THEME: MetabaseComponentTheme = merge( { table: { cell: { + fontSize: FONT_SIZES.tableCell.em, backgroundColor: "bg-white", }, }, + cartesian: { + label: { fontSize: FONT_SIZES.label.em }, + goalLine: { + label: { fontSize: FONT_SIZES.goalLabel.em }, + }, + }, }, ); diff --git a/enterprise/frontend/src/embedding-sdk/lib/theme/get-embedding-theme.ts b/enterprise/frontend/src/embedding-sdk/lib/theme/get-embedding-theme.ts index d17890ba774..03ddde8bce5 100644 --- a/enterprise/frontend/src/embedding-sdk/lib/theme/get-embedding-theme.ts +++ b/enterprise/frontend/src/embedding-sdk/lib/theme/get-embedding-theme.ts @@ -12,6 +12,7 @@ import type { import { colorTuple } from "./color-tuple"; import { DEFAULT_EMBEDDED_COMPONENT_THEME, + DEFAULT_SDK_FONT_SIZE, EMBEDDING_SDK_COMPONENTS_OVERRIDES, } from "./default-component-theme"; import type { MappableSdkColor } from "./embedding-color-palette"; @@ -20,6 +21,8 @@ import { SDK_TO_MAIN_APP_COLORS_MAPPING } from "./embedding-color-palette"; const getFontFamily = (theme: MetabaseTheme) => theme.fontFamily ?? DEFAULT_FONT; +const SDK_BASE_FONT_SIZE = `${DEFAULT_SDK_FONT_SIZE / 16}em`; + /** * Transforms a public-facing Metabase theme configuration * into a Mantine theme override for internal use. @@ -39,7 +42,7 @@ export function getEmbeddingThemeOverride( other: { ...components, - ...(theme.fontSize && { fontSize: theme.fontSize }), + fontSize: theme.fontSize ?? SDK_BASE_FONT_SIZE, }, components: EMBEDDING_SDK_COMPONENTS_OVERRIDES, diff --git a/enterprise/frontend/src/embedding-sdk/types/theme/index.ts b/enterprise/frontend/src/embedding-sdk/types/theme/index.ts index 90247245632..1a8531316c1 100644 --- a/enterprise/frontend/src/embedding-sdk/types/theme/index.ts +++ b/enterprise/frontend/src/embedding-sdk/types/theme/index.ts @@ -5,7 +5,11 @@ import type { DeepPartial } from "../utils"; * Theme configuration for embedded Metabase components. */ export interface MetabaseTheme { - /** Base font size */ + /** + * Base font size. + * Supported units are px, em and rem. + * Defaults to ~14px (0.875em) + **/ fontSize?: string; /** @@ -83,6 +87,9 @@ export interface MetabaseComponentTheme { /** Default background color of cells, defaults to `background` */ backgroundColor?: string; + + /** Font size of cell values, defaults to ~12.5px */ + fontSize: string; }; idColumn?: { @@ -111,6 +118,21 @@ export interface MetabaseComponentTheme { lineHeight?: string; }; }; + + /** Cartesian charts */ + cartesian: { + label: { + /** Labels used in cartesian charts, such as axis ticks and series. */ + fontSize: string; + }; + + goalLine: { + label: { + /** Font size of goal line labels */ + fontSize: string; + }; + }; + }; } export type ChartColor = diff --git a/enterprise/frontend/src/embedding-sdk/types/theme/private.ts b/enterprise/frontend/src/embedding-sdk/types/theme/private.ts index 06d2a077d5e..a2cd0867f92 100644 --- a/enterprise/frontend/src/embedding-sdk/types/theme/private.ts +++ b/enterprise/frontend/src/embedding-sdk/types/theme/private.ts @@ -1,9 +1,7 @@ -import type { MetabaseComponentTheme } from "."; +import type { MetabaseComponentTheme, MetabaseTheme } from "."; /** * Mantine theme options specific to React embedding. */ -export type EmbeddingThemeOptions = MetabaseComponentTheme & { - /** Base font size */ - fontSize?: string; -}; +export type EmbeddingThemeOptions = MetabaseComponentTheme & + Pick<MetabaseTheme, "fontSize">; diff --git a/frontend/src/metabase/static-viz/components/ComboChart/ComboChart.stories.tsx b/frontend/src/metabase/static-viz/components/ComboChart/ComboChart.stories.tsx index 001c734fb38..0c95be526ef 100644 --- a/frontend/src/metabase/static-viz/components/ComboChart/ComboChart.stories.tsx +++ b/frontend/src/metabase/static-viz/components/ComboChart/ComboChart.stories.tsx @@ -3,6 +3,7 @@ import type { ComponentStory } from "@storybook/react"; import { color } from "metabase/lib/colors"; import { formatStaticValue } from "metabase/static-viz/lib/format"; import { measureTextWidth } from "metabase/static-viz/lib/text"; +import { DEFAULT_VISUALIZATION_THEME } from "metabase/visualizations/shared/utils/theme"; import type { RenderingContext } from "metabase/visualizations/types"; import { ComboChart } from "./ComboChart"; @@ -27,6 +28,7 @@ const renderingContext: RenderingContext = { measureText: (text, style) => measureTextWidth(text, Number(style.size), Number(style.weight)), fontFamily: "Lato", + theme: DEFAULT_VISUALIZATION_THEME, }; export const LineLinearXScale = Template.bind({}); diff --git a/frontend/src/metabase/static-viz/components/FunnelBarChart/FunnelBarChart.stories.tsx b/frontend/src/metabase/static-viz/components/FunnelBarChart/FunnelBarChart.stories.tsx index e1edf76e700..c2857a3669f 100644 --- a/frontend/src/metabase/static-viz/components/FunnelBarChart/FunnelBarChart.stories.tsx +++ b/frontend/src/metabase/static-viz/components/FunnelBarChart/FunnelBarChart.stories.tsx @@ -3,6 +3,7 @@ import type { ComponentStory } from "@storybook/react"; import { color } from "metabase/lib/colors"; import { formatStaticValue } from "metabase/static-viz/lib/format"; import { measureTextWidth } from "metabase/static-viz/lib/text"; +import { DEFAULT_VISUALIZATION_THEME } from "metabase/visualizations/shared/utils/theme"; import type { RenderingContext } from "metabase/visualizations/types"; import { FunnelBarChart } from "./FunnelBarChart"; @@ -27,6 +28,7 @@ const renderingContext: RenderingContext = { measureText: (text, style) => measureTextWidth(text, Number(style.size), Number(style.weight)), fontFamily: "Lato", + theme: DEFAULT_VISUALIZATION_THEME, }; export const Default = Template.bind({}); diff --git a/frontend/src/metabase/static-viz/components/ScalarChart/ScalarChart.stories.tsx b/frontend/src/metabase/static-viz/components/ScalarChart/ScalarChart.stories.tsx index bb522f1c80a..59a9576f65e 100644 --- a/frontend/src/metabase/static-viz/components/ScalarChart/ScalarChart.stories.tsx +++ b/frontend/src/metabase/static-viz/components/ScalarChart/ScalarChart.stories.tsx @@ -3,6 +3,7 @@ import type { ComponentStory } from "@storybook/react"; import { color } from "metabase/lib/colors"; import { formatStaticValue } from "metabase/static-viz/lib/format"; import { measureTextWidth } from "metabase/static-viz/lib/text"; +import { DEFAULT_VISUALIZATION_THEME } from "metabase/visualizations/shared/utils/theme"; import type { RenderingContext } from "metabase/visualizations/types"; import { ScalarChart } from "./ScalarChart"; @@ -27,6 +28,7 @@ const renderingContext: RenderingContext = { measureText: (text, style) => measureTextWidth(text, Number(style.size), Number(style.weight)), fontFamily: "Lato", + theme: DEFAULT_VISUALIZATION_THEME, }; export const Default = Template.bind({}); diff --git a/frontend/src/metabase/static-viz/components/ScatterPlot/ScatterPlot.stories.tsx b/frontend/src/metabase/static-viz/components/ScatterPlot/ScatterPlot.stories.tsx index 81e22799b1a..979acb3783c 100644 --- a/frontend/src/metabase/static-viz/components/ScatterPlot/ScatterPlot.stories.tsx +++ b/frontend/src/metabase/static-viz/components/ScatterPlot/ScatterPlot.stories.tsx @@ -3,6 +3,7 @@ import type { ComponentStory } from "@storybook/react"; import { color } from "metabase/lib/colors"; import { formatStaticValue } from "metabase/static-viz/lib/format"; import { measureTextWidth } from "metabase/static-viz/lib/text"; +import { DEFAULT_VISUALIZATION_THEME } from "metabase/visualizations/shared/utils/theme"; import type { RenderingContext } from "metabase/visualizations/types"; import { ScatterPlot } from "./ScatterPlot"; @@ -27,6 +28,7 @@ const renderingContext: RenderingContext = { measureText: (text, style) => measureTextWidth(text, Number(style.size), Number(style.weight)), fontFamily: "Lato", + theme: DEFAULT_VISUALIZATION_THEME, }; export const Default = Template.bind({}); diff --git a/frontend/src/metabase/static-viz/components/SmartScalar/SmartScalar.stories.tsx b/frontend/src/metabase/static-viz/components/SmartScalar/SmartScalar.stories.tsx index be53b2d24c6..10d6edb6cb2 100644 --- a/frontend/src/metabase/static-viz/components/SmartScalar/SmartScalar.stories.tsx +++ b/frontend/src/metabase/static-viz/components/SmartScalar/SmartScalar.stories.tsx @@ -2,6 +2,7 @@ import { colors } from "metabase/lib/colors"; import { createColorGetter } from "metabase/static-viz/lib/colors"; import { formatStaticValue } from "metabase/static-viz/lib/format"; import { measureTextWidth } from "metabase/static-viz/lib/text"; +import { DEFAULT_VISUALIZATION_THEME } from "metabase/visualizations/shared/utils/theme"; import type { RowValues, VisualizationSettings } from "metabase-types/api"; import { createMockColumn, @@ -136,6 +137,7 @@ const createTemplate = ({ rows, vizSettings }: SmartScalarSeriesOpts) => getColor: createColorGetter(colors), measureText: (text, style) => measureTextWidth(text, Number(style.size), Number(style.weight)), + theme: DEFAULT_VISUALIZATION_THEME, }} /> ); diff --git a/frontend/src/metabase/static-viz/components/WaterfallChart/WaterfallChart.stories.tsx b/frontend/src/metabase/static-viz/components/WaterfallChart/WaterfallChart.stories.tsx index daf26ee33d9..e7e5201340f 100644 --- a/frontend/src/metabase/static-viz/components/WaterfallChart/WaterfallChart.stories.tsx +++ b/frontend/src/metabase/static-viz/components/WaterfallChart/WaterfallChart.stories.tsx @@ -4,6 +4,7 @@ import { color } from "metabase/lib/colors"; import { data } from "metabase/static-viz/components/WaterfallChart/stories-data"; import { formatStaticValue } from "metabase/static-viz/lib/format"; import { measureTextWidth } from "metabase/static-viz/lib/text"; +import { DEFAULT_VISUALIZATION_THEME } from "metabase/visualizations/shared/utils/theme"; import type { RenderingContext } from "metabase/visualizations/types"; import { WaterfallChart } from "./WaterfallChart"; @@ -27,6 +28,7 @@ const renderingContext: RenderingContext = { measureText: (text, style) => measureTextWidth(text, Number(style.size), Number(style.weight)), fontFamily: "Lato", + theme: DEFAULT_VISUALIZATION_THEME, }; export const YAxisCompactWithoutDataLabels = Template.bind({}); diff --git a/frontend/src/metabase/static-viz/index.js b/frontend/src/metabase/static-viz/index.js index 6987169ab82..9cfc4a8c2d6 100644 --- a/frontend/src/metabase/static-viz/index.js +++ b/frontend/src/metabase/static-viz/index.js @@ -11,6 +11,7 @@ import { measureTextWidth, measureTextEChartsAdapter, } from "metabase/static-viz/lib/text"; +import { DEFAULT_VISUALIZATION_THEME } from "metabase/visualizations/shared/utils/theme"; import { LegacyStaticChart } from "./containers/LegacyStaticChart"; @@ -38,6 +39,7 @@ export function RenderChart(rawSeries, dashcardSettings, colors) { measureText: (text, style) => measureTextWidth(text, style.size, style.weight), fontFamily: "Lato, 'Helvetica Neue', Helvetica, Arial, sans-serif", + theme: DEFAULT_VISUALIZATION_THEME, }; const props = { diff --git a/frontend/src/metabase/ui/index.ts b/frontend/src/metabase/ui/index.ts index b926912c52e..fd469e35ff8 100644 --- a/frontend/src/metabase/ui/index.ts +++ b/frontend/src/metabase/ui/index.ts @@ -3,6 +3,7 @@ export type { TabsValue, MantineTheme, MantineThemeOverride, + MantineThemeOther, } from "@mantine/core"; export { useHover } from "@mantine/hooks"; export * from "./components"; diff --git a/frontend/src/metabase/visualizations/components/FunnelNormal.styled.tsx b/frontend/src/metabase/visualizations/components/FunnelNormal.styled.tsx index 24cc6227f03..7b5bcdc5985 100644 --- a/frontend/src/metabase/visualizations/components/FunnelNormal.styled.tsx +++ b/frontend/src/metabase/visualizations/components/FunnelNormal.styled.tsx @@ -2,7 +2,6 @@ import { css } from "@emotion/react"; import styled from "@emotion/styled"; import { isDesktopSafari } from "metabase/lib/browser"; -import { color } from "metabase/lib/colors"; interface SharedProps { isNarrow: boolean; @@ -17,7 +16,7 @@ interface FunnelStepProps { export const FunnelStep = styled.div<FunnelStepProps>` width: 100%; min-width: 20px; - border-right: 1px solid ${color("border")}; + border-right: 1px solid var(--mb-color-border); display: flex; flex-direction: column; @@ -95,7 +94,7 @@ interface FunnelNormalRootProps { export const FunnelNormalRoot = styled.div<FunnelNormalRootProps>` display: flex; padding: ${props => (props.isSmall ? "0.5rem" : "1rem")}; - color: ${color("text-medium")}; + color: var(--mb-color-text-medium); ${isDesktopSafari() ? css` diff --git a/frontend/src/metabase/visualizations/components/TableInteractive/TableInteractive.jsx b/frontend/src/metabase/visualizations/components/TableInteractive/TableInteractive.jsx index cae0d890549..25e75885c85 100644 --- a/frontend/src/metabase/visualizations/components/TableInteractive/TableInteractive.jsx +++ b/frontend/src/metabase/visualizations/components/TableInteractive/TableInteractive.jsx @@ -121,9 +121,19 @@ class TableInteractive extends Component { static defaultProps = { isPivoted: false, hasMetadataPopovers: true, - renderTableHeaderWrapper: children => { + + // NOTE: the column and index arguments are used in the DatasetEditor, + // which renders table header differently. + renderTableHeaderWrapper: (children, _column, _index, theme) => { + const cellTheme = theme.other?.table?.cell; + return ( - <Box className={TableS.cellData} data-testid="cell-data" c="brand"> + <Box + className={TableS.cellData} + data-testid="cell-data" + c="brand" + fz={cellTheme?.fontSize} + > {children} </Box> ); @@ -145,6 +155,7 @@ class TableInteractive extends Component { c={cellTheme.color} bg={cellTheme.background} style={{ border: cellTheme.border }} + fz={cellTheme.fontSize} > {children} </Box> @@ -771,6 +782,7 @@ class TableInteractive extends Component { renderTableHeaderWrapper, question, mode, + theme, } = this.props; const { dragColIndex, showDetailShortcut } = this.state; @@ -921,6 +933,7 @@ class TableInteractive extends Component { </Ellipsified>, column, columnIndex, + theme, )} </QueryColumnInfoPopover> <TableDraggable diff --git a/frontend/src/metabase/visualizations/components/TableInteractive/TableInteractive.module.css b/frontend/src/metabase/visualizations/components/TableInteractive/TableInteractive.module.css index cfd1d2e9be5..1553aa7a4b1 100644 --- a/frontend/src/metabase/visualizations/components/TableInteractive/TableInteractive.module.css +++ b/frontend/src/metabase/visualizations/components/TableInteractive/TableInteractive.module.css @@ -5,7 +5,6 @@ .TableInteractiveHeaderCellData .cellData { font-weight: 900; - font-size: 10px; border: 1px solid transparent; padding: 0.25em 0.65em; border-radius: 6px; @@ -56,7 +55,6 @@ text-overflow: ellipsis; overflow-x: hidden; font-weight: 700; - font-size: 12.5px; } /* pivot */ diff --git a/frontend/src/metabase/visualizations/components/TableInteractive/table-theme-utils.ts b/frontend/src/metabase/visualizations/components/TableInteractive/table-theme-utils.ts index b7184566dd8..019005c847d 100644 --- a/frontend/src/metabase/visualizations/components/TableInteractive/table-theme-utils.ts +++ b/frontend/src/metabase/visualizations/components/TableInteractive/table-theme-utils.ts @@ -16,9 +16,12 @@ export function getCellDataTheme({ const cellTheme = theme.other?.table?.cell; const idTheme = theme.other?.table?.idColumn; + const fontSize = cellTheme?.fontSize; + if (isIDColumn) { return { color: idTheme?.textColor, + fontSize, background: idTheme?.backgroundColor || alpha(theme.fn.themeColor("brand"), 0.08), border: `1px solid ${alpha( @@ -28,7 +31,7 @@ export function getCellDataTheme({ }; } - return { color: cellTheme?.textColor }; + return { color: cellTheme?.textColor, fontSize }; } export const getCellHoverBackground = ({ diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/chart-measurements/index.ts b/frontend/src/metabase/visualizations/echarts/cartesian/chart-measurements/index.ts index 0405feeaf91..016e1e7c829 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/chart-measurements/index.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/chart-measurements/index.ts @@ -49,7 +49,7 @@ const getYAxisTicksWidth = ( axisModel: YAxisModel, yAxisScaleTransforms: NumericAxisScaleTransforms, settings: ComputedVisualizationSettings, - { measureText, fontFamily }: RenderingContext, + { measureText, fontFamily, theme }: RenderingContext, ): number => { if (!settings["graph.y_axis.axis_enabled"]) { return 0; @@ -58,7 +58,9 @@ const getYAxisTicksWidth = ( const fontStyle = { ...CHART_STYLE.axisTicks, family: fontFamily, + size: theme.cartesian.label.fontSize, }; + // extents need to be untransformed to get the value of the tick label const [min, max] = axisModel.extent.map(extent => yAxisScaleTransforms.fromEChartsAxisValue(extent), @@ -117,20 +119,23 @@ const getXAxisTicksWidth = ( dataset: ChartDataset, axisEnabledSetting: ComputedVisualizationSettings["graph.x_axis.axis_enabled"], axisModel: XAxisModel, - { measureText, fontFamily }: RenderingContext, + { theme, measureText, fontFamily }: RenderingContext, ) => { + const { fontSize } = theme.cartesian.label; + if (!axisEnabledSetting) { return { firstXTickWidth: 0, lastXTickWidth: 0 }; } if (axisEnabledSetting === "rotate-90") { return { - firstXTickWidth: CHART_STYLE.axisTicks.size, - lastXTickWidth: CHART_STYLE.axisTicks.size, + firstXTickWidth: fontSize, + lastXTickWidth: fontSize, }; } const fontStyle = { ...CHART_STYLE.axisTicks, + size: fontSize, family: fontFamily, }; @@ -161,13 +166,16 @@ const getXAxisTicksWidth = ( const getXAxisTicksHeight = ( maxXTickWidth: number, axisEnabledSetting: ComputedVisualizationSettings["graph.x_axis.axis_enabled"], + { theme }: RenderingContext, ) => { + const { fontSize } = theme.cartesian.label; + if (!axisEnabledSetting) { return 0; } if (axisEnabledSetting === true || axisEnabledSetting === "compact") { - return CHART_STYLE.axisTicks.size; + return fontSize; } if (axisEnabledSetting === "rotate-90") { @@ -182,7 +190,7 @@ const getXAxisTicksHeight = ( `Unexpected "graph.x_axis.axis_enabled" value ${axisEnabledSetting}`, ); - return CHART_STYLE.axisTicks.size + CHART_STYLE.axisNameMargin; + return fontSize + CHART_STYLE.axisNameMargin; }; const X_LABEL_HEIGHT_RATIO_THRESHOLD = 0.7; // x-axis labels cannot be taller than 70% of chart height @@ -211,6 +219,8 @@ const getAutoAxisEnabledSetting = ( outerHeight: number, renderingContext: RenderingContext, ): ComputedVisualizationSettings["graph.x_axis.axis_enabled"] => { + const { fontSize } = renderingContext.theme.cartesian.label; + const shouldAutoSelectSetting = settings["graph.x_axis.axis_enabled"] === true && (settings["graph.x_axis.scale"] === "ordinal" || @@ -232,19 +242,13 @@ const getAutoAxisEnabledSetting = ( return true; } - if ( - dimensionWidth >= - CHART_STYLE.axisTicks.size * X_LABEL_ROTATE_45_THRESHOLD_FACTOR - ) { + if (dimensionWidth >= fontSize * X_LABEL_ROTATE_45_THRESHOLD_FACTOR) { return checkHeight(maxXTickWidth, outerHeight, "rotate-45") ? "rotate-45" : false; } - if ( - dimensionWidth >= - CHART_STYLE.axisTicks.size * X_LABEL_ROTATE_90_THRESHOLD_FACTOR - ) { + if (dimensionWidth >= fontSize * X_LABEL_ROTATE_90_THRESHOLD_FACTOR) { return checkHeight(maxXTickWidth, outerHeight, "rotate-90") ? "rotate-90" : false; @@ -261,6 +265,8 @@ const getTicksDimensions = ( hasTimelineEvents: boolean, renderingContext: RenderingContext, ) => { + const { fontSize } = renderingContext.theme.cartesian.label; + const ticksDimensions: TicksDimensions = { yTicksWidthLeft: 0, yTicksWidthRight: 0, @@ -302,6 +308,7 @@ const getTicksDimensions = ( if (hasBottomAxis) { const fontStyle = { ...CHART_STYLE.axisTicks, + size: fontSize, family: renderingContext.fontFamily, }; @@ -333,7 +340,7 @@ const getTicksDimensions = ( ticksDimensions.lastXTickWidth = lastXTickWidth; ticksDimensions.xTicksHeight = - getXAxisTicksHeight(maxXTickWidth, axisEnabledSetting) + + getXAxisTicksHeight(maxXTickWidth, axisEnabledSetting, renderingContext) + CHART_STYLE.axisTicksMarginX + (isTimeSeries && hasTimelineEvents ? CHART_STYLE.timelineEvents.height @@ -357,7 +364,13 @@ export const getChartPadding = ( ticksDimensions: TicksDimensions, axisEnabledSetting: ComputedVisualizationSettings["graph.x_axis.axis_enabled"], chartWidth: number, + { theme }: RenderingContext, ): Padding => { + const { fontSize } = theme.cartesian.label; + + const axisNameFontSize = fontSize; + const seriesLabelFontSize = fontSize; + const padding: Padding = { top: CHART_STYLE.padding.y, left: CHART_STYLE.padding.x, @@ -372,8 +385,7 @@ export const getChartPadding = ( settings["graph.show_values"] || (settings["graph.show_goal"] && settings["graph.goal_label"]) ) { - padding.top += - CHART_STYLE.seriesLabels.size + CHART_STYLE.seriesLabels.offset; + padding.top += seriesLabelFontSize + CHART_STYLE.seriesLabels.offset; } // 2. Bottom Padding @@ -382,14 +394,12 @@ export const getChartPadding = ( const hasXAxisName = settings["graph.x_axis.labels_enabled"]; if (hasXAxisName) { - padding.bottom += - CHART_STYLE.axisName.size / 2 + CHART_STYLE.axisNameMargin; + padding.bottom += axisNameFontSize / 2 + CHART_STYLE.axisNameMargin; } // 3. Side (Left and Right) Padding - const yAxisNameTotalWidth = - CHART_STYLE.axisName.size + CHART_STYLE.axisNameMargin; + const yAxisNameTotalWidth = axisNameFontSize + CHART_STYLE.axisNameMargin; padding.left += ticksDimensions.yTicksWidthLeft; if (chartModel.leftAxisModel?.label) { @@ -500,10 +510,13 @@ const areHorizontalXAxisTicksOverlapping = ( dataset: ChartDataset, dimensionWidth: number, formatter: AxisFormatter, - { measureText, fontFamily }: RenderingContext, + { theme, measureText, fontFamily }: RenderingContext, ) => { + const { fontSize } = theme.cartesian.label; + const fontStyle = { ...CHART_STYLE.axisTicks, + size: fontSize, family: fontFamily, }; @@ -648,6 +661,7 @@ export const getChartMeasurements = ( ticksDimensions, axisEnabledSetting, width, + renderingContext, ); const bounds = getChartBounds(width, height, padding, ticksDimensions); diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/constants/style.ts b/frontend/src/metabase/visualizations/echarts/cartesian/constants/style.ts index 9e5483e3804..5db7f467590 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/constants/style.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/constants/style.ts @@ -24,7 +24,6 @@ export const CHART_STYLE = { axisTicksMarginX: 5, axisTicksMarginY: 10, axisTicks: { - size: 12, weight: 700, }, seriesLabels: { @@ -34,7 +33,6 @@ export const CHART_STYLE = { stackedPadding: 2, }, axisName: { - size: 12, weight: 700, }, axisNameMargin: 12, diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/model/series.unit.spec.ts b/frontend/src/metabase/visualizations/echarts/cartesian/model/series.unit.spec.ts index 8395c77e705..d2bc91e2060 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/model/series.unit.spec.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/model/series.unit.spec.ts @@ -2,6 +2,7 @@ import type { BreakoutChartColumns, CartesianChartColumns, } from "metabase/visualizations/lib/graph/columns"; +import { DEFAULT_VISUALIZATION_THEME } from "metabase/visualizations/shared/utils/theme"; import type { ComputedVisualizationSettings, RenderingContext, @@ -30,6 +31,7 @@ const renderingContextMock: RenderingContext = { getColor: colorName => colorName, measureText: () => 0, fontFamily: "Lato", + theme: DEFAULT_VISUALIZATION_THEME, }; describe("series", () => { diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/option/axis.ts b/frontend/src/metabase/visualizations/echarts/cartesian/option/axis.ts index 6af66adec5e..e9f6eceb6f5 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/option/axis.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/option/axis.ts @@ -65,7 +65,7 @@ export const getYAxisRange = ( }; export const getAxisNameDefaultOption = ( - { getColor, fontFamily }: RenderingContext, + { getColor, fontFamily, theme }: RenderingContext, nameGap: number, name: string | undefined, rotate?: number, @@ -76,20 +76,21 @@ export const getAxisNameDefaultOption = ( nameRotate: rotate, nameTextStyle: { color: getColor("text-dark"), - fontSize: CHART_STYLE.axisName.size, + fontSize: theme.cartesian.label.fontSize, fontWeight: CHART_STYLE.axisName.weight, fontFamily, }, }); export const getTicksDefaultOption = ({ + theme, getColor, fontFamily, }: RenderingContext) => { return { hideOverlap: true, color: getColor("text-dark"), - fontSize: CHART_STYLE.axisTicks.size, + fontSize: theme.cartesian.label.fontSize, fontWeight: CHART_STYLE.axisTicks.weight, fontFamily, }; @@ -110,7 +111,10 @@ const getHistogramTicksOptions = ( chartModel: BaseCartesianChartModel, settings: ComputedVisualizationSettings, chartMeasurements: ChartMeasurements, + { theme }: RenderingContext, ) => { + const { fontSize } = theme.cartesian.label; + if (settings["graph.x_axis.scale"] !== "histogram") { return {}; } @@ -120,16 +124,14 @@ const getHistogramTicksOptions = ( const options = { showMinLabel: false, showMaxLabel: true }; if (settings["graph.x_axis.axis_enabled"] === "rotate-45") { - const topOffset = - (histogramDimensionWidth + CHART_STYLE.axisTicks.size / 2) * Math.SQRT1_2; + const topOffset = (histogramDimensionWidth + fontSize / 2) * Math.SQRT1_2; return { ...options, padding: [0, topOffset, 0, 0], margin: -histogramDimensionWidth / 2 + CHART_STYLE.axisTicksMarginX, }; } else if (settings["graph.x_axis.axis_enabled"] === "rotate-90") { - const rightOffset = - histogramDimensionWidth / 2 - CHART_STYLE.axisTicks.size / 2; + const rightOffset = histogramDimensionWidth / 2 - fontSize / 2; return { ...options, verticalAlign: "bottom", @@ -334,7 +336,12 @@ export const buildCategoricalDimensionAxis = ( axisLabel: { margin: CHART_STYLE.axisTicksMarginX, ...getDimensionTicksDefaultOption(settings, renderingContext), - ...getHistogramTicksOptions(chartModel, settings, chartMeasurements), + ...getHistogramTicksOptions( + chartModel, + settings, + chartMeasurements, + renderingContext, + ), interval: () => true, formatter: (value: string) => { const numberValue = parseNumberValue(value); diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/option/goal-line.ts b/frontend/src/metabase/visualizations/echarts/cartesian/option/goal-line.ts index bd3321a507c..0cfbfbefc8b 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/option/goal-line.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/option/goal-line.ts @@ -36,6 +36,7 @@ export function getGoalLineSeriesOption( } const goalValue = settings["graph.goal_value"]; + const { fontSize } = renderingContext.theme.cartesian.goalLine.label; return { id: GOAL_LINE_SERIES_ID, @@ -78,8 +79,7 @@ export function getGoalLineSeriesOption( const hasRightYAxis = chartModel.rightAxisModel == null; const align = hasRightYAxis ? ("right" as const) : ("left" as const); const labelX = hasRightYAxis ? xEnd : xStart; - const labelY = - y - CHART_STYLE.goalLine.label.size - CHART_STYLE.goalLine.label.margin; + const labelY = y - fontSize - CHART_STYLE.goalLine.label.margin; const label = { type: "text" as const, @@ -94,7 +94,7 @@ export function getGoalLineSeriesOption( align, text: settings["graph.goal_label"] ?? "", fontFamily: renderingContext.fontFamily, - fontSize: CHART_STYLE.goalLine.label.size, + fontSize, fontWeight: CHART_STYLE.goalLine.label.weight, fill: renderingContext.getColor("text-medium"), }, diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/option/series.ts b/frontend/src/metabase/visualizations/echarts/cartesian/option/series.ts index 65729e223c8..9abbad6896f 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/option/series.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/option/series.ts @@ -266,6 +266,8 @@ export const buildEChartsLabelOptions = ( chartDataDensity?: ChartDataDensity, position?: "top" | "bottom" | "inside", ): SeriesLabelOption => { + const { fontSize } = renderingContext.theme.cartesian.label; + return { show: !!formatter, silent: true, @@ -273,7 +275,7 @@ export const buildEChartsLabelOptions = ( opacity: 1, fontFamily: renderingContext.fontFamily, fontWeight: CHART_STYLE.seriesLabels.weight, - fontSize: CHART_STYLE.seriesLabels.size, + fontSize, color: renderingContext.getColor("text-dark"), textBorderColor: renderingContext.getColor("white"), textBorderWidth: 3, diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/timeline-events/model.ts b/frontend/src/metabase/visualizations/echarts/cartesian/timeline-events/model.ts index 80e9276fef9..ff0d59e6e8e 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/timeline-events/model.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/timeline-events/model.ts @@ -62,6 +62,7 @@ const getMinDistanceFromTimelineEventGroup = ( const countLabelWidth = renderingContext.measureText(eventsCount.toString(), { ...CHART_STYLE.axisTicks, + size: renderingContext.theme.cartesian.label.fontSize, family: renderingContext.fontFamily, }); diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/timeline-events/option.ts b/frontend/src/metabase/visualizations/echarts/cartesian/timeline-events/option.ts index 7249d3d46d2..5f021317fee 100644 --- a/frontend/src/metabase/visualizations/echarts/cartesian/timeline-events/option.ts +++ b/frontend/src/metabase/visualizations/echarts/cartesian/timeline-events/option.ts @@ -40,8 +40,10 @@ function svgToImageUri(svgString: string) { export const getTimelineEventsSeries = ( timelineEventsModel: TimelineEventsModel, selectedEventsIds: TimelineEventId[], - { fontFamily, getColor }: RenderingContext, + { fontFamily, getColor, theme }: RenderingContext, ): LineSeriesOption | null => { + const { fontSize } = theme?.cartesian?.label ?? {}; + if (timelineEventsModel.length === 0) { return null; } @@ -74,7 +76,7 @@ export const getTimelineEventsSeries = ( padding: [0, 0, 0, 24], hideOverlap: true, color, - fontSize: CHART_STYLE.axisTicks.size, + fontSize, fontWeight: CHART_STYLE.axisTicks.weight, fontFamily, }, diff --git a/frontend/src/metabase/visualizations/hooks/use-browser-rendering-context.ts b/frontend/src/metabase/visualizations/hooks/use-browser-rendering-context.ts index 4f8d6110695..6de4af88068 100644 --- a/frontend/src/metabase/visualizations/hooks/use-browser-rendering-context.ts +++ b/frontend/src/metabase/visualizations/hooks/use-browser-rendering-context.ts @@ -4,20 +4,31 @@ import { usePalette } from "metabase/hooks/use-palette"; import { color } from "metabase/lib/colors"; import { formatValue } from "metabase/lib/formatting/value"; import { measureTextWidth } from "metabase/lib/measure-text"; +import { useMantineTheme } from "metabase/ui"; +import { getVisualizationTheme } from "metabase/visualizations/shared/utils/theme"; import type { RenderingContext } from "metabase/visualizations/types"; +interface RenderingOptions { + fontFamily: string; +} + export const useBrowserRenderingContext = ( - fontFamily: string, + options: RenderingOptions, ): RenderingContext => { + const { fontFamily } = options; + const palette = usePalette(); + const theme = useMantineTheme(); + + return useMemo(() => { + const style = getVisualizationTheme(theme.other); - return useMemo( - () => ({ + return { getColor: name => color(name, palette), formatValue: (value, options) => String(formatValue(value, options)), measureText: measureTextWidth, fontFamily: `${fontFamily}, Arial, sans-serif`, - }), - [fontFamily, palette], - ); + theme: style, + }; + }, [fontFamily, palette, theme]); }; diff --git a/frontend/src/metabase/visualizations/shared/components/RowChart/RowChart.stories.tsx b/frontend/src/metabase/visualizations/shared/components/RowChart/RowChart.stories.tsx index 1d1837a7451..674d553bd4f 100644 --- a/frontend/src/metabase/visualizations/shared/components/RowChart/RowChart.stories.tsx +++ b/frontend/src/metabase/visualizations/shared/components/RowChart/RowChart.stories.tsx @@ -1,8 +1,11 @@ import type { ComponentStory } from "@storybook/react"; +import { SdkVisualizationWrapper } from "__support__/storybook"; import { color } from "metabase/lib/colors"; import { measureTextWidth } from "metabase/lib/measure-text"; import { getStaticChartTheme } from "metabase/static-viz/components/RowChart/theme"; +import { Box } from "metabase/ui"; +import { useRowChartTheme } from "metabase/visualizations/visualizations/RowChart/utils/theme"; import { RowChart } from "./RowChart"; @@ -13,14 +16,13 @@ export default { const Template: ComponentStory<typeof RowChart> = args => { return ( - <div style={{ padding: 8, height: 600, backgroundColor: "white" }}> + <Box h={600} bg="white" p="8px"> <RowChart {...args} /> - </div> + </Box> ); }; -export const Default = Template.bind({}); -Default.args = { +const DEFAULT_ROW_CHART_ARGS = { width: 800, height: 400, data: [ @@ -78,3 +80,22 @@ Default.args = { style: { fontFamily: "Lato" }, }; + +export const Default = Template.bind({}); +Default.args = DEFAULT_ROW_CHART_ARGS; + +const ThemedRowChart = () => { + const theme = useRowChartTheme({ fontFamily: "Lato" }); + + return ( + <Box h={600} bg="white" p="8px"> + <RowChart {...DEFAULT_ROW_CHART_ARGS} theme={theme} stackOffset={null} /> + </Box> + ); +}; + +export const HugeFont = () => ( + <SdkVisualizationWrapper theme={{ fontSize: "20px" }}> + <ThemedRowChart /> + </SdkVisualizationWrapper> +); diff --git a/frontend/src/metabase/visualizations/shared/utils/size-in-px.ts b/frontend/src/metabase/visualizations/shared/utils/size-in-px.ts new file mode 100644 index 00000000000..47b4be1ae37 --- /dev/null +++ b/frontend/src/metabase/visualizations/shared/utils/size-in-px.ts @@ -0,0 +1,33 @@ +/** + * Convert string font sizes (e.g. 12px, 25em) to number in pixels. + * + * This is useful for visualizations that require font size in pixels, + * mainly for calculating padding and offsets. + **/ +export function getSizeInPx( + value?: string | number, + parentFontSize: number = 16, +): number | undefined { + if (typeof value !== "string") { + return value; + } + + if (value.endsWith("px")) { + return stripNaN(parseFloat(value)); + } + + if (value.endsWith("em")) { + const em = stripNaN(parseFloat(value.replace(/em|rem/, ""))); + + if (em === undefined) { + return undefined; + } + + const emValue = em * parentFontSize; + + return Math.round(emValue * 100) / 100; + } +} + +const stripNaN = (value: number): number | undefined => + isNaN(value) ? undefined : value; diff --git a/frontend/src/metabase/visualizations/shared/utils/size-in-px.unit.spec.ts b/frontend/src/metabase/visualizations/shared/utils/size-in-px.unit.spec.ts new file mode 100644 index 00000000000..c6c1e48a1b5 --- /dev/null +++ b/frontend/src/metabase/visualizations/shared/utils/size-in-px.unit.spec.ts @@ -0,0 +1,24 @@ +import { getSizeInPx } from "./size-in-px"; + +describe("getSizeInPx", () => { + it("returns the number value if it's not a string", () => { + expect(getSizeInPx(12)).toBe(12); + }); + + it("returns the px units as a number", () => { + expect(getSizeInPx("14px")).toBe(14); + expect(getSizeInPx("8.256px")).toBe(8.256); + }); + + it("converts em/rem units based on parent font size", () => { + expect(getSizeInPx("0.75em")).toBe(12); + expect(getSizeInPx("0.75rem", 14)).toBe(10.5); + expect(getSizeInPx("1.56em", 18)).toBe(28.08); + }); + + it("returns undefined if the value cannot be parsed", () => { + expect(getSizeInPx("15%")).toBe(undefined); + expect(getSizeInPx("22")).toBe(undefined); + expect(getSizeInPx("foobar")).toBe(undefined); + }); +}); diff --git a/frontend/src/metabase/visualizations/shared/utils/theme.ts b/frontend/src/metabase/visualizations/shared/utils/theme.ts new file mode 100644 index 00000000000..c0d3193f895 --- /dev/null +++ b/frontend/src/metabase/visualizations/shared/utils/theme.ts @@ -0,0 +1,34 @@ +import { DEFAULT_METABASE_COMPONENT_THEME } from "embedding-sdk/lib/theme"; +import type { MantineThemeOther } from "metabase/ui"; +import { getSizeInPx } from "metabase/visualizations/shared/utils/size-in-px"; +import type { VisualizationTheme } from "metabase/visualizations/types"; + +/** + * Computes the visualization style from the Mantine theme. + */ +export function getVisualizationTheme( + options: MantineThemeOther, +): VisualizationTheme { + const { cartesian } = options; + + // This allows sdk users to set the base font size, + // which scales the visualization's font sizes. + const baseFontSize = getSizeInPx(options.fontSize); + + // ECharts requires font sizes in px for offset calculations. + const px = (value: string) => + getSizeInPx(value, baseFontSize) ?? baseFontSize ?? 14; + + return { + cartesian: { + label: { fontSize: px(cartesian.label.fontSize) }, + goalLine: { + label: { fontSize: px(cartesian.goalLine.label.fontSize) }, + }, + }, + }; +} + +export const DEFAULT_VISUALIZATION_THEME = getVisualizationTheme( + DEFAULT_METABASE_COMPONENT_THEME, +); diff --git a/frontend/src/metabase/visualizations/types/visualization.ts b/frontend/src/metabase/visualizations/types/visualization.ts index dd0ec98f2dd..5fa19f22936 100644 --- a/frontend/src/metabase/visualizations/types/visualization.ts +++ b/frontend/src/metabase/visualizations/types/visualization.ts @@ -31,6 +31,25 @@ export interface RenderingContext { measureText: TextWidthMeasurer; fontFamily: string; + + theme: VisualizationTheme; +} + +/** + * Visualization theming overrides. + * Refer to DEFAULT_METABASE_COMPONENT_THEME for the default values. + **/ +export interface VisualizationTheme { + cartesian: { + label: { + fontSize: number; + }; + goalLine: { + label: { + fontSize: number; + }; + }; + }; } export type OnChangeCardAndRunOpts = { diff --git a/frontend/src/metabase/visualizations/visualizations/BarChart/BarChart.stories.tsx b/frontend/src/metabase/visualizations/visualizations/BarChart/BarChart.stories.tsx new file mode 100644 index 00000000000..53755d658a9 --- /dev/null +++ b/frontend/src/metabase/visualizations/visualizations/BarChart/BarChart.stories.tsx @@ -0,0 +1,59 @@ +import type { Story } from "@storybook/react"; + +import { + SdkVisualizationWrapper, + VisualizationWrapper, +} from "__support__/storybook"; +import { NumberColumn, StringColumn } from "__support__/visualizations"; +import type { MetabaseTheme } from "embedding-sdk"; +import { Box } from "metabase/ui"; +import { registerVisualization } from "metabase/visualizations"; +import Visualization from "metabase/visualizations/components/Visualization"; +import { createMockCard } from "metabase-types/api/mocks"; + +import { BarChart } from "./BarChart"; + +export default { + title: "viz/BarChart", + component: BarChart, +}; + +// @ts-expect-error: incompatible prop types with registerVisualization +registerVisualization(BarChart); + +const MOCK_SERIES = [ + { + card: createMockCard({ name: "Card", display: "bar" }), + data: { + cols: [ + StringColumn({ name: "Dimension" }), + NumberColumn({ name: "Count" }), + ], + rows: [ + ["foo", 1], + ["bar", 2], + ], + }, + }, +]; + +export const Default: Story = () => ( + <VisualizationWrapper> + <Box h={500}> + <Visualization rawSeries={MOCK_SERIES} width={500} /> + </Box> + </VisualizationWrapper> +); + +// Example of how themes can be applied in the SDK. +export const EmbeddingHugeFont: Story = () => { + const theme: MetabaseTheme = { fontSize: "20px" }; + + return ( + <SdkVisualizationWrapper theme={theme}> + <Box h={500}> + <Visualization rawSeries={MOCK_SERIES} width={500} /> + </Box> + </SdkVisualizationWrapper> + ); +}; diff --git a/frontend/src/metabase/visualizations/visualizations/CartesianChart/use-models-and-option.ts b/frontend/src/metabase/visualizations/visualizations/CartesianChart/use-models-and-option.ts index 3320b4a2abc..a83514dc49d 100644 --- a/frontend/src/metabase/visualizations/visualizations/CartesianChart/use-models-and-option.ts +++ b/frontend/src/metabase/visualizations/visualizations/CartesianChart/use-models-and-option.ts @@ -33,6 +33,8 @@ export function useModelsAndOption({ onRender, hovered, }: VisualizationProps) { + const renderingContext = useBrowserRenderingContext({ fontFamily }); + const rawSeriesWithRemappings = useMemo( () => extractRemappings(rawSeries), [rawSeries], @@ -48,8 +50,6 @@ export function useModelsAndOption({ [onRender], ); - const renderingContext = useBrowserRenderingContext(fontFamily); - const hasTimelineEvents = timelineEvents ? timelineEvents.length !== 0 : false; diff --git a/frontend/src/metabase/visualizations/visualizations/Funnel/Funnel.tsx b/frontend/src/metabase/visualizations/visualizations/Funnel/Funnel.tsx index 17455f87e88..63504b5113b 100644 --- a/frontend/src/metabase/visualizations/visualizations/Funnel/Funnel.tsx +++ b/frontend/src/metabase/visualizations/visualizations/Funnel/Funnel.tsx @@ -204,7 +204,7 @@ export function Funnel(props: VisualizationProps) { } = props; const hasTitle = showTitle && settings["card.title"]; - const renderingContext = useBrowserRenderingContext(fontFamily); + const renderingContext = useBrowserRenderingContext({ fontFamily }); if (settings["funnel.type"] === "bar") { return ( diff --git a/frontend/src/metabase/visualizations/visualizations/Funnel/Funnel.unit.spec.jsx b/frontend/src/metabase/visualizations/visualizations/Funnel/Funnel.unit.spec.jsx index ed32f6bb970..a8b6a397a2d 100644 --- a/frontend/src/metabase/visualizations/visualizations/Funnel/Funnel.unit.spec.jsx +++ b/frontend/src/metabase/visualizations/visualizations/Funnel/Funnel.unit.spec.jsx @@ -1,4 +1,5 @@ import { render, screen } from "__support__/ui"; +import { ThemeProvider } from "metabase/ui"; import registerVisualizations from "metabase/visualizations/register"; import { createMockCard, @@ -45,14 +46,17 @@ const setup = (funnelProps, visualizationSettings = {}) => { }); render( - <Funnel - series={[series]} - rawSeries={[series]} - settings={settings} - visualizationIsClickable={jest.fn()} - card={card} - {...funnelProps} - />, + <ThemeProvider> + <Funnel + series={[series]} + rawSeries={[series]} + settings={settings} + visualizationIsClickable={jest.fn()} + card={card} + {...funnelProps} + /> + , + </ThemeProvider>, ); }; diff --git a/frontend/src/metabase/visualizations/visualizations/LineChart/LineChart.stories.tsx b/frontend/src/metabase/visualizations/visualizations/LineChart/LineChart.stories.tsx new file mode 100644 index 00000000000..a2988784d01 --- /dev/null +++ b/frontend/src/metabase/visualizations/visualizations/LineChart/LineChart.stories.tsx @@ -0,0 +1,66 @@ +import type { Story } from "@storybook/react"; + +import { + SdkVisualizationWrapper, + VisualizationWrapper, +} from "__support__/storybook"; +import { NumberColumn, StringColumn } from "__support__/visualizations"; +import type { MetabaseTheme } from "embedding-sdk"; +import { Box } from "metabase/ui"; +import { registerVisualization } from "metabase/visualizations"; +import Visualization from "metabase/visualizations/components/Visualization"; +import { + createMockCard, + createMockStructuredDatasetQuery, +} from "metabase-types/api/mocks"; + +import { LineChart } from "./LineChart"; + +export default { + title: "viz/LineChart", + component: LineChart, +}; + +// @ts-expect-error: incompatible prop types with registerVisualization +registerVisualization(LineChart); + +const dataset_query = createMockStructuredDatasetQuery({ + query: { "source-table": 1 }, +}); + +const MOCK_SERIES = [ + { + card: createMockCard({ id: 1, display: "line", dataset_query }), + data: { + cols: [ + StringColumn({ name: "Dimension" }), + NumberColumn({ name: "Count" }), + ], + rows: [ + ["foo", 4], + ["bar", 20], + ["baz", 12], + ], + }, + }, +]; + +export const Default: Story = () => ( + <VisualizationWrapper> + <Box h={500}> + <Visualization rawSeries={MOCK_SERIES} width={500} /> + </Box> + </VisualizationWrapper> +); + +export const EmbeddingHugeFont: Story = () => { + const theme: MetabaseTheme = { fontSize: "20px" }; + + return ( + <SdkVisualizationWrapper theme={theme}> + <Box h={500}> + <Visualization rawSeries={MOCK_SERIES} width={500} /> + </Box> + </SdkVisualizationWrapper> + ); +}; diff --git a/frontend/src/metabase/visualizations/visualizations/RowChart/RowChart.tsx b/frontend/src/metabase/visualizations/visualizations/RowChart/RowChart.tsx index 3322728ff57..ba1666de885 100644 --- a/frontend/src/metabase/visualizations/visualizations/RowChart/RowChart.tsx +++ b/frontend/src/metabase/visualizations/visualizations/RowChart/RowChart.tsx @@ -48,7 +48,7 @@ import { getHoverData, getLegendClickData, } from "metabase/visualizations/visualizations/RowChart/utils/events"; -import { getChartTheme } from "metabase/visualizations/visualizations/RowChart/utils/theme"; +import { useRowChartTheme } from "metabase/visualizations/visualizations/RowChart/utils/theme"; import { isDimension, isMetric } from "metabase-lib/v1/types/utils/isa"; import type { DatasetData, VisualizationSettings } from "metabase-types/api"; @@ -134,8 +134,8 @@ const RowChartVisualization = ({ [chartColumns, data, formatColumnValue], ); const goal = useMemo(() => getChartGoal(settings), [settings]); - const theme = useMemo(getChartTheme, []); const stackOffset = getStackOffset(settings); + const theme = useRowChartTheme({ fontFamily }); const chartWarnings = useMemo( () => getChartWarnings(chartColumns, data.rows), diff --git a/frontend/src/metabase/visualizations/visualizations/RowChart/utils/theme.ts b/frontend/src/metabase/visualizations/visualizations/RowChart/utils/theme.ts index 835caa2b1cd..36073fde259 100644 --- a/frontend/src/metabase/visualizations/visualizations/RowChart/utils/theme.ts +++ b/frontend/src/metabase/visualizations/visualizations/RowChart/utils/theme.ts @@ -1,40 +1,57 @@ +import { useMemo } from "react"; + import { color } from "metabase/lib/colors"; +import { useMantineTheme } from "metabase/ui"; import type { RowChartTheme } from "metabase/visualizations/shared/components/RowChart/types"; +import { getVisualizationTheme } from "metabase/visualizations/shared/utils/theme"; -export const getChartTheme = (fontFamily: string = "Lato"): RowChartTheme => { - return { - axis: { - color: color("border"), - ticks: { - size: 12, - weight: 700, - color: color("text-medium"), - family: fontFamily, +interface RowChartThemeOptions { + fontFamily?: string; +} + +export const useRowChartTheme = ( + options: RowChartThemeOptions, +): RowChartTheme => { + const theme = useMantineTheme(); + + return useMemo(() => { + const { fontFamily = "Lato" } = options; + const { cartesian } = getVisualizationTheme(theme.other); + + return { + axis: { + color: color("border"), + ticks: { + size: cartesian.label.fontSize, + weight: 700, + color: color("text-medium"), + family: fontFamily, + }, + label: { + size: cartesian.label.fontSize, + weight: 700, + color: color("text-dark"), + family: fontFamily, + }, + }, + goal: { + lineStroke: color("text-medium"), + label: { + size: cartesian.goalLine.label.fontSize, + weight: 700, + color: color("text-medium"), + family: fontFamily, + }, }, - label: { - size: 12, + dataLabels: { weight: 700, color: color("text-dark"), + size: cartesian.label.fontSize, family: fontFamily, }, - }, - goal: { - lineStroke: color("text-medium"), - label: { - size: 14, - weight: 700, - color: color("text-medium"), - family: fontFamily, + grid: { + color: color("border"), }, - }, - dataLabels: { - weight: 700, - color: color("text-dark"), - size: 12, - family: fontFamily, - }, - grid: { - color: color("border"), - }, - }; + }; + }, [options, theme]); }; diff --git a/frontend/src/metabase/visualizations/visualizations/SmartScalar/SmartScalar.stories.tsx b/frontend/src/metabase/visualizations/visualizations/SmartScalar/SmartScalar.stories.tsx index 28ee83b47c4..8b8e80c5ef0 100644 --- a/frontend/src/metabase/visualizations/visualizations/SmartScalar/SmartScalar.stories.tsx +++ b/frontend/src/metabase/visualizations/visualizations/SmartScalar/SmartScalar.stories.tsx @@ -4,6 +4,7 @@ import { SdkVisualizationWrapper, VisualizationWrapper, } from "__support__/storybook"; +import type { MetabaseTheme } from "embedding-sdk"; import { registerVisualization } from "metabase/visualizations"; import Visualization from "metabase/visualizations/components/Visualization"; @@ -36,7 +37,7 @@ export const Default: Story = () => ( // Example of how themes can be applied in the SDK. export const EmbeddingTemplate: Story = () => { - const theme = { + const theme: MetabaseTheme = { colors: { positive: "#4834d4", negative: "#e84118", diff --git a/loki.config.js b/loki.config.js index e684dd31599..35fd56a7256 100644 --- a/loki.config.js +++ b/loki.config.js @@ -1,6 +1,6 @@ module.exports = { diffingEngine: "looks-same", - storiesFilter: "static-viz|viz", + storiesFilter: "static-viz|viz|visualizations/shared", configurations: { "chrome.laptop": { target: "chrome.docker", diff --git a/webpack.static-viz.config.js b/webpack.static-viz.config.js index c69db2e5dc7..8fac3ca092d 100644 --- a/webpack.static-viz.config.js +++ b/webpack.static-viz.config.js @@ -9,6 +9,7 @@ const CLJS_SRC_PATH = __dirname + "/target/cljs_release"; const CLJS_SRC_PATH_DEV = __dirname + "/target/cljs_dev"; const LIB_SRC_PATH = __dirname + "/frontend/src/metabase-lib"; const TYPES_SRC_PATH = __dirname + "/frontend/src/metabase-types"; +const SDK_SRC_PATH = __dirname + "/enterprise/frontend/src/embedding-sdk"; const BABEL_CONFIG = { cacheDirectory: process.env.BABEL_DISABLE_CACHE ? null : ".babel_cache", @@ -89,6 +90,7 @@ module.exports = env => { cljs: devMode ? CLJS_SRC_PATH_DEV : CLJS_SRC_PATH, "metabase-lib": LIB_SRC_PATH, "metabase-types": TYPES_SRC_PATH, + "embedding-sdk": SDK_SRC_PATH, }, }, optimization: { -- GitLab