@openshift-migration-advisor/shared-components 0.27.0-ad43dbdf05ab → 0.28.0-16fc442157c1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"MigrationDonutChart.d.ts","sourceRoot":"","sources":["../../src/charts/MigrationDonutChart.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,EAAE,EAAgB,MAAM,OAAO,CAAC;AAG9C,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1C,WAAW,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,MAAM,gCAAgC,GAAG,MAAM,GAAG,OAAO,CAAC;AAEhE,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,wBAAwB,EAAE,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qBAAqB,CAAC,EAAE,CAAC,IAAI,EAAE;QAC7B,KAAK,EAAE;YACL,CAAC,EAAE,MAAM,CAAC;YACV,CAAC,EAAE,MAAM,CAAC;YACV,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;YAC/B,cAAc,EAAE,MAAM,CAAC;SACxB,CAAC;QACF,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;KACf,KAAK,MAAM,CAAC;IACb,iDAAiD;IACjD,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,wBAAwB,KAAK,IAAI,CAAC;IACvD,gDAAgD;IAChD,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,mFAAmF;IACnF,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE;QAC5B,CAAC,EAAE,MAAM,CAAC;QACV,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;KAChC,KAAK,MAAM,CAAC;IACb;;;;OAIG;IACH,aAAa,CAAC,EAAE,gCAAgC,CAAC;IACjD,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0EAA0E;IAC1E,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AA8ED,eAAO,MAAM,mBAAmB,EAAE,EAAE,CAAC,wBAAwB,CAiX5D,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"MigrationDonutChart.d.ts","sourceRoot":"","sources":["../../src/charts/MigrationDonutChart.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,EAAE,EAAgB,MAAM,OAAO,CAAC;AAG9C,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1C,WAAW,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,MAAM,gCAAgC,GAAG,MAAM,GAAG,OAAO,CAAC;AAEhE,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,wBAAwB,EAAE,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qBAAqB,CAAC,EAAE,CAAC,IAAI,EAAE;QAC7B,KAAK,EAAE;YACL,CAAC,EAAE,MAAM,CAAC;YACV,CAAC,EAAE,MAAM,CAAC;YACV,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;YAC/B,cAAc,EAAE,MAAM,CAAC;SACxB,CAAC;QACF,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;KACf,KAAK,MAAM,CAAC;IACb,iDAAiD;IACjD,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,wBAAwB,KAAK,IAAI,CAAC;IACvD,gDAAgD;IAChD,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,mFAAmF;IACnF,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE;QAC5B,CAAC,EAAE,MAAM,CAAC;QACV,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;KAChC,KAAK,MAAM,CAAC;IACb;;;;OAIG;IACH,aAAa,CAAC,EAAE,gCAAgC,CAAC;IACjD,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0EAA0E;IAC1E,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAoFD,eAAO,MAAM,mBAAmB,EAAE,EAAE,CAAC,wBAAwB,CAoX5D,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
@@ -35,6 +35,8 @@ const themedChartTooltipFlyoutPadding = {
35
35
  left: 10,
36
36
  right: 10,
37
37
  };
38
+ /** Victory SVG text defaults to a serif face; match PatternFly / html2canvas export. */
39
+ const chartTextFontFamily = "RedHatText, Overpass, Helvetica, Arial, sans-serif";
38
40
  const styles = {
39
41
  legendIcon: css `
40
42
  margin-right: 4px;
@@ -63,6 +65,7 @@ const styles = {
63
65
  background: none;
64
66
  padding: var(--pf-t--global--spacer--xs) var(--pf-t--global--spacer--ml);
65
67
  margin: 0;
68
+ font-family: ${chartTextFontFamily};
66
69
  transition: opacity var(--pf-t--global--motion--duration--short);
67
70
  white-space: nowrap;
68
71
 
@@ -73,6 +76,7 @@ const styles = {
73
76
  legendLabel: css `
74
77
  gap: var(--pf-t--global--spacer--lg);
75
78
  padding: var(--pf-t--global--spacer--xs) var(--pf-t--global--spacer--ml);
79
+ font-family: ${chartTextFontFamily};
76
80
  white-space: nowrap;
77
81
  `,
78
82
  legendInner: css `
@@ -214,6 +218,7 @@ export const MigrationDonutChart = ({ data, legend, customColors, height = 260,
214
218
  labels: {
215
219
  fontSize: labelFontSize,
216
220
  fill: "var(--pf-t--global--text--color--regular)",
221
+ fontFamily: chartTextFontFamily,
217
222
  },
218
223
  } }) }) }) }));
219
224
  return (_jsxs(Flex, { direction: { default: "column" }, alignItems: { default: "alignItemsCenter" }, className: `${onItemClick ? styles.cursorPointer : styles.cursorDefault} ${styles.chartContainer}`, children: [_jsxs("div", { className: styles.donutWrapper, children: [_jsx(ChartDonut, { ariaDesc: "Migration data donut chart", data: chartData, events: chartEvents, labelComponent: donutTooltip, labels: ({ datum, }) => formatLabel(datum), colorScale: colorScale, constrainToVisibleArea: true, innerRadius: innerRadius, padAngle: padAngle, title: title, subTitle: subTitle, height: height, width: width, padding: {
@@ -226,11 +231,13 @@ export const MigrationDonutChart = ({ data, legend, customColors, height = 260,
226
231
  fill: titleColor,
227
232
  fontSize: titleFontSize,
228
233
  fontWeight: "bold",
234
+ fontFamily: chartTextFontFamily,
229
235
  },
230
236
  ] })) : undefined, subTitleComponent: subTitle ? (_jsx(ChartLabel, { dy: showChartLegend ? 7 : undefined, style: [
231
237
  {
232
238
  fill: subTitleColor,
233
239
  fontSize: subTitleFontSize,
240
+ fontFamily: chartTextFontFamily,
234
241
  },
235
242
  ] })) : undefined }), onTitleClick && title && (_jsx("div", { onClick: onTitleClick, className: css `
236
243
  position: absolute;
@@ -1,6 +1,6 @@
1
1
  import { type FC, type ReactNode } from "react";
2
2
  import { type ChartCaptureSource, type ChartExportFile, type PdfTextPage } from "./chartExport.js";
3
- export type CaptureChartElement = (element: HTMLElement) => Promise<HTMLCanvasElement>;
3
+ export type CaptureChartElement = (element: HTMLElement, options?: import("./captureChartElement.js").CaptureChartElementOptions) => Promise<HTMLCanvasElement>;
4
4
  export type ZipChartFiles = (files: ChartExportFile[]) => Promise<Blob>;
5
5
  export type EncodeChartPng = (canvas: HTMLCanvasElement) => Promise<Blob>;
6
6
  export type BuildChartDocument = (charts: ChartCaptureSource[], documentTitle: string) => Promise<Blob>;
@@ -1 +1 @@
1
- {"version":3,"file":"ChartExportProvider.d.ts","sourceRoot":"","sources":["../../src/report/ChartExportProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EAAE,EACP,KAAK,SAAS,EAKf,MAAM,OAAO,CAAC;AACf,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,eAAe,EAGpB,KAAK,WAAW,EAMjB,MAAM,kBAAkB,CAAC;AAU1B,MAAM,MAAM,mBAAmB,GAAG,CAChC,OAAO,EAAE,WAAW,KACjB,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAChC,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AACxE,MAAM,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAC1E,MAAM,MAAM,kBAAkB,GAAG,CAC/B,MAAM,EAAE,kBAAkB,EAAE,EAC5B,aAAa,EAAE,MAAM,KAClB,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,MAAM,MAAM,gBAAgB,GAAG,CAC7B,MAAM,EAAE,kBAAkB,EAAE,EAC5B,aAAa,EAAE,MAAM,EACrB,UAAU,CAAC,EAAE,WAAW,EAAE,KACvB,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,YAAY,EACV,cAAc,EACd,iBAAiB,GAClB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACtD,cAAc,CAAC,EAAE,MAAM,MAAM,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,MAAM,CAAC;IAC9B,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;CAChC;AAsED,eAAO,MAAM,mBAAmB,EAAE,EAAE,CAAC,wBAAwB,CAiQ5D,CAAC"}
1
+ {"version":3,"file":"ChartExportProvider.d.ts","sourceRoot":"","sources":["../../src/report/ChartExportProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EAAE,EACP,KAAK,SAAS,EAKf,MAAM,OAAO,CAAC;AAEf,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,eAAe,EAGpB,KAAK,WAAW,EAMjB,MAAM,kBAAkB,CAAC;AAU1B,MAAM,MAAM,mBAAmB,GAAG,CAChC,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE,OAAO,0BAA0B,EAAE,0BAA0B,KACpE,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAChC,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AACxE,MAAM,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAC1E,MAAM,MAAM,kBAAkB,GAAG,CAC/B,MAAM,EAAE,kBAAkB,EAAE,EAC5B,aAAa,EAAE,MAAM,KAClB,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,MAAM,MAAM,gBAAgB,GAAG,CAC7B,MAAM,EAAE,kBAAkB,EAAE,EAC5B,aAAa,EAAE,MAAM,EACrB,UAAU,CAAC,EAAE,WAAW,EAAE,KACvB,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,YAAY,EACV,cAAc,EACd,iBAAiB,GAClB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACtD,cAAc,CAAC,EAAE,MAAM,MAAM,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,MAAM,CAAC;IAC9B,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;CAChC;AAsED,eAAO,MAAM,mBAAmB,EAAE,EAAE,CAAC,wBAAwB,CAmQ5D,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useCallback, useMemo, useRef, useState, } from "react";
3
+ import { CHART_CAPTURE_SCALE_SINGLE } from "./captureChartElement.js";
3
4
  import { canvasToBlob, downloadBlob, releaseCanvas, restoreChartExportViews, sortRegisteredChartsByDocumentOrder, toBulkChartCaptureSources, } from "./chartExport.js";
4
5
  import { ChartExportApiContext, ChartExportRegistryContext, } from "./chartExportContext.js";
5
6
  import { getChartExportFilename } from "./chartExportFilenames.js";
@@ -108,7 +109,9 @@ export const ChartExportProvider = ({ children, capture, zipFiles, encodePng = c
108
109
  throw new Error("The chart is not ready to export yet.");
109
110
  }
110
111
  const captureFn = await resolveCapture(capture);
111
- const canvas = await captureFn(chart.element);
112
+ const canvas = await captureFn(chart.element, {
113
+ scale: CHART_CAPTURE_SCALE_SINGLE,
114
+ });
112
115
  try {
113
116
  downloadFile(await encodePng(canvas), chart.filename);
114
117
  }
@@ -8,6 +8,6 @@ export const FeatureStatusBadge = ({ status }) => {
8
8
  if (status === "enabled") {
9
9
  return (_jsx(Label, { color: "green", isCompact: true, icon: _jsx(CheckCircleIcon, {}), children: "Enabled" }));
10
10
  }
11
- return (_jsx(Label, { color: "grey", isCompact: true, icon: _jsx(TimesCircleIcon, {}), children: "Disabled" }));
11
+ return (_jsx(Label, { variant: "outline", isCompact: true, icon: _jsx(TimesCircleIcon, {}), children: "Disabled" }));
12
12
  };
13
13
  FeatureStatusBadge.displayName = "FeatureStatusBadge";
@@ -1,8 +1,13 @@
1
+ export declare const CHART_CAPTURE_SCALE_SINGLE = 2;
2
+ export type CaptureChartElementOptions = {
3
+ /** Higher scale sharpens text in PNG exports; keep at 1 for bulk PDF/zip. */
4
+ scale?: number;
5
+ };
1
6
  /**
2
7
  * Tab panels stay mounted with `hidden` / `display:none` when another tab is
3
8
  * active. html2canvas then measures a 0×0 box. Reveal those ancestors off-screen
4
9
  * for the duration of the capture, then restore.
5
10
  */
6
11
  export declare function revealHiddenChartAncestors(element: HTMLElement): () => void;
7
- export declare function captureChartElement(element: HTMLElement): Promise<HTMLCanvasElement>;
12
+ export declare function captureChartElement(element: HTMLElement, options?: CaptureChartElementOptions): Promise<HTMLCanvasElement>;
8
13
  //# sourceMappingURL=captureChartElement.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"captureChartElement.d.ts","sourceRoot":"","sources":["../../src/report/captureChartElement.ts"],"names":[],"mappings":"AAsCA;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,IAAI,CAqD3E;AAuQD,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,iBAAiB,CAAC,CAoC5B"}
1
+ {"version":3,"file":"captureChartElement.d.ts","sourceRoot":"","sources":["../../src/report/captureChartElement.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAG5C,MAAM,MAAM,0BAA0B,GAAG;IACvC,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAwBF;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,IAAI,CAqD3E;AAwQD,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,WAAW,EACpB,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,iBAAiB,CAAC,CA0C5B"}
@@ -1,8 +1,10 @@
1
1
  import { t_color_gray_20, t_color_white, t_global_text_color_regular, } from "@patternfly/react-tokens";
2
2
  import html2canvas from "html2canvas-pro";
3
3
  import { applyLightThemeToDocument, CHART_EXPORT_CAPTURING_ATTR, CHART_EXPORT_SCROLL_ATTR, shouldIgnoreChartExportElement, } from "./chartExport.js";
4
- /** CSS-pixel scale; 2x made zip-all of ~15 live cards too slow. */
5
- const CHART_CAPTURE_SCALE = 1;
4
+ /** Default scale for bulk exports; single-chart PNG uses a higher scale. */
5
+ const CHART_CAPTURE_SCALE_DEFAULT = 1;
6
+ export const CHART_CAPTURE_SCALE_SINGLE = 2;
7
+ const EXPORT_FONT_FAMILY = "RedHatText, Overpass, Helvetica, Arial, sans-serif";
6
8
  const HIDDEN_LAYOUT_STYLE_KEYS = [
7
9
  "display",
8
10
  "position",
@@ -140,6 +142,7 @@ function applyLightThemeSvgText(root) {
140
142
  }
141
143
  node.style.fill = LIGHT_EXPORT_TEXT;
142
144
  node.style.color = LIGHT_EXPORT_TEXT;
145
+ node.style.fontFamily = EXPORT_FONT_FAMILY;
143
146
  }
144
147
  }
145
148
  function hideCardBeforePseudo() {
@@ -266,7 +269,8 @@ function prepareCaptureLayout(element) {
266
269
  }
267
270
  };
268
271
  }
269
- export async function captureChartElement(element) {
272
+ export async function captureChartElement(element, options = {}) {
273
+ const scale = options.scale ?? CHART_CAPTURE_SCALE_DEFAULT;
270
274
  const restoreHidden = revealHiddenChartAncestors(element);
271
275
  const restoreLayout = prepareCaptureLayout(element);
272
276
  element.setAttribute(CHART_EXPORT_CAPTURING_ATTR, "");
@@ -284,14 +288,19 @@ export async function captureChartElement(element) {
284
288
  useCORS: true,
285
289
  backgroundColor: LIGHT_EXPORT_BACKGROUND,
286
290
  logging: false,
287
- scale: CHART_CAPTURE_SCALE,
291
+ scale,
288
292
  imageTimeout: 0,
289
293
  ignoreElements: (node) => node instanceof Element &&
290
294
  shouldIgnoreChartExportElement(node, element),
291
295
  onclone: (clonedDoc, clonedElement) => {
296
+ // Dropping the dark-theme class off the clone root makes every
297
+ // PatternFly CSS-variable surface (cards, tables, labels) resolve to
298
+ // light automatically — html2canvas reads computed styles from this
299
+ // clone. Only Victory's inlined SVG text needs explicit recoloring.
292
300
  applyLightThemeToDocument(clonedDoc);
293
301
  applyComputedStylesToClone(element, clonedElement);
294
302
  applyLightThemeSvgText(clonedElement);
303
+ clonedElement.style.fontFamily = EXPORT_FONT_FAMILY;
295
304
  },
296
305
  });
297
306
  }
@@ -9,7 +9,7 @@ export const chartExportScrollProps = {
9
9
  };
10
10
  export const chartExportRootStyle = {
11
11
  width: "100%",
12
- height: "100%",
12
+ height: "auto",
13
13
  };
14
14
  export function releaseCanvas(canvas) {
15
15
  canvas.width = 0;
@@ -3,6 +3,12 @@ export declare const dashboardStyles: {
3
3
  cardScroll: string;
4
4
  equalHeightRow: string;
5
5
  equalHeight: string;
6
+ /**
7
+ * Flex child of {@link dashboardStyles.card}. `min-height: 0` lets the body
8
+ * shrink inside the card max-height; `overflow: auto` scrolls tables and tall
9
+ * charts when needed (phantom scrollbars on donut cards are avoided by the
10
+ * card layout and ChartExportSurface sizing, not a second body class).
11
+ */
6
12
  cardBodyScrollable: string;
7
13
  card: string;
8
14
  storageCardOverflowHidden: string;
@@ -1 +1 @@
1
- {"version":3,"file":"dashboardStyles.d.ts","sourceRoot":"","sources":["../../src/report/dashboardStyles.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,eAAe;;;;;;;;;;;;;CAkF3B,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAM/B,CAAC"}
1
+ {"version":3,"file":"dashboardStyles.d.ts","sourceRoot":"","sources":["../../src/report/dashboardStyles.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,eAAe;;;;;IA8B1B;;;;;OAKG;;;;;;;;;CAkDJ,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAM/B,CAAC"}
@@ -25,6 +25,12 @@ export const dashboardStyles = {
25
25
  flex: 1 1 0;
26
26
  height: 100%;
27
27
  `,
28
+ /**
29
+ * Flex child of {@link dashboardStyles.card}. `min-height: 0` lets the body
30
+ * shrink inside the card max-height; `overflow: auto` scrolls tables and tall
31
+ * charts when needed (phantom scrollbars on donut cards are avoided by the
32
+ * card layout and ChartExportSurface sizing, not a second body class).
33
+ */
28
34
  cardBodyScrollable: css `
29
35
  overflow: auto;
30
36
  `,
@@ -32,12 +38,9 @@ export const dashboardStyles = {
32
38
  // at the same specificity, which wins in the production build due to stylesheet
33
39
  // injection order. `!important` forces `hidden` regardless of that order.
34
40
  card: css `
35
- min-height: 430px;
36
- max-height: 520px;
37
- height: 100%;
41
+ height: 520px;
38
42
  display: flex;
39
43
  flex-direction: column;
40
- justify-content: space-between;
41
44
  overflow: hidden !important;
42
45
  `,
43
46
  storageCardOverflowHidden: css `
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openshift-migration-advisor/shared-components",
3
- "version": "0.27.0-ad43dbdf05ab",
3
+ "version": "0.28.0-16fc442157c1",
4
4
  "description": "Shared React UI components for Migration Advisor apps (report charts, forms, OS support tiers)",
5
5
  "author": "Montse Ortega <mortegag@redhat.com>",
6
6
  "license": "Apache-2.0",
@@ -46,7 +46,7 @@
46
46
  "README.md"
47
47
  ],
48
48
  "dependencies": {
49
- "html2canvas-pro": "^2.5.1",
49
+ "html2canvas-pro": "^2.5.2",
50
50
  "jspdf": "^4.2.1",
51
51
  "jszip": "^3.10.2"
52
52
  }
@@ -108,6 +108,10 @@ const themedChartTooltipFlyoutPadding = {
108
108
  right: 10,
109
109
  } as const;
110
110
 
111
+ /** Victory SVG text defaults to a serif face; match PatternFly / html2canvas export. */
112
+ const chartTextFontFamily =
113
+ "RedHatText, Overpass, Helvetica, Arial, sans-serif";
114
+
111
115
  const styles = {
112
116
  legendIcon: css`
113
117
  margin-right: 4px;
@@ -136,6 +140,7 @@ const styles = {
136
140
  background: none;
137
141
  padding: var(--pf-t--global--spacer--xs) var(--pf-t--global--spacer--ml);
138
142
  margin: 0;
143
+ font-family: ${chartTextFontFamily};
139
144
  transition: opacity var(--pf-t--global--motion--duration--short);
140
145
  white-space: nowrap;
141
146
 
@@ -146,6 +151,7 @@ const styles = {
146
151
  legendLabel: css`
147
152
  gap: var(--pf-t--global--spacer--lg);
148
153
  padding: var(--pf-t--global--spacer--xs) var(--pf-t--global--spacer--ml);
154
+ font-family: ${chartTextFontFamily};
149
155
  white-space: nowrap;
150
156
  `,
151
157
  legendInner: css`
@@ -422,6 +428,7 @@ export const MigrationDonutChart: FC<MigrationDonutChartProps> = ({
422
428
  labels: {
423
429
  fontSize: labelFontSize,
424
430
  fill: "var(--pf-t--global--text--color--regular)",
431
+ fontFamily: chartTextFontFamily,
425
432
  },
426
433
  }}
427
434
  />
@@ -474,6 +481,7 @@ export const MigrationDonutChart: FC<MigrationDonutChartProps> = ({
474
481
  fill: titleColor,
475
482
  fontSize: titleFontSize,
476
483
  fontWeight: "bold",
484
+ fontFamily: chartTextFontFamily,
477
485
  },
478
486
  ]}
479
487
  />
@@ -487,6 +495,7 @@ export const MigrationDonutChart: FC<MigrationDonutChartProps> = ({
487
495
  {
488
496
  fill: subTitleColor,
489
497
  fontSize: subTitleFontSize,
498
+ fontFamily: chartTextFontFamily,
490
499
  },
491
500
  ]}
492
501
  />
@@ -6,6 +6,7 @@ import {
6
6
  useRef,
7
7
  useState,
8
8
  } from "react";
9
+ import { CHART_CAPTURE_SCALE_SINGLE } from "./captureChartElement.js";
9
10
  import {
10
11
  type ChartCaptureSource,
11
12
  type ChartExportFile,
@@ -29,6 +30,7 @@ import { getChartExportFilename } from "./chartExportFilenames.js";
29
30
 
30
31
  export type CaptureChartElement = (
31
32
  element: HTMLElement,
33
+ options?: import("./captureChartElement.js").CaptureChartElementOptions,
32
34
  ) => Promise<HTMLCanvasElement>;
33
35
  export type ZipChartFiles = (files: ChartExportFile[]) => Promise<Blob>;
34
36
  export type EncodeChartPng = (canvas: HTMLCanvasElement) => Promise<Blob>;
@@ -227,7 +229,9 @@ export const ChartExportProvider: FC<ChartExportProviderProps> = ({
227
229
  throw new Error("The chart is not ready to export yet.");
228
230
  }
229
231
  const captureFn = await resolveCapture(capture);
230
- const canvas = await captureFn(chart.element);
232
+ const canvas = await captureFn(chart.element, {
233
+ scale: CHART_CAPTURE_SCALE_SINGLE,
234
+ });
231
235
  try {
232
236
  downloadFile(await encodePng(canvas), chart.filename);
233
237
  } finally {
@@ -21,7 +21,7 @@ export const FeatureStatusBadge: FC<FeatureStatusBadgeProps> = ({ status }) => {
21
21
  }
22
22
 
23
23
  return (
24
- <Label color="grey" isCompact icon={<TimesCircleIcon />}>
24
+ <Label variant="outline" isCompact icon={<TimesCircleIcon />}>
25
25
  Disabled
26
26
  </Label>
27
27
  );
@@ -202,4 +202,51 @@ describe("captureChartElement", () => {
202
202
  ).toBe(true);
203
203
  expect(card.style.backgroundColor).toBe("rgb(30, 30, 30)");
204
204
  });
205
+
206
+ it("relights tables and labels via the clone cascade, not by hand-painting them", async () => {
207
+ document.documentElement.classList.add("pf-v6-theme-dark");
208
+ const root = document.createElement("div");
209
+ const label = document.createElement("span");
210
+ label.className = "pf-v6-c-label pf-m-compact pf-m-outline";
211
+ const labelContent = document.createElement("span");
212
+ labelContent.className = "pf-v6-c-label__content";
213
+ label.append(labelContent);
214
+ root.append(label);
215
+ document.body.append(root);
216
+
217
+ mockedHtml2Canvas.mockImplementation(async (_element, options) => {
218
+ const clonedDoc = document.implementation.createHTMLDocument("export");
219
+ clonedDoc.documentElement.classList.add("pf-v6-theme-dark");
220
+ const cloneRoot = clonedDoc.createElement("div");
221
+ const cloneTh = clonedDoc.createElement("th");
222
+ cloneTh.className = "pf-v6-c-table__th";
223
+ const cloneLabelContent = clonedDoc.createElement("span");
224
+ cloneLabelContent.className = "pf-v6-c-label__content";
225
+ cloneRoot.append(cloneTh, cloneLabelContent);
226
+ clonedDoc.body.append(cloneRoot);
227
+
228
+ await options?.onclone?.(clonedDoc, cloneRoot);
229
+
230
+ // Dropping the dark class off the clone root is what relights these
231
+ // surfaces — the cascade does the work. We must NOT hand-paint inline
232
+ // colors onto PatternFly table/label nodes, and the live page stays dark.
233
+ expect(
234
+ clonedDoc.documentElement.classList.contains("pf-v6-theme-dark"),
235
+ ).toBe(false);
236
+ expect(cloneTh.style.backgroundColor).toBe("");
237
+ expect(cloneLabelContent.style.backgroundColor).toBe("");
238
+
239
+ const canvas = document.createElement("canvas");
240
+ canvas.width = 1;
241
+ canvas.height = 1;
242
+ return canvas;
243
+ });
244
+
245
+ await captureChartElement(root);
246
+
247
+ expect(
248
+ document.documentElement.classList.contains("pf-v6-theme-dark"),
249
+ ).toBe(true);
250
+ expect(labelContent.style.backgroundColor).toBe("");
251
+ });
205
252
  });
@@ -11,8 +11,15 @@ import {
11
11
  shouldIgnoreChartExportElement,
12
12
  } from "./chartExport.js";
13
13
 
14
- /** CSS-pixel scale; 2x made zip-all of ~15 live cards too slow. */
15
- const CHART_CAPTURE_SCALE = 1;
14
+ /** Default scale for bulk exports; single-chart PNG uses a higher scale. */
15
+ const CHART_CAPTURE_SCALE_DEFAULT = 1;
16
+ export const CHART_CAPTURE_SCALE_SINGLE = 2;
17
+ const EXPORT_FONT_FAMILY = "RedHatText, Overpass, Helvetica, Arial, sans-serif";
18
+
19
+ export type CaptureChartElementOptions = {
20
+ /** Higher scale sharpens text in PNG exports; keep at 1 for bulk PDF/zip. */
21
+ scale?: number;
22
+ };
16
23
  const HIDDEN_LAYOUT_STYLE_KEYS = [
17
24
  "display",
18
25
  "position",
@@ -187,6 +194,7 @@ function applyLightThemeSvgText(root: HTMLElement): void {
187
194
  }
188
195
  node.style.fill = LIGHT_EXPORT_TEXT;
189
196
  node.style.color = LIGHT_EXPORT_TEXT;
197
+ node.style.fontFamily = EXPORT_FONT_FAMILY;
190
198
  }
191
199
  }
192
200
 
@@ -359,7 +367,9 @@ function prepareCaptureLayout(element: HTMLElement): () => void {
359
367
 
360
368
  export async function captureChartElement(
361
369
  element: HTMLElement,
370
+ options: CaptureChartElementOptions = {},
362
371
  ): Promise<HTMLCanvasElement> {
372
+ const scale = options.scale ?? CHART_CAPTURE_SCALE_DEFAULT;
363
373
  const restoreHidden = revealHiddenChartAncestors(element);
364
374
  const restoreLayout = prepareCaptureLayout(element);
365
375
  element.setAttribute(CHART_EXPORT_CAPTURING_ATTR, "");
@@ -378,15 +388,20 @@ export async function captureChartElement(
378
388
  useCORS: true,
379
389
  backgroundColor: LIGHT_EXPORT_BACKGROUND,
380
390
  logging: false,
381
- scale: CHART_CAPTURE_SCALE,
391
+ scale,
382
392
  imageTimeout: 0,
383
393
  ignoreElements: (node) =>
384
394
  node instanceof Element &&
385
395
  shouldIgnoreChartExportElement(node, element),
386
396
  onclone: (clonedDoc, clonedElement) => {
397
+ // Dropping the dark-theme class off the clone root makes every
398
+ // PatternFly CSS-variable surface (cards, tables, labels) resolve to
399
+ // light automatically — html2canvas reads computed styles from this
400
+ // clone. Only Victory's inlined SVG text needs explicit recoloring.
387
401
  applyLightThemeToDocument(clonedDoc);
388
402
  applyComputedStylesToClone(element, clonedElement);
389
403
  applyLightThemeSvgText(clonedElement);
404
+ clonedElement.style.fontFamily = EXPORT_FONT_FAMILY;
390
405
  },
391
406
  });
392
407
  } finally {
@@ -14,7 +14,7 @@ export const chartExportScrollProps = {
14
14
 
15
15
  export const chartExportRootStyle: CSSProperties = {
16
16
  width: "100%",
17
- height: "100%",
17
+ height: "auto",
18
18
  };
19
19
 
20
20
  export type ChartExportMeta = {
@@ -30,6 +30,12 @@ export const dashboardStyles = {
30
30
  height: 100%;
31
31
  `,
32
32
 
33
+ /**
34
+ * Flex child of {@link dashboardStyles.card}. `min-height: 0` lets the body
35
+ * shrink inside the card max-height; `overflow: auto` scrolls tables and tall
36
+ * charts when needed (phantom scrollbars on donut cards are avoided by the
37
+ * card layout and ChartExportSurface sizing, not a second body class).
38
+ */
33
39
  cardBodyScrollable: css`
34
40
  overflow: auto;
35
41
  `,
@@ -38,12 +44,9 @@ export const dashboardStyles = {
38
44
  // at the same specificity, which wins in the production build due to stylesheet
39
45
  // injection order. `!important` forces `hidden` regardless of that order.
40
46
  card: css`
41
- min-height: 430px;
42
- max-height: 520px;
43
- height: 100%;
47
+ height: 520px;
44
48
  display: flex;
45
49
  flex-direction: column;
46
- justify-content: space-between;
47
50
  overflow: hidden !important;
48
51
  `,
49
52