@cloudscape-design/chart-components 1.0.92 → 1.0.93

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.
@@ -22,16 +22,36 @@ export function ChartContainer({ chart, verticalAxisTitle, verticalAxisTitlePlac
22
22
  const withMinHeight = (height) => Math.max(chartMinHeight !== null && chartMinHeight !== void 0 ? chartMinHeight : DEFAULT_CHART_MIN_HEIGHT, height) - heightOffset;
23
23
  const measuredChartHeight = withMinHeight(measures.chart - measures.header - measures.footer);
24
24
  const effectiveChartHeight = fitHeight ? measuredChartHeight : withMinHeight(chartHeight !== null && chartHeight !== void 0 ? chartHeight : DEFAULT_CHART_HEIGHT);
25
- const hasLegend = primaryLegend || secondaryLegend;
25
+ const hasLegend = !!(primaryLegend || secondaryLegend);
26
26
  return (_jsxs("div", { ref: refs.chart, className: clsx({
27
27
  [styles["chart-container-fit-height"]]: fitHeight,
28
28
  [styles["chart-container-min-width"]]: chartMinWidth !== undefined,
29
- }), children: [_jsxs("div", { ref: refs.header, children: [header, filter] }), hasLegend && legendPosition === "side" ? (_jsxs("div", { className: styles["chart-plot-and-legend-wrapper"], children: [_jsxs("div", { style: { minInlineSize: chartMinWidth !== null && chartMinWidth !== void 0 ? chartMinWidth : 0 }, className: clsx(styles["chart-plot-wrapper"], testClasses["chart-plot-wrapper"]), children: [verticalAxisTitle, chart(effectiveChartHeight), noData] }), _jsxs("div", { className: styles["side-legend-container"], style: { maxBlockSize: effectiveChartHeight }, children: [primaryLegend, secondaryLegend] })] })) : (_jsxs("div", { style: chartMinWidth !== undefined ? { minInlineSize: chartMinWidth } : {}, className: clsx(styles["chart-plot-wrapper"], testClasses["chart-plot-wrapper"]), children: [verticalAxisTitle, chart(effectiveChartHeight), !hasLegend || legendPosition === "bottom" ? noData : null] })), _jsxs("div", { ref: refs.footer, style: chartMinWidth !== undefined ? { minInlineSize: chartMinWidth } : {}, children: [navigator && _jsx("div", { className: testClasses["chart-navigator"], children: navigator }), hasLegend && legendPosition === "bottom" && (_jsxs("div", { className: styles["bottom-legend-container"], style: { maxBlockSize: legendBottomMaxHeight ? `${legendBottomMaxHeight}px` : undefined }, children: [primaryLegend, secondaryLegend] })), footer] })] }));
29
+ }), children: [_jsxs("div", { ref: refs.header, children: [header, filter] }), hasLegend && legendPosition === "side" ? (_jsxs("div", { className: styles["chart-plot-and-legend-wrapper"], children: [_jsxs("div", { style: { minInlineSize: chartMinWidth !== null && chartMinWidth !== void 0 ? chartMinWidth : 0 }, className: clsx(styles["chart-plot-wrapper"], testClasses["chart-plot-wrapper"]), children: [verticalAxisTitle, chart(effectiveChartHeight), noData] }), _jsxs("div", { className: styles["side-legend-container"], style: { maxBlockSize: effectiveChartHeight }, children: [primaryLegend, secondaryLegend] })] })) : (_jsxs("div", { className: clsx(styles["chart-plot-wrapper"], testClasses["chart-plot-wrapper"]), style: getChartPlotWrapperStyles({
30
+ measures,
31
+ fitHeight,
32
+ hasLegend,
33
+ chartMinWidth,
34
+ legendPosition,
35
+ }), children: [verticalAxisTitle, chart(effectiveChartHeight), !hasLegend || legendPosition === "bottom" ? noData : null] })), _jsxs("div", { ref: refs.footer, style: chartMinWidth !== undefined ? { minInlineSize: chartMinWidth } : {}, children: [navigator && _jsx("div", { className: testClasses["chart-navigator"], children: navigator }), hasLegend && legendPosition === "bottom" && (_jsxs("div", { className: styles["bottom-legend-container"], style: { maxBlockSize: legendBottomMaxHeight ? `${legendBottomMaxHeight}px` : undefined }, children: [primaryLegend, secondaryLegend] })), footer] })] }));
36
+ }
37
+ /**
38
+ * Computes the styles for the chart plot wrapper in the bottom/no-legend layout case.
39
+ * When fitHeight is enabled with a bottom legend, the chart height depends on the footer measurement.
40
+ * Without this, the chart briefly renders at full container height then visibly shrinks once the
41
+ * legend is measured, causing a layout shift. We hide the chart until the footer measurement
42
+ * completes to prevent this flash.
43
+ */
44
+ function getChartPlotWrapperStyles({ measures, fitHeight, hasLegend, chartMinWidth, legendPosition, }) {
45
+ const needsFooterMeasure = fitHeight && hasLegend && legendPosition !== "side" && measures.footer === 0 && measures.chart > 0;
46
+ return {
47
+ ...(needsFooterMeasure && { visibility: "hidden" }),
48
+ ...(chartMinWidth !== undefined && { minInlineSize: chartMinWidth }),
49
+ };
30
50
  }
31
51
  // This hook combines 3 resize observer and does a small optimization to batch their updates in a single set-state.
32
52
  function useContainerQueries() {
33
- const [measuresState, setMeasuresState] = useState({ ready: false, chart: 0, header: 0, footer: 0 });
34
- const measuresRef = useRef({ ready: false, chart: 0, header: 0, footer: 0 });
53
+ const [measuresState, setMeasuresState] = useState({ chart: 0, header: 0, footer: 0 });
54
+ const measuresRef = useRef({ chart: 0, header: 0, footer: 0 });
35
55
  const measureDebounce = useRef(new DebouncedCall()).current;
36
56
  const setMeasure = (type, value) => {
37
57
  measuresRef.current[type] = value;
@@ -1 +1 @@
1
- {"version":3,"file":"chart-container.js","sourceRoot":"","sources":["../../../src/core/chart-container.tsx"],"names":[],"mappings":";AAAA,qEAAqE;AACrE,sCAAsC;AAEtC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;AAElF,OAAO,KAAK,MAAM,MAAM,0BAA0B,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAExD,OAAO,MAAM,MAAM,iBAAiB,CAAC;AACrC,OAAO,WAAW,MAAM,8BAA8B,CAAC;AAEvD,0GAA0G;AAC1G,+DAA+D;AAE/D,MAAM,oBAAoB,GAAG,GAAG,CAAC;AACjC,MAAM,wBAAwB,GAAG,GAAG,CAAC;AAwBrC,MAAM,UAAU,cAAc,CAAC,EAC7B,KAAK,EACL,iBAAiB,EACjB,0BAA0B,EAC1B,MAAM,EACN,MAAM,EACN,MAAM,EACN,aAAa,EACb,eAAe,EACf,cAAc,EACd,qBAAqB,EACrB,SAAS,EACT,MAAM,EACN,SAAS,EACT,WAAW,EACX,cAAc,EACd,aAAa,GACO;IACpB,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,mBAAmB,EAAE,CAAC;IAEjD,wGAAwG;IACxG,8GAA8G;IAC9G,oGAAoG;IACpG,MAAM,mBAAmB,GAAG,MAAM,CAAC,0BAA0B,GAAG,MAAM,CAAC,uBAAuB,CAAC;IAC/F,MAAM,YAAY,GAAG,0BAA0B,KAAK,KAAK,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC;IACpF,MAAM,aAAa,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,aAAd,cAAc,cAAd,cAAc,GAAI,wBAAwB,EAAE,MAAM,CAAC,GAAG,YAAY,CAAC;IACtH,MAAM,mBAAmB,GAAG,aAAa,CAAC,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9F,MAAM,oBAAoB,GAAG,SAAS,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,aAAa,CAAC,WAAW,aAAX,WAAW,cAAX,WAAW,GAAI,oBAAoB,CAAC,CAAC;IAClH,MAAM,SAAS,GAAG,aAAa,IAAI,eAAe,CAAC;IACnD,OAAO,CACL,eACE,GAAG,EAAE,IAAI,CAAC,KAAK,EACf,SAAS,EAAE,IAAI,CAAC;YACd,CAAC,MAAM,CAAC,4BAA4B,CAAC,CAAC,EAAE,SAAS;YACjD,CAAC,MAAM,CAAC,2BAA2B,CAAC,CAAC,EAAE,aAAa,KAAK,SAAS;SACnE,CAAC,aAEF,eAAK,GAAG,EAAE,IAAI,CAAC,MAAM,aAClB,MAAM,EACN,MAAM,IACH,EAEL,SAAS,IAAI,cAAc,KAAK,MAAM,CAAC,CAAC,CAAC,CACxC,eAAK,SAAS,EAAE,MAAM,CAAC,+BAA+B,CAAC,aACrD,eACE,KAAK,EAAE,EAAE,aAAa,EAAE,aAAa,aAAb,aAAa,cAAb,aAAa,GAAI,CAAC,EAAE,EAC5C,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,EAAE,WAAW,CAAC,oBAAoB,CAAC,CAAC,aAE/E,iBAAiB,EACjB,KAAK,CAAC,oBAAoB,CAAC,EAC3B,MAAM,IACH,EACN,eAAK,SAAS,EAAE,MAAM,CAAC,uBAAuB,CAAC,EAAE,KAAK,EAAE,EAAE,YAAY,EAAE,oBAAoB,EAAE,aAC3F,aAAa,EACb,eAAe,IACZ,IACF,CACP,CAAC,CAAC,CAAC,CACF,eACE,KAAK,EAAE,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,EAC1E,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,EAAE,WAAW,CAAC,oBAAoB,CAAC,CAAC,aAE/E,iBAAiB,EACjB,KAAK,CAAC,oBAAoB,CAAC,EAC3B,CAAC,SAAS,IAAI,cAAc,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,IACtD,CACP,EAED,eAAK,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,aAC9F,SAAS,IAAI,cAAK,SAAS,EAAE,WAAW,CAAC,iBAAiB,CAAC,YAAG,SAAS,GAAO,EAC9E,SAAS,IAAI,cAAc,KAAK,QAAQ,IAAI,CAC3C,eACE,SAAS,EAAE,MAAM,CAAC,yBAAyB,CAAC,EAC5C,KAAK,EAAE,EAAE,YAAY,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAAG,qBAAqB,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,aAExF,aAAa,EACb,eAAe,IACZ,CACP,EACA,MAAM,IACH,IACF,CACP,CAAC;AACJ,CAAC;AAED,mHAAmH;AACnH,SAAS,mBAAmB;IAC1B,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IACrG,MAAM,WAAW,GAAG,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IAC7E,MAAM,eAAe,GAAG,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC;IAC5D,MAAM,UAAU,GAAG,CAAC,IAAmC,EAAE,KAAa,EAAE,EAAE;QACxE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;QAClC,eAAe,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,EAAE,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9E,CAAC,CAAC;IAEF,MAAM,eAAe,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAChE,iBAAiB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAEpF,MAAM,gBAAgB,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAClE,iBAAiB,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAEtF,MAAM,gBAAgB,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAClE,iBAAiB,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAEtF,OAAO;QACL,IAAI,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,gBAAgB,EAAE;QACpF,QAAQ,EAAE,aAAa;KACxB,CAAC;AACJ,CAAC","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { useCallback, useRef, useState } from \"react\";\nimport clsx from \"clsx\";\n\nimport { useResizeObserver } from \"@cloudscape-design/component-toolkit/internal\";\n\nimport * as Styles from \"../internal/chart-styles\";\nimport { DebouncedCall } from \"../internal/utils/utils\";\n\nimport styles from \"./styles.css.js\";\nimport testClasses from \"./test-classes/styles.css.js\";\n\n// Chart container implements the layout for top-level components, including chart plot, legend, and more.\n// It also implements the height- and width overflow behaviors.\n\nconst DEFAULT_CHART_HEIGHT = 400;\nconst DEFAULT_CHART_MIN_HEIGHT = 200;\n\ninterface ChartContainerProps {\n // The header, footer, vertical axis title, and legend are rendered as is, and we measure the height of these components\n // to compute the available height for the chart plot when fitHeight=true. When there is not enough vertical space, the\n // container will ensure the overflow behavior.\n chart: (height: undefined | number) => React.ReactNode;\n verticalAxisTitle?: React.ReactNode;\n verticalAxisTitlePlacement: \"top\" | \"side\";\n header?: React.ReactNode;\n filter?: React.ReactNode;\n navigator?: React.ReactNode;\n primaryLegend?: React.ReactNode;\n secondaryLegend?: React.ReactNode;\n legendBottomMaxHeight?: number;\n legendPosition: \"bottom\" | \"side\";\n footer?: React.ReactNode;\n noData?: React.ReactNode;\n fitHeight?: boolean;\n chartHeight?: number;\n chartMinHeight?: number;\n chartMinWidth?: number;\n}\n\nexport function ChartContainer({\n chart,\n verticalAxisTitle,\n verticalAxisTitlePlacement,\n header,\n filter,\n footer,\n primaryLegend,\n secondaryLegend,\n legendPosition,\n legendBottomMaxHeight,\n navigator,\n noData,\n fitHeight,\n chartHeight,\n chartMinHeight,\n chartMinWidth,\n}: ChartContainerProps) {\n const { refs, measures } = useContainerQueries();\n\n // The vertical axis title is rendered above the chart, and is technically not a part of the chart plot.\n // However, we want to include it to the chart's height computations as it does belong to the chart logically.\n // We do so by taking the title's constant height into account, when \"top\" axis placement is chosen.\n const verticalTitleOffset = Styles.verticalAxisTitleBlockSize + Styles.verticalAxisTitleMargin;\n const heightOffset = verticalAxisTitlePlacement === \"top\" ? verticalTitleOffset : 0;\n const withMinHeight = (height: number) => Math.max(chartMinHeight ?? DEFAULT_CHART_MIN_HEIGHT, height) - heightOffset;\n const measuredChartHeight = withMinHeight(measures.chart - measures.header - measures.footer);\n const effectiveChartHeight = fitHeight ? measuredChartHeight : withMinHeight(chartHeight ?? DEFAULT_CHART_HEIGHT);\n const hasLegend = primaryLegend || secondaryLegend;\n return (\n <div\n ref={refs.chart}\n className={clsx({\n [styles[\"chart-container-fit-height\"]]: fitHeight,\n [styles[\"chart-container-min-width\"]]: chartMinWidth !== undefined,\n })}\n >\n <div ref={refs.header}>\n {header}\n {filter}\n </div>\n\n {hasLegend && legendPosition === \"side\" ? (\n <div className={styles[\"chart-plot-and-legend-wrapper\"]}>\n <div\n style={{ minInlineSize: chartMinWidth ?? 0 }}\n className={clsx(styles[\"chart-plot-wrapper\"], testClasses[\"chart-plot-wrapper\"])}\n >\n {verticalAxisTitle}\n {chart(effectiveChartHeight)}\n {noData}\n </div>\n <div className={styles[\"side-legend-container\"]} style={{ maxBlockSize: effectiveChartHeight }}>\n {primaryLegend}\n {secondaryLegend}\n </div>\n </div>\n ) : (\n <div\n style={chartMinWidth !== undefined ? { minInlineSize: chartMinWidth } : {}}\n className={clsx(styles[\"chart-plot-wrapper\"], testClasses[\"chart-plot-wrapper\"])}\n >\n {verticalAxisTitle}\n {chart(effectiveChartHeight)}\n {!hasLegend || legendPosition === \"bottom\" ? noData : null}\n </div>\n )}\n\n <div ref={refs.footer} style={chartMinWidth !== undefined ? { minInlineSize: chartMinWidth } : {}}>\n {navigator && <div className={testClasses[\"chart-navigator\"]}>{navigator}</div>}\n {hasLegend && legendPosition === \"bottom\" && (\n <div\n className={styles[\"bottom-legend-container\"]}\n style={{ maxBlockSize: legendBottomMaxHeight ? `${legendBottomMaxHeight}px` : undefined }}\n >\n {primaryLegend}\n {secondaryLegend}\n </div>\n )}\n {footer}\n </div>\n </div>\n );\n}\n\n// This hook combines 3 resize observer and does a small optimization to batch their updates in a single set-state.\nfunction useContainerQueries() {\n const [measuresState, setMeasuresState] = useState({ ready: false, chart: 0, header: 0, footer: 0 });\n const measuresRef = useRef({ ready: false, chart: 0, header: 0, footer: 0 });\n const measureDebounce = useRef(new DebouncedCall()).current;\n const setMeasure = (type: \"chart\" | \"header\" | \"footer\", value: number) => {\n measuresRef.current[type] = value;\n measureDebounce.call(() => setMeasuresState({ ...measuresRef.current }), 0);\n };\n\n const chartMeasureRef = useRef<HTMLDivElement>(null);\n const getChart = useCallback(() => chartMeasureRef.current, []);\n useResizeObserver(getChart, (entry) => setMeasure(\"chart\", entry.contentBoxHeight));\n\n const headerMeasureRef = useRef<HTMLDivElement>(null);\n const getHeader = useCallback(() => headerMeasureRef.current, []);\n useResizeObserver(getHeader, (entry) => setMeasure(\"header\", entry.contentBoxHeight));\n\n const footerMeasureRef = useRef<HTMLDivElement>(null);\n const getFooter = useCallback(() => footerMeasureRef.current, []);\n useResizeObserver(getFooter, (entry) => setMeasure(\"footer\", entry.contentBoxHeight));\n\n return {\n refs: { chart: chartMeasureRef, header: headerMeasureRef, footer: footerMeasureRef },\n measures: measuresState,\n };\n}\n"]}
1
+ {"version":3,"file":"chart-container.js","sourceRoot":"","sources":["../../../src/core/chart-container.tsx"],"names":[],"mappings":"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","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { useCallback, useRef, useState } from \"react\";\nimport clsx from \"clsx\";\n\nimport { useResizeObserver } from \"@cloudscape-design/component-toolkit/internal\";\n\nimport * as Styles from \"../internal/chart-styles\";\nimport { DebouncedCall } from \"../internal/utils/utils\";\n\nimport styles from \"./styles.css.js\";\nimport testClasses from \"./test-classes/styles.css.js\";\n\n// Chart container implements the layout for top-level components, including chart plot, legend, and more.\n// It also implements the height- and width overflow behaviors.\n\nconst DEFAULT_CHART_HEIGHT = 400;\nconst DEFAULT_CHART_MIN_HEIGHT = 200;\n\ninterface ChartContainerProps {\n // The header, footer, vertical axis title, and legend are rendered as is, and we measure the height of these components\n // to compute the available height for the chart plot when fitHeight=true. When there is not enough vertical space, the\n // container will ensure the overflow behavior.\n chart: (height: undefined | number) => React.ReactNode;\n verticalAxisTitle?: React.ReactNode;\n verticalAxisTitlePlacement: \"top\" | \"side\";\n header?: React.ReactNode;\n filter?: React.ReactNode;\n navigator?: React.ReactNode;\n primaryLegend?: React.ReactNode;\n secondaryLegend?: React.ReactNode;\n legendBottomMaxHeight?: number;\n legendPosition: \"bottom\" | \"side\";\n footer?: React.ReactNode;\n noData?: React.ReactNode;\n fitHeight?: boolean;\n chartHeight?: number;\n chartMinHeight?: number;\n chartMinWidth?: number;\n}\n\nexport function ChartContainer({\n chart,\n verticalAxisTitle,\n verticalAxisTitlePlacement,\n header,\n filter,\n footer,\n primaryLegend,\n secondaryLegend,\n legendPosition,\n legendBottomMaxHeight,\n navigator,\n noData,\n fitHeight,\n chartHeight,\n chartMinHeight,\n chartMinWidth,\n}: ChartContainerProps) {\n const { refs, measures } = useContainerQueries();\n\n // The vertical axis title is rendered above the chart, and is technically not a part of the chart plot.\n // However, we want to include it to the chart's height computations as it does belong to the chart logically.\n // We do so by taking the title's constant height into account, when \"top\" axis placement is chosen.\n const verticalTitleOffset = Styles.verticalAxisTitleBlockSize + Styles.verticalAxisTitleMargin;\n const heightOffset = verticalAxisTitlePlacement === \"top\" ? verticalTitleOffset : 0;\n const withMinHeight = (height: number) => Math.max(chartMinHeight ?? DEFAULT_CHART_MIN_HEIGHT, height) - heightOffset;\n const measuredChartHeight = withMinHeight(measures.chart - measures.header - measures.footer);\n const effectiveChartHeight = fitHeight ? measuredChartHeight : withMinHeight(chartHeight ?? DEFAULT_CHART_HEIGHT);\n const hasLegend = !!(primaryLegend || secondaryLegend);\n return (\n <div\n ref={refs.chart}\n className={clsx({\n [styles[\"chart-container-fit-height\"]]: fitHeight,\n [styles[\"chart-container-min-width\"]]: chartMinWidth !== undefined,\n })}\n >\n <div ref={refs.header}>\n {header}\n {filter}\n </div>\n\n {hasLegend && legendPosition === \"side\" ? (\n <div className={styles[\"chart-plot-and-legend-wrapper\"]}>\n <div\n style={{ minInlineSize: chartMinWidth ?? 0 }}\n className={clsx(styles[\"chart-plot-wrapper\"], testClasses[\"chart-plot-wrapper\"])}\n >\n {verticalAxisTitle}\n {chart(effectiveChartHeight)}\n {noData}\n </div>\n <div className={styles[\"side-legend-container\"]} style={{ maxBlockSize: effectiveChartHeight }}>\n {primaryLegend}\n {secondaryLegend}\n </div>\n </div>\n ) : (\n <div\n className={clsx(styles[\"chart-plot-wrapper\"], testClasses[\"chart-plot-wrapper\"])}\n style={getChartPlotWrapperStyles({\n measures,\n fitHeight,\n hasLegend,\n chartMinWidth,\n legendPosition,\n })}\n >\n {verticalAxisTitle}\n {chart(effectiveChartHeight)}\n {!hasLegend || legendPosition === \"bottom\" ? noData : null}\n </div>\n )}\n\n <div ref={refs.footer} style={chartMinWidth !== undefined ? { minInlineSize: chartMinWidth } : {}}>\n {navigator && <div className={testClasses[\"chart-navigator\"]}>{navigator}</div>}\n {hasLegend && legendPosition === \"bottom\" && (\n <div\n className={styles[\"bottom-legend-container\"]}\n style={{ maxBlockSize: legendBottomMaxHeight ? `${legendBottomMaxHeight}px` : undefined }}\n >\n {primaryLegend}\n {secondaryLegend}\n </div>\n )}\n {footer}\n </div>\n </div>\n );\n}\n\n/**\n * Computes the styles for the chart plot wrapper in the bottom/no-legend layout case.\n * When fitHeight is enabled with a bottom legend, the chart height depends on the footer measurement.\n * Without this, the chart briefly renders at full container height then visibly shrinks once the\n * legend is measured, causing a layout shift. We hide the chart until the footer measurement\n * completes to prevent this flash.\n */\nfunction getChartPlotWrapperStyles({\n measures,\n fitHeight,\n hasLegend,\n chartMinWidth,\n legendPosition,\n}: {\n hasLegend: boolean;\n fitHeight?: boolean;\n chartMinWidth?: number;\n legendPosition: \"bottom\" | \"side\";\n measures: { header: number; footer: number; chart: number };\n}): React.CSSProperties {\n const needsFooterMeasure =\n fitHeight && hasLegend && legendPosition !== \"side\" && measures.footer === 0 && measures.chart > 0;\n return {\n ...(needsFooterMeasure && { visibility: \"hidden\" }),\n ...(chartMinWidth !== undefined && { minInlineSize: chartMinWidth }),\n };\n}\n\n// This hook combines 3 resize observer and does a small optimization to batch their updates in a single set-state.\nfunction useContainerQueries() {\n const [measuresState, setMeasuresState] = useState({ chart: 0, header: 0, footer: 0 });\n const measuresRef = useRef({ chart: 0, header: 0, footer: 0 });\n const measureDebounce = useRef(new DebouncedCall()).current;\n const setMeasure = (type: \"chart\" | \"header\" | \"footer\", value: number) => {\n measuresRef.current[type] = value;\n measureDebounce.call(() => setMeasuresState({ ...measuresRef.current }), 0);\n };\n\n const chartMeasureRef = useRef<HTMLDivElement>(null);\n const getChart = useCallback(() => chartMeasureRef.current, []);\n useResizeObserver(getChart, (entry) => setMeasure(\"chart\", entry.contentBoxHeight));\n\n const headerMeasureRef = useRef<HTMLDivElement>(null);\n const getHeader = useCallback(() => headerMeasureRef.current, []);\n useResizeObserver(getHeader, (entry) => setMeasure(\"header\", entry.contentBoxHeight));\n\n const footerMeasureRef = useRef<HTMLDivElement>(null);\n const getFooter = useCallback(() => footerMeasureRef.current, []);\n useResizeObserver(getFooter, (entry) => setMeasure(\"footer\", entry.contentBoxHeight));\n\n return {\n refs: { chart: chartMeasureRef, header: headerMeasureRef, footer: footerMeasureRef },\n measures: measuresState,\n };\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  export var PACKAGE_SOURCE = "chart-components";
2
- export var PACKAGE_VERSION = "1.0.0 (3b86022a)";
2
+ export var PACKAGE_VERSION = "1.0.0 (40086fb4)";
3
3
  export var THEME = "open-source-visual-refresh";
4
4
  export var ALWAYS_VISUAL_REFRESH = true;
5
5
  export var SYSTEM = "core";
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "PACKAGE_SOURCE": "chart-components",
3
- "PACKAGE_VERSION": "1.0.0 (3b86022a)",
3
+ "PACKAGE_VERSION": "1.0.0 (40086fb4)",
4
4
  "THEME": "open-source-visual-refresh",
5
5
  "ALWAYS_VISUAL_REFRESH": true,
6
6
  "SYSTEM": "core"
@@ -1,3 +1,3 @@
1
1
  {
2
- "commit": "3b86022a24a43c16d2ad2aa1478fb766cd987aa2"
2
+ "commit": "40086fb41692351f0d8dee030a7eacaa0be8ae76"
3
3
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudscape-design/chart-components",
3
- "version": "1.0.92",
3
+ "version": "1.0.93",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/cloudscape-design/chart-components.git"