From cf724c19514dc9f52281bf571aa1f5f01c9e38bd Mon Sep 17 00:00:00 2001 From: Anush Date: Mon, 22 Dec 2025 17:50:41 +0530 Subject: [PATCH 01/10] port changes from v9 to v8 --- .../react-charting/etc/react-charting.api.md | 1 + .../CommonComponents/CartesianChart.base.tsx | 2 + .../CommonComponents/CartesianChart.types.ts | 5 + .../DeclarativeChart/PlotlySchemaAdapter.ts | 48 +++++- .../DeclarativeChartRTL.test.tsx.snap | 140 +++++++++++------- .../PlotlySchemaAdapterUT.test.tsx.snap | 26 ++++ .../src/components/DonutChart/Pie/Pie.tsx | 8 +- .../components/LineChart/LineChart.base.tsx | 6 + .../SankeyChart/SankeyChart.base.tsx | 2 +- .../__snapshots__/SankeyChart.test.tsx.snap | 10 -- .../ScatterChart/ScatterChart.base.tsx | 4 + .../react-charting/src/types/IDataPoint.ts | 1 + .../react-charting/src/utilities/utilities.ts | 47 +++++- 13 files changed, 227 insertions(+), 73 deletions(-) diff --git a/packages/charts/react-charting/etc/react-charting.api.md b/packages/charts/react-charting/etc/react-charting.api.md index ac1517cf42026..535375c572a2e 100644 --- a/packages/charts/react-charting/etc/react-charting.api.md +++ b/packages/charts/react-charting/etc/react-charting.api.md @@ -458,6 +458,7 @@ export interface ICartesianChartProps { xAxistickSize?: number; xAxisTitle?: string; xMaxValue?: number; + xMinValue?: number; xScaleType?: AxisScaleType; yAxis?: AxisProps; yAxisAnnotation?: string; diff --git a/packages/charts/react-charting/src/components/CommonComponents/CartesianChart.base.tsx b/packages/charts/react-charting/src/components/CommonComponents/CartesianChart.base.tsx index bbbcc8c24013b..0a62a2f9d0f62 100644 --- a/packages/charts/react-charting/src/components/CommonComponents/CartesianChart.base.tsx +++ b/packages/charts/react-charting/src/components/CommonComponents/CartesianChart.base.tsx @@ -244,6 +244,8 @@ export class CartesianChartBase containerWidth: this.state.containerWidth, hideTickOverlap: this.props.hideTickOverlap, calcMaxLabelWidth: this._calcMaxLabelWidthWithTransform, + xMinValue: this.props.xMinValue, + xMaxValue: this.props.xMaxValue, ...this.props.xAxis, }; diff --git a/packages/charts/react-charting/src/components/CommonComponents/CartesianChart.types.ts b/packages/charts/react-charting/src/components/CommonComponents/CartesianChart.types.ts index 30ccc50c9a257..cc4982c4243d5 100644 --- a/packages/charts/react-charting/src/components/CommonComponents/CartesianChart.types.ts +++ b/packages/charts/react-charting/src/components/CommonComponents/CartesianChart.types.ts @@ -322,6 +322,11 @@ export interface ICartesianChartProps { */ yMaxValue?: number; + /** + * minimum data value point in x-axis (for numeric x-axis) + */ + xMinValue?: number; + /** * maximum data value point in x-axis */ diff --git a/packages/charts/react-charting/src/components/DeclarativeChart/PlotlySchemaAdapter.ts b/packages/charts/react-charting/src/components/DeclarativeChart/PlotlySchemaAdapter.ts index 29534bad7e9c8..5ff61111ade16 100644 --- a/packages/charts/react-charting/src/components/DeclarativeChart/PlotlySchemaAdapter.ts +++ b/packages/charts/react-charting/src/components/DeclarativeChart/PlotlySchemaAdapter.ts @@ -212,6 +212,18 @@ const getYMinMaxValues = (series: Data, layout: Partial | undefined) => return {}; }; +const getXMinMaxValues = (series: Data, layout: Partial | undefined) => { + const range = getXAxisProperties(series, layout)?.range; + if (range && range.length === 2) { + return { + xMinValue: range[0], + xMaxValue: range[1], + showRoundOffXTickValues: false, + }; + } + return {}; +}; + const getYAxisProperties = (series: Data, layout: Partial | undefined): Partial | undefined => { return layout?.yaxis; }; @@ -1408,6 +1420,14 @@ export const transformPlotlyJsonToVSBCProps = ( .forEach((shape, shapeIdx) => { const lineColor = shape.line?.color; const resolveX = (val: Datum) => { + if (shape.xref === 'x domain') { + if (val === 0) { + return xCategories[0]; + } + if (val === 1) { + return xCategories[xCategories.length - 1]; + } + } if (typeof val === 'number' && Array.isArray(xCategories)) { if (xCategories[val] !== undefined) { return xCategories[val]; @@ -1480,7 +1500,9 @@ export const transformPlotlyJsonToVSBCProps = ( showYAxisLables: true, noOfCharsToTruncate: 20, showYAxisLablesTooltip: true, + roundedTicks: true, wrapXAxisLables: typeof vsbcData[0]?.xAxisPoint === 'string', + ...getXMinMaxValues(input.data[0], input.layout), ...getTitles(input.layout), ...getAxisCategoryOrderProps(input.data, input.layout), ...getYMinMaxValues(input.data[0], input.layout), @@ -1654,8 +1676,10 @@ export const transformPlotlyJsonToGVBCProps = ( hideTickOverlap: true, hideLegend, roundCorners: true, + roundedTicks: true, wrapXAxisLables: true, showYAxisLables: true, + ...getXMinMaxValues(processedInput.data[0], processedInput.layout), ...getTitles(processedInput.layout), ...getAxisCategoryOrderProps(processedInput.data, processedInput.layout), ...getYMinMaxValues(processedInput.data[0], processedInput.layout), @@ -1769,8 +1793,10 @@ export const transformPlotlyJsonToVBCProps = ( maxBarWidth: 50, hideLegend, roundCorners: true, + roundedTicks: true, wrapXAxisLables: typeof vbcData[0]?.x === 'string', showYAxisLables: true, + ...getXMinMaxValues(input.data[0], input.layout), ...getTitles(input.layout), ...getAxisCategoryOrderProps(input.data, input.layout), ...getYMinMaxValues(input.data[0], input.layout), @@ -2057,6 +2083,8 @@ const transformPlotlyJsonToScatterTraceProps = ( optimizeLargeData: numDataPoints > 1000, wrapXAxisLables: shouldWrapLabels, showYAxisLables: true, + roundedTicks: true, + ...getXMinMaxValues(input.data[0], input.layout), ...getTitles(input.layout), ...getXAxisTickFormat(input.data[0], input.layout), ...yAxisTickFormat, @@ -2074,7 +2102,6 @@ const transformPlotlyJsonToScatterTraceProps = ( } else { return { data: isScatterChart ? scatterChartProps : chartProps, - roundedTicks: true, enableReflow: false, ...commonProps, ...yMinMax, @@ -2166,6 +2193,8 @@ export const transformPlotlyJsonToHorizontalBarWithAxisProps = ( noOfCharsToTruncate: 20, showYAxisLablesTooltip: true, roundCorners: true, + roundedTicks: true, + ...getXMinMaxValues(input.data[0], input.layout), ...getTitles(input.layout), ...getAxisCategoryOrderProps(input.data, input.layout), ...getBarProps(input.data, input.layout, true), @@ -2468,6 +2497,14 @@ export const transformPlotlyJsonToSankeyProps = ( colorMap, isDarkTheme, ); + const extractedLinkColors = extractColor( + input.layout?.template?.layout?.colorway, + colorwayType, + link?.color, + colorMap, + isDarkTheme, + ); + const sankeyChartData = { nodes: node.label?.map((label: string, index: number) => { const color = resolveColor( @@ -2487,8 +2524,17 @@ export const transformPlotlyJsonToSankeyProps = ( }), // eslint-disable-next-line @typescript-eslint/no-explicit-any links: validLinks.map((validLink: any, index: number) => { + const color = resolveColor( + extractedLinkColors, + index, + validLink.target, + colorMap, + input.layout?.template?.layout?.colorway, + isDarkTheme, + ); return { ...validLink, + color, }; }), } as ISankeyChartData; diff --git a/packages/charts/react-charting/src/components/DeclarativeChart/__snapshots__/DeclarativeChartRTL.test.tsx.snap b/packages/charts/react-charting/src/components/DeclarativeChart/__snapshots__/DeclarativeChartRTL.test.tsx.snap index fab3435e8a90b..aec6ee5d6578a 100644 --- a/packages/charts/react-charting/src/components/DeclarativeChart/__snapshots__/DeclarativeChartRTL.test.tsx.snap +++ b/packages/charts/react-charting/src/components/DeclarativeChart/__snapshots__/DeclarativeChartRTL.test.tsx.snap @@ -334,7 +334,7 @@ exports[`DeclarativeChart Should render areachart in DeclarativeChart 1`] = ` - 3 + 2 + + + + + + + + + - 9 + 10 @@ -396,7 +432,7 @@ exports[`DeclarativeChart Should render areachart in DeclarativeChart 1`] = ` { public render(): JSXElement { const { pie, data } = this.props; - const focusData = this._pieForFocusRing(data); - const piechart = pie(data); + + // Filter out data points with value 0 to avoid gaps in the donut chart + const filteredData = data.filter((d: IChartDataPoint) => d.data !== 0); + + const focusData = this._pieForFocusRing(filteredData.map(d => d.data!)); + const piechart = pie(filteredData); const translate = `translate(${this.props.width / 2}, ${this.props.height / 2})`; const classNames = getClassNames(getStyles, { theme: this.props.theme!, diff --git a/packages/charts/react-charting/src/components/LineChart/LineChart.base.tsx b/packages/charts/react-charting/src/components/LineChart/LineChart.base.tsx index aac681c72efc6..77fe98cc7b096 100644 --- a/packages/charts/react-charting/src/components/LineChart/LineChart.base.tsx +++ b/packages/charts/react-charting/src/components/LineChart/LineChart.base.tsx @@ -441,6 +441,8 @@ export class LineChartBase extends React.Component = Rea yScalePrimary: _yAxisScale.current, xScaleType: props.xScaleType, yScaleType: props.yScaleType, + xMinValue: props.xMinValue, + xMaxValue: props.xMaxValue, + yMinValue: props.yMinValue, + yMaxValue: props.yMaxValue, }) : 0; diff --git a/packages/charts/react-charting/src/types/IDataPoint.ts b/packages/charts/react-charting/src/types/IDataPoint.ts index 4837282eb056e..de42cdffa28bd 100644 --- a/packages/charts/react-charting/src/types/IDataPoint.ts +++ b/packages/charts/react-charting/src/types/IDataPoint.ts @@ -597,6 +597,7 @@ interface ISLinkExtra { */ value: number; unnormalizedValue?: number; + color?: string; } export type SNode = SankeyNode; diff --git a/packages/charts/react-charting/src/utilities/utilities.ts b/packages/charts/react-charting/src/utilities/utilities.ts index 8b72cac817922..2ffab8ecf03d3 100644 --- a/packages/charts/react-charting/src/utilities/utilities.ts +++ b/packages/charts/react-charting/src/utilities/utilities.ts @@ -179,6 +179,8 @@ export interface IXAxisParams extends AxisProps { containerWidth: number; hideTickOverlap?: boolean; calcMaxLabelWidth: (x: (string | number)[]) => number; + xMaxValue?: number; + xMinValue?: number; } export interface ITickParams { tickValues?: Date[] | number[] | string[]; @@ -262,8 +264,12 @@ export function createNumericXAxis( tick0, tickText, } = xAxisParams; + const dStartValue = domainNRangeValues.dStartValue as number; + const dEndValue = domainNRangeValues.dEndValue as number; + const finalXmin = xAxisParams.xMinValue !== undefined ? Math.min(dStartValue, xAxisParams.xMinValue) : dStartValue; + const finalXmax = xAxisParams.xMaxValue !== undefined ? Math.max(dEndValue, xAxisParams.xMaxValue) : dEndValue; const xAxisScale = createNumericScale(scaleType) - .domain([domainNRangeValues.dStartValue, domainNRangeValues.dEndValue]) + .domain([finalXmin, finalXmax]) .range([domainNRangeValues.rStartValue, domainNRangeValues.rEndValue]); showRoundOffXTickValues && xAxisScale.nice(); @@ -1334,12 +1340,14 @@ export function domainRangeOfNumericForAreaLineScatterCharts( isRTL: boolean, scaleType?: AxisScaleType, hasMarkersMode?: boolean, + xMinVal?: number, + xMaxVal?: number, ): IDomainNRange { const isScatterPolar = isScatterPolarSeries(points); let [xMin, xMax] = getScatterXDomainExtent(points, scaleType) as [number, number]; if (hasMarkersMode) { - const xPadding = getDomainPaddingForMarkers(xMin, xMax, scaleType); + const xPadding = getDomainPaddingForMarkers(xMin, xMax, scaleType, xMinVal, xMaxVal); xMin = xMin - xPadding.start; xMax = xMax + xPadding.end; } @@ -2133,6 +2141,8 @@ export const getDomainPaddingForMarkers = ( minVal: number, maxVal: number, scaleType?: AxisScaleType, + userMinVal?: number, + userMaxVal?: number, ): { start: number; end: number } => { if (scaleType === 'log') { return { @@ -2141,10 +2151,25 @@ export const getDomainPaddingForMarkers = ( }; } - const defaultPadding = (maxVal - minVal) * 0.1; + /* if user explicitly sets userMinVal or userMaxVal, we will check that to avoid excessive padding on either side. + If the difference between minVal and userMinVal is more than 10% of the data range, we set padding to 0 on that side. + this is to avoid cases where userMinVal is significantly smaller than minVal or userMaxVal is significantly larger than + maxVal, which would lead to excessive padding. In other cases, we apply the default 10% padding on both sides. + */ + const rangePadding = (maxVal - minVal) * 0.1; + + // If explicit bounds are set and they're far from the data range, don't add extra padding + const paddingAlreadySatisfiedAtMin = + userMinVal !== undefined && rangePadding > Math.abs(minVal - Math.min(minVal, userMinVal)); + const paddingAlreadySatisfiedAtMax = + userMaxVal !== undefined && rangePadding > Math.abs(maxVal - Math.max(maxVal, userMaxVal)); + + const startPadding = paddingAlreadySatisfiedAtMin ? 0 : rangePadding; + const endPadding = paddingAlreadySatisfiedAtMax ? 0 : rangePadding; + return { - start: defaultPadding, - end: defaultPadding, + start: startPadding, + end: endPadding, }; }; @@ -2191,6 +2216,10 @@ export const getRangeForScatterMarkerSize = ({ xScaleType, yScaleType: primaryYScaleType, secondaryYScaleType, + xMinValue, + xMaxValue, + yMinValue, + yMaxValue, }: { data: ILineChartPoints[] | IScatterChartPoints[]; xScale: IScaleContinuousNumeric | IScaleTime; @@ -2200,6 +2229,10 @@ export const getRangeForScatterMarkerSize = ({ xScaleType?: AxisScaleType; yScaleType?: AxisScaleType; secondaryYScaleType?: AxisScaleType; + xMinValue?: number; + xMaxValue?: number; + yMinValue?: number; + yMaxValue?: number; }): number => { // Note: This function is executed after the scale is created, so the actual padding can be // obtained by calculating the difference between the respective minimums or maximums of the @@ -2211,14 +2244,14 @@ export const getRangeForScatterMarkerSize = ({ // it the other way around (i.e., adjusting the scale domain first with padding and then scaling // the markers to fit inside the plot area). const [xMin, xMax] = getScatterXDomainExtent(data, xScaleType); - const xPadding = getDomainPaddingForMarkers(+xMin, +xMax, xScaleType); + const xPadding = getDomainPaddingForMarkers(+xMin, +xMax, xScaleType, xMinValue, xMaxValue); const scaleXMin = xMin instanceof Date ? new Date(+xMin - xPadding.start) : xMin - xPadding.start; const scaleXMax = xMax instanceof Date ? new Date(+xMax + xPadding.end) : xMax + xPadding.end; const extraXPixels = Math.min(Math.abs(xScale(xMin) - xScale(scaleXMin)), Math.abs(xScale(scaleXMax) - xScale(xMax))); const yScaleType = useSecondaryYScale ? secondaryYScaleType : primaryYScaleType; const { startValue: yMin, endValue: yMax } = findNumericMinMaxOfY(data, undefined, useSecondaryYScale, yScaleType); - const yPadding = getDomainPaddingForMarkers(yMin, yMax, yScaleType); + const yPadding = getDomainPaddingForMarkers(yMin, yMax, yScaleType, yMinValue, yMaxValue); const scaleYMin = yMin - yPadding.start; const scaleYMax = yMax + yPadding.end; const yScale = (useSecondaryYScale ? yScaleSecondary : yScalePrimary)!; From 6d89d744883da6ff17f49e7748eb5d54fd714fe0 Mon Sep 17 00:00:00 2001 From: Anush Date: Mon, 22 Dec 2025 18:01:28 +0530 Subject: [PATCH 02/10] add prompt file --- .github/agents/v9tov8Migration.agent.md | 119 ++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 .github/agents/v9tov8Migration.agent.md diff --git a/.github/agents/v9tov8Migration.agent.md b/.github/agents/v9tov8Migration.agent.md new file mode 100644 index 0000000000000..c175585f4269c --- /dev/null +++ b/.github/agents/v9tov8Migration.agent.md @@ -0,0 +1,119 @@ +--- +description: 'Migrate code from functional component(v9) to class component(v8) in accordance with Fluent UI standards.' +tools: ['vscode', 'execute', 'read', 'edit', 'search', 'web', 'agent', 'todo'] +--- + +**Difference between v8 and v9:** + +- **v8**: + + 1. class component code written inside `packages/charts/react-charting`. + 2. Traditional component lifecycle methods (e.g., componentDidMount, componentDidUpdate). + 3. State is managed using this.state and this.setState. + 4. Props accessed via this.props. + +- **v9**: + 1. functional component code written inside `packages/charts/react-charts`. + 2. Utilizes React hooks (e.g., useState, useEffect) for state and lifecycle management. + 3. State is managed using useState hook. + 4. Direct props destructuring. + +**Difference between v8 styles file and v9 styles file:** + +- **example v8 styles file:** + `import { FontWeights } from '@fluentui/react/lib/Styling'; + import { IHeatMapChartStyleProps, IHeatMapChartStyles } from './HeatMapChart.types'; + export const getHeatMapChartStyles = (props: IHeatMapChartStyleProps): IHeatMapChartStyles => { + const { theme } = props; + return { + root: {}, + text: [ + theme.fonts.medium, + { + pointerEvents: 'none', + fontWeight: FontWeights.semibold, + }, + ], + subComponentStyles: {}, + }; +};` + +- **_Some important points to note:_** + + - Uses mergeStyleSets from @fluentui/react/lib/Styling + - Exports a function that returns styles (e.g., getHeatMapChartStyles) + - Uses theme-based styling with theme.fonts, theme.palette + - Styles are defined as objects or arrays of style rules + - Interfaces have I prefix (e.g., IHeatMapChartStyleProps, IHeatMapChartStyles) + +- **example v9 styles file:** + `'use client'; + import { makeStyles, mergeClasses } from '@griffel/react'; + import type { HeatMapChartProps, HeatMapChartStyles } from './HeatMapChart.types'; + import type { SlotClassNames } from '@fluentui/react-utilities'; + import { typographyStyles } from '@fluentui/react-theme'; + + export const heatmapChartClassNames: SlotClassNames = { + root: 'fui-hmc**root', + text: 'fui-hmc**text', + calloutContentRoot: 'fui-hmc\_\_calloutContentRoot', + xAxis: '', + yAxis: '', + legendContainer: '', + hover: '', + descriptionMessage: '', + tooltip: '', + axisTitle: '', + chartTitle: '', + opacityChangeOnHover: '', + shapeStyles: '', + chartWrapper: '', + svgTooltip: '', + chart: '', + axisAnnotation: '', + plotContainer: '', + annotationLayer: '', + }; + const useStyles = makeStyles({ + root: {}, + text: { + ...typographyStyles.body1Strong, + pointerEvents: 'none', + }, + calloutContentRoot: { + maxWidth: '238px', + }, + }); + + export const useHeatMapChartStyles = (props: HeatMapChartProps): HeatMapChartStyles => { + const baseStyles = useStyles(); + + return { + root: mergeClasses(heatmapChartClassNames.root, baseStyles.root /_, props.styles?.root_/), + text: mergeClasses(heatmapChartClassNames.text, baseStyles.text /_, props.styles?.text_/), + calloutContentRoot: mergeClasses( + heatmapChartClassNames.calloutContentRoot, + baseStyles.calloutContentRoot /_, props.styles?.calloutContentRoot_/, + ), + }; + };` + +- **_Some important points to note:_** + + - Uses makeStyles and mergeClasses from @griffel/react + - Exports a hook function that returns styles (e.g., useHeatMapChartStyles) + - Uses typographyStyles from @fluentui/react-theme for text styles + - Styles are defined as objects within makeStyles + - Interfaces do not have I prefix (e.g., HeatMapChartProps, HeatMapChartStyles) + +- Migrate the provided v9 functional component code to a v8 class component code, ensuring to replace hooks with appropriate lifecycle methods and state management. + +- Follow all the migration steps mentioned below to ensure a successful migration. + +- **Migration steps:** + 1. Take the commit id from the user which needs to be migrated from v9 to v8. + 2. use git commands to fetch the file content from that commit. + 3. Use the above differences and points to convert the functional component code to class component code. + 4. Ensure all changes of that particular commit are addressed in the migration. + 5. **_IMPORTANT:_** After migration, run `yarn build` to build the `react-charting` package and ensure there are no build errors. + 6. **_IMPORTANT:_** Then run `npx cross-env TZ=UTC jest -u` to ensure all tests are passing. From 8ef81c0cef269d144c8d923a62d15e2915aa607d Mon Sep 17 00:00:00 2001 From: Anush Date: Tue, 23 Dec 2025 09:33:19 +0530 Subject: [PATCH 03/10] resolve comments and build erros --- .../charts/.github}/agents/v9tov8Migration.agent.md | 2 +- .../src/components/ScatterChart/ScatterChart.base.tsx | 4 ++++ .../charts/react-charting/src/utilities/utilities.ts | 9 +++++---- 3 files changed, 10 insertions(+), 5 deletions(-) rename {.github => packages/charts/.github}/agents/v9tov8Migration.agent.md (95%) diff --git a/.github/agents/v9tov8Migration.agent.md b/packages/charts/.github/agents/v9tov8Migration.agent.md similarity index 95% rename from .github/agents/v9tov8Migration.agent.md rename to packages/charts/.github/agents/v9tov8Migration.agent.md index c175585f4269c..2d92d53edbfff 100644 --- a/.github/agents/v9tov8Migration.agent.md +++ b/packages/charts/.github/agents/v9tov8Migration.agent.md @@ -116,4 +116,4 @@ tools: ['vscode', 'execute', 'read', 'edit', 'search', 'web', 'agent', 'todo'] 3. Use the above differences and points to convert the functional component code to class component code. 4. Ensure all changes of that particular commit are addressed in the migration. 5. **_IMPORTANT:_** After migration, run `yarn build` to build the `react-charting` package and ensure there are no build errors. - 6. **_IMPORTANT:_** Then run `npx cross-env TZ=UTC jest -u` to ensure all tests are passing. + 6. **_IMPORTANT:_** Then run `npx cross-env TZ=UTC jest` to ensure all tests are passing. If there are snapshots failures, update the snapshots by running `npx cross-env TZ=UTC jest -u`. diff --git a/packages/charts/react-charting/src/components/ScatterChart/ScatterChart.base.tsx b/packages/charts/react-charting/src/components/ScatterChart/ScatterChart.base.tsx index 294ab9df07bc8..67a2c7e3f86bd 100644 --- a/packages/charts/react-charting/src/components/ScatterChart/ScatterChart.base.tsx +++ b/packages/charts/react-charting/src/components/ScatterChart/ScatterChart.base.tsx @@ -679,6 +679,10 @@ export const ScatterChartBase: React.FunctionComponent = Rea classNames, props.xScaleType, props.yScaleType, + props.xMinValue, + props.xMaxValue, + props.yMinValue, + props.yMaxValue, ], ); diff --git a/packages/charts/react-charting/src/utilities/utilities.ts b/packages/charts/react-charting/src/utilities/utilities.ts index 2ffab8ecf03d3..53bd1376f4669 100644 --- a/packages/charts/react-charting/src/utilities/utilities.ts +++ b/packages/charts/react-charting/src/utilities/utilities.ts @@ -2151,10 +2151,11 @@ export const getDomainPaddingForMarkers = ( }; } - /* if user explicitly sets userMinVal or userMaxVal, we will check that to avoid excessive padding on either side. - If the difference between minVal and userMinVal is more than 10% of the data range, we set padding to 0 on that side. - this is to avoid cases where userMinVal is significantly smaller than minVal or userMaxVal is significantly larger than - maxVal, which would lead to excessive padding. In other cases, we apply the default 10% padding on both sides. + /* if user explicitly sets userMinVal or userMaxVal, we will check that to avoid excessive padding on either + side.If the difference between minVal and userMinVal is more than 10% of the data range, we set padding + to 0 on that side. this is to avoid cases where userMinVal is significantly smaller than minVal or + userMaxVal is significantly larger than maxVal, which would lead to excessive padding. In other cases, + we apply the default 10% padding on both sides. */ const rangePadding = (maxVal - minVal) * 0.1; From 67bab6c4d2f37f53784510b82d10663ebdd0fbdd Mon Sep 17 00:00:00 2001 From: Anush Date: Tue, 23 Dec 2025 09:36:03 +0530 Subject: [PATCH 04/10] Add change file --- ...eact-charting-7925662b-9688-4022-9347-a3e7ebb7c42d.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/@fluentui-react-charting-7925662b-9688-4022-9347-a3e7ebb7c42d.json diff --git a/change/@fluentui-react-charting-7925662b-9688-4022-9347-a3e7ebb7c42d.json b/change/@fluentui-react-charting-7925662b-9688-4022-9347-a3e7ebb7c42d.json new file mode 100644 index 0000000000000..f54486e2facf0 --- /dev/null +++ b/change/@fluentui-react-charting-7925662b-9688-4022-9347-a3e7ebb7c42d.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "port changes from v9 to v8 using custom github agent", + "packageName": "@fluentui/react-charting", + "email": "anushgupta@microsoft.com", + "dependentChangeType": "patch" +} From da609b3eb9be8d526200b2ff3e4c331361867e8f Mon Sep 17 00:00:00 2001 From: Anush Date: Tue, 23 Dec 2025 12:15:25 +0530 Subject: [PATCH 05/10] modify prompt file --- packages/charts/.github/agents/v9tov8Migration.agent.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/charts/.github/agents/v9tov8Migration.agent.md b/packages/charts/.github/agents/v9tov8Migration.agent.md index 2d92d53edbfff..e07fb227ba138 100644 --- a/packages/charts/.github/agents/v9tov8Migration.agent.md +++ b/packages/charts/.github/agents/v9tov8Migration.agent.md @@ -114,6 +114,7 @@ tools: ['vscode', 'execute', 'read', 'edit', 'search', 'web', 'agent', 'todo'] 1. Take the commit id from the user which needs to be migrated from v9 to v8. 2. use git commands to fetch the file content from that commit. 3. Use the above differences and points to convert the functional component code to class component code. - 4. Ensure all changes of that particular commit are addressed in the migration. + 4. Ensure all changes of that particular commit are addressed in the migration. **_ONLY MAKE CODE CHANGES FROM THAT COMMIT. DO NOT MAKE ANY OTHER CHANGES._** 5. **_IMPORTANT:_** After migration, run `yarn build` to build the `react-charting` package and ensure there are no build errors. 6. **_IMPORTANT:_** Then run `npx cross-env TZ=UTC jest` to ensure all tests are passing. If there are snapshots failures, update the snapshots by running `npx cross-env TZ=UTC jest -u`. + 7. Finally run `yarn change` to create a change file for the migration. From 6c5775497eca3da14b5ac7da4a3f50b038e4fa07 Mon Sep 17 00:00:00 2001 From: Anush Date: Tue, 23 Dec 2025 15:08:09 +0530 Subject: [PATCH 06/10] modify prompt file --- packages/charts/.github/agents/v9tov8Migration.agent.md | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/charts/.github/agents/v9tov8Migration.agent.md b/packages/charts/.github/agents/v9tov8Migration.agent.md index e07fb227ba138..bb7fb3cfda664 100644 --- a/packages/charts/.github/agents/v9tov8Migration.agent.md +++ b/packages/charts/.github/agents/v9tov8Migration.agent.md @@ -117,4 +117,3 @@ tools: ['vscode', 'execute', 'read', 'edit', 'search', 'web', 'agent', 'todo'] 4. Ensure all changes of that particular commit are addressed in the migration. **_ONLY MAKE CODE CHANGES FROM THAT COMMIT. DO NOT MAKE ANY OTHER CHANGES._** 5. **_IMPORTANT:_** After migration, run `yarn build` to build the `react-charting` package and ensure there are no build errors. 6. **_IMPORTANT:_** Then run `npx cross-env TZ=UTC jest` to ensure all tests are passing. If there are snapshots failures, update the snapshots by running `npx cross-env TZ=UTC jest -u`. - 7. Finally run `yarn change` to create a change file for the migration. From edd5dd1385fb3c449393744a71ca63037d68471b Mon Sep 17 00:00:00 2001 From: Anush Date: Tue, 23 Dec 2025 16:56:33 +0530 Subject: [PATCH 07/10] remove agent code --- .../.github/agents/v9tov8Migration.agent.md | 119 ------------------ 1 file changed, 119 deletions(-) delete mode 100644 packages/charts/.github/agents/v9tov8Migration.agent.md diff --git a/packages/charts/.github/agents/v9tov8Migration.agent.md b/packages/charts/.github/agents/v9tov8Migration.agent.md deleted file mode 100644 index bb7fb3cfda664..0000000000000 --- a/packages/charts/.github/agents/v9tov8Migration.agent.md +++ /dev/null @@ -1,119 +0,0 @@ ---- -description: 'Migrate code from functional component(v9) to class component(v8) in accordance with Fluent UI standards.' -tools: ['vscode', 'execute', 'read', 'edit', 'search', 'web', 'agent', 'todo'] ---- - -**Difference between v8 and v9:** - -- **v8**: - - 1. class component code written inside `packages/charts/react-charting`. - 2. Traditional component lifecycle methods (e.g., componentDidMount, componentDidUpdate). - 3. State is managed using this.state and this.setState. - 4. Props accessed via this.props. - -- **v9**: - 1. functional component code written inside `packages/charts/react-charts`. - 2. Utilizes React hooks (e.g., useState, useEffect) for state and lifecycle management. - 3. State is managed using useState hook. - 4. Direct props destructuring. - -**Difference between v8 styles file and v9 styles file:** - -- **example v8 styles file:** - `import { FontWeights } from '@fluentui/react/lib/Styling'; - import { IHeatMapChartStyleProps, IHeatMapChartStyles } from './HeatMapChart.types'; - export const getHeatMapChartStyles = (props: IHeatMapChartStyleProps): IHeatMapChartStyles => { - const { theme } = props; - return { - root: {}, - text: [ - theme.fonts.medium, - { - pointerEvents: 'none', - fontWeight: FontWeights.semibold, - }, - ], - subComponentStyles: {}, - }; -};` - -- **_Some important points to note:_** - - - Uses mergeStyleSets from @fluentui/react/lib/Styling - - Exports a function that returns styles (e.g., getHeatMapChartStyles) - - Uses theme-based styling with theme.fonts, theme.palette - - Styles are defined as objects or arrays of style rules - - Interfaces have I prefix (e.g., IHeatMapChartStyleProps, IHeatMapChartStyles) - -- **example v9 styles file:** - `'use client'; - import { makeStyles, mergeClasses } from '@griffel/react'; - import type { HeatMapChartProps, HeatMapChartStyles } from './HeatMapChart.types'; - import type { SlotClassNames } from '@fluentui/react-utilities'; - import { typographyStyles } from '@fluentui/react-theme'; - - export const heatmapChartClassNames: SlotClassNames = { - root: 'fui-hmc**root', - text: 'fui-hmc**text', - calloutContentRoot: 'fui-hmc\_\_calloutContentRoot', - xAxis: '', - yAxis: '', - legendContainer: '', - hover: '', - descriptionMessage: '', - tooltip: '', - axisTitle: '', - chartTitle: '', - opacityChangeOnHover: '', - shapeStyles: '', - chartWrapper: '', - svgTooltip: '', - chart: '', - axisAnnotation: '', - plotContainer: '', - annotationLayer: '', - }; - const useStyles = makeStyles({ - root: {}, - text: { - ...typographyStyles.body1Strong, - pointerEvents: 'none', - }, - calloutContentRoot: { - maxWidth: '238px', - }, - }); - - export const useHeatMapChartStyles = (props: HeatMapChartProps): HeatMapChartStyles => { - const baseStyles = useStyles(); - - return { - root: mergeClasses(heatmapChartClassNames.root, baseStyles.root /_, props.styles?.root_/), - text: mergeClasses(heatmapChartClassNames.text, baseStyles.text /_, props.styles?.text_/), - calloutContentRoot: mergeClasses( - heatmapChartClassNames.calloutContentRoot, - baseStyles.calloutContentRoot /_, props.styles?.calloutContentRoot_/, - ), - }; - };` - -- **_Some important points to note:_** - - - Uses makeStyles and mergeClasses from @griffel/react - - Exports a hook function that returns styles (e.g., useHeatMapChartStyles) - - Uses typographyStyles from @fluentui/react-theme for text styles - - Styles are defined as objects within makeStyles - - Interfaces do not have I prefix (e.g., HeatMapChartProps, HeatMapChartStyles) - -- Migrate the provided v9 functional component code to a v8 class component code, ensuring to replace hooks with appropriate lifecycle methods and state management. - -- Follow all the migration steps mentioned below to ensure a successful migration. - -- **Migration steps:** - 1. Take the commit id from the user which needs to be migrated from v9 to v8. - 2. use git commands to fetch the file content from that commit. - 3. Use the above differences and points to convert the functional component code to class component code. - 4. Ensure all changes of that particular commit are addressed in the migration. **_ONLY MAKE CODE CHANGES FROM THAT COMMIT. DO NOT MAKE ANY OTHER CHANGES._** - 5. **_IMPORTANT:_** After migration, run `yarn build` to build the `react-charting` package and ensure there are no build errors. - 6. **_IMPORTANT:_** Then run `npx cross-env TZ=UTC jest` to ensure all tests are passing. If there are snapshots failures, update the snapshots by running `npx cross-env TZ=UTC jest -u`. From 4fa0f64b0340433824cdfafda4e144f7fef4a47a Mon Sep 17 00:00:00 2001 From: Anush Date: Thu, 25 Dec 2025 17:35:17 +0530 Subject: [PATCH 08/10] fix markers issue --- .../src/components/LineChart/LineChart.base.tsx | 4 ---- .../components/ScatterChart/ScatterChart.base.tsx | 4 ---- .../charts/react-charting/src/utilities/utilities.ts | 12 ++---------- .../library/src/components/LineChart/LineChart.tsx | 4 ---- .../src/components/ScatterChart/ScatterChart.tsx | 4 ---- .../react-charts/library/src/utilities/utilities.ts | 12 ++---------- 6 files changed, 4 insertions(+), 36 deletions(-) diff --git a/packages/charts/react-charting/src/components/LineChart/LineChart.base.tsx b/packages/charts/react-charting/src/components/LineChart/LineChart.base.tsx index 77fe98cc7b096..70b8fc9db7d32 100644 --- a/packages/charts/react-charting/src/components/LineChart/LineChart.base.tsx +++ b/packages/charts/react-charting/src/components/LineChart/LineChart.base.tsx @@ -761,10 +761,6 @@ export class LineChartBase extends React.Component = Rea yScalePrimary: _yAxisScale.current, xScaleType: props.xScaleType, yScaleType: props.yScaleType, - xMinValue: props.xMinValue, - xMaxValue: props.xMaxValue, - yMinValue: props.yMinValue, - yMaxValue: props.yMaxValue, }) : 0; diff --git a/packages/charts/react-charting/src/utilities/utilities.ts b/packages/charts/react-charting/src/utilities/utilities.ts index 53bd1376f4669..115f1bb4d5a54 100644 --- a/packages/charts/react-charting/src/utilities/utilities.ts +++ b/packages/charts/react-charting/src/utilities/utilities.ts @@ -2217,10 +2217,6 @@ export const getRangeForScatterMarkerSize = ({ xScaleType, yScaleType: primaryYScaleType, secondaryYScaleType, - xMinValue, - xMaxValue, - yMinValue, - yMaxValue, }: { data: ILineChartPoints[] | IScatterChartPoints[]; xScale: IScaleContinuousNumeric | IScaleTime; @@ -2230,10 +2226,6 @@ export const getRangeForScatterMarkerSize = ({ xScaleType?: AxisScaleType; yScaleType?: AxisScaleType; secondaryYScaleType?: AxisScaleType; - xMinValue?: number; - xMaxValue?: number; - yMinValue?: number; - yMaxValue?: number; }): number => { // Note: This function is executed after the scale is created, so the actual padding can be // obtained by calculating the difference between the respective minimums or maximums of the @@ -2245,14 +2237,14 @@ export const getRangeForScatterMarkerSize = ({ // it the other way around (i.e., adjusting the scale domain first with padding and then scaling // the markers to fit inside the plot area). const [xMin, xMax] = getScatterXDomainExtent(data, xScaleType); - const xPadding = getDomainPaddingForMarkers(+xMin, +xMax, xScaleType, xMinValue, xMaxValue); + const xPadding = getDomainPaddingForMarkers(+xMin, +xMax, xScaleType); const scaleXMin = xMin instanceof Date ? new Date(+xMin - xPadding.start) : xMin - xPadding.start; const scaleXMax = xMax instanceof Date ? new Date(+xMax + xPadding.end) : xMax + xPadding.end; const extraXPixels = Math.min(Math.abs(xScale(xMin) - xScale(scaleXMin)), Math.abs(xScale(scaleXMax) - xScale(xMax))); const yScaleType = useSecondaryYScale ? secondaryYScaleType : primaryYScaleType; const { startValue: yMin, endValue: yMax } = findNumericMinMaxOfY(data, undefined, useSecondaryYScale, yScaleType); - const yPadding = getDomainPaddingForMarkers(yMin, yMax, yScaleType, yMinValue, yMaxValue); + const yPadding = getDomainPaddingForMarkers(yMin, yMax, yScaleType); const scaleYMin = yMin - yPadding.start; const scaleYMax = yMax + yPadding.end; const yScale = (useSecondaryYScale ? yScaleSecondary : yScalePrimary)!; diff --git a/packages/charts/react-charts/library/src/components/LineChart/LineChart.tsx b/packages/charts/react-charts/library/src/components/LineChart/LineChart.tsx index b50811f54c985..fb07ae138084a 100644 --- a/packages/charts/react-charts/library/src/components/LineChart/LineChart.tsx +++ b/packages/charts/react-charts/library/src/components/LineChart/LineChart.tsx @@ -549,10 +549,6 @@ export const LineChart: React.FunctionComponent = React.forwardR xScaleType: props.xScaleType, yScaleType: props.yScaleType, secondaryYScaleType: props.secondaryYScaleType, - xMinValue: props.xMinValue, - xMaxValue: props.xMaxValue, - yMinValue: props.yMinValue, - yMaxValue: props.yMaxValue, }) : 0; if (_points[i].data.length === 1) { diff --git a/packages/charts/react-charts/library/src/components/ScatterChart/ScatterChart.tsx b/packages/charts/react-charts/library/src/components/ScatterChart/ScatterChart.tsx index 1555f8500531a..41f9dc4ac3561 100644 --- a/packages/charts/react-charts/library/src/components/ScatterChart/ScatterChart.tsx +++ b/packages/charts/react-charts/library/src/components/ScatterChart/ScatterChart.tsx @@ -391,10 +391,6 @@ export const ScatterChart: React.FunctionComponent = React.fo yScalePrimary: _yAxisScale, xScaleType: props.xScaleType, yScaleType: props.yScaleType, - xMinValue: props.xMinValue, - xMaxValue: props.xMaxValue, - yMinValue: props.yMinValue, - yMaxValue: props.yMaxValue, }) : 0; diff --git a/packages/charts/react-charts/library/src/utilities/utilities.ts b/packages/charts/react-charts/library/src/utilities/utilities.ts index ab1a0c712ce60..5eef6b620f429 100644 --- a/packages/charts/react-charts/library/src/utilities/utilities.ts +++ b/packages/charts/react-charts/library/src/utilities/utilities.ts @@ -2304,10 +2304,6 @@ export const getRangeForScatterMarkerSize = ({ xScaleType, yScaleType: primaryYScaleType, secondaryYScaleType, - xMinValue, - xMaxValue, - yMinValue, - yMaxValue, }: { data: LineChartPoints[] | ScatterChartPoints[]; xScale: ScaleContinuousNumeric | ScaleTime; @@ -2317,10 +2313,6 @@ export const getRangeForScatterMarkerSize = ({ xScaleType?: AxisScaleType; yScaleType?: AxisScaleType; secondaryYScaleType?: AxisScaleType; - xMinValue?: number; - xMaxValue?: number; - yMinValue?: number; - yMaxValue?: number; }): number => { // Note: This function is executed after the scale is created, so the actual padding can be // obtained by calculating the difference between the respective minimums or maximums of the @@ -2332,14 +2324,14 @@ export const getRangeForScatterMarkerSize = ({ // it the other way around (i.e., adjusting the scale domain first with padding and then scaling // the markers to fit inside the plot area). const [xMin, xMax] = getScatterXDomainExtent(data, xScaleType); - const xPadding = getDomainPaddingForMarkers(+xMin, +xMax, xScaleType, xMinValue, xMaxValue); + const xPadding = getDomainPaddingForMarkers(+xMin, +xMax, xScaleType); const scaleXMin = xMin instanceof Date ? new Date(+xMin - xPadding.start) : xMin - xPadding.start; const scaleXMax = xMax instanceof Date ? new Date(+xMax + xPadding.end) : xMax + xPadding.end; const extraXPixels = Math.min(Math.abs(xScale(xMin) - xScale(scaleXMin)), Math.abs(xScale(scaleXMax) - xScale(xMax))); const yScaleType = useSecondaryYScale ? secondaryYScaleType : primaryYScaleType; const { startValue: yMin, endValue: yMax } = findNumericMinMaxOfY(data, undefined, useSecondaryYScale, yScaleType); - const yPadding = getDomainPaddingForMarkers(yMin, yMax, yScaleType, yMinValue, yMaxValue); + const yPadding = getDomainPaddingForMarkers(yMin, yMax, yScaleType); const scaleYMin = yMin - yPadding.start; const scaleYMax = yMax + yPadding.end; const yScale = (useSecondaryYScale ? yScaleSecondary : yScalePrimary)!; From 6c683b05e390ad2d04f66761a16166ad7264dd0a Mon Sep 17 00:00:00 2001 From: Anush Date: Thu, 25 Dec 2025 17:39:37 +0530 Subject: [PATCH 09/10] Add change file --- ...-react-charts-4fe41249-5868-447b-80ae-10aee8a78584.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/@fluentui-react-charts-4fe41249-5868-447b-80ae-10aee8a78584.json diff --git a/change/@fluentui-react-charts-4fe41249-5868-447b-80ae-10aee8a78584.json b/change/@fluentui-react-charts-4fe41249-5868-447b-80ae-10aee8a78584.json new file mode 100644 index 0000000000000..3b89c70d94ea1 --- /dev/null +++ b/change/@fluentui-react-charts-4fe41249-5868-447b-80ae-10aee8a78584.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "fix scatter marker issue", + "packageName": "@fluentui/react-charts", + "email": "anushgupta@microsoft.com", + "dependentChangeType": "patch" +} From a7cdd218eb94e2878d6de91c89c725b057dc3d90 Mon Sep 17 00:00:00 2001 From: Anush Date: Thu, 25 Dec 2025 17:54:19 +0530 Subject: [PATCH 10/10] solve lint errors --- .../src/components/ScatterChart/ScatterChart.base.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/charts/react-charting/src/components/ScatterChart/ScatterChart.base.tsx b/packages/charts/react-charting/src/components/ScatterChart/ScatterChart.base.tsx index c9c4b926915a7..b5a436ff129b3 100644 --- a/packages/charts/react-charting/src/components/ScatterChart/ScatterChart.base.tsx +++ b/packages/charts/react-charting/src/components/ScatterChart/ScatterChart.base.tsx @@ -675,10 +675,6 @@ export const ScatterChartBase: React.FunctionComponent = Rea classNames, props.xScaleType, props.yScaleType, - props.xMinValue, - props.xMaxValue, - props.yMinValue, - props.yMaxValue, ], );