From f0afca3be87768300ce58c4629fbf135f23699ff Mon Sep 17 00:00:00 2001 From: Fluent UI Build Date: Thu, 24 Aug 2023 07:33:40 +0000 Subject: [PATCH 01/26] applying package updates --- ...emes-cfae358f-02a7-46ba-8e4d-ee45180e9eb8.json | 7 ------- packages/azure-themes/CHANGELOG.json | 15 +++++++++++++++ packages/azure-themes/CHANGELOG.md | 11 ++++++++++- packages/azure-themes/package.json | 2 +- packages/react-examples/package.json | 2 +- packages/storybook/package.json | 2 +- 6 files changed, 28 insertions(+), 11 deletions(-) delete mode 100644 change/@fluentui-azure-themes-cfae358f-02a7-46ba-8e4d-ee45180e9eb8.json diff --git a/change/@fluentui-azure-themes-cfae358f-02a7-46ba-8e4d-ee45180e9eb8.json b/change/@fluentui-azure-themes-cfae358f-02a7-46ba-8e4d-ee45180e9eb8.json deleted file mode 100644 index a5bac08b613cbe..00000000000000 --- a/change/@fluentui-azure-themes-cfae358f-02a7-46ba-8e4d-ee45180e9eb8.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "patch", - "comment": "Updated focus state border for detailslist", - "packageName": "@fluentui/azure-themes", - "email": "30805892+Jacqueline-ms@users.noreply.github.com", - "dependentChangeType": "patch" -} diff --git a/packages/azure-themes/CHANGELOG.json b/packages/azure-themes/CHANGELOG.json index 89561a79ad4cec..0e5b777af56c32 100644 --- a/packages/azure-themes/CHANGELOG.json +++ b/packages/azure-themes/CHANGELOG.json @@ -1,6 +1,21 @@ { "name": "@fluentui/azure-themes", "entries": [ + { + "date": "Thu, 24 Aug 2023 07:33:35 GMT", + "tag": "@fluentui/azure-themes_v8.6.31", + "version": "8.6.31", + "comments": { + "patch": [ + { + "author": "30805892+Jacqueline-ms@users.noreply.github.com", + "package": "@fluentui/azure-themes", + "commit": "7b1585f0bfd58428c5511262b5fb97686b481812", + "comment": "Updated focus state border for detailslist" + } + ] + } + }, { "date": "Wed, 23 Aug 2023 07:36:23 GMT", "tag": "@fluentui/azure-themes_v8.6.30", diff --git a/packages/azure-themes/CHANGELOG.md b/packages/azure-themes/CHANGELOG.md index aec95974e7d32b..9cbefbf372afc1 100644 --- a/packages/azure-themes/CHANGELOG.md +++ b/packages/azure-themes/CHANGELOG.md @@ -1,9 +1,18 @@ # Change Log - @fluentui/azure-themes -This log was last generated on Wed, 23 Aug 2023 07:36:23 GMT and should not be manually modified. +This log was last generated on Thu, 24 Aug 2023 07:33:35 GMT and should not be manually modified. +## [8.6.31](https://github.com/microsoft/fluentui/tree/@fluentui/azure-themes_v8.6.31) + +Thu, 24 Aug 2023 07:33:35 GMT +[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/azure-themes_v8.6.30..@fluentui/azure-themes_v8.6.31) + +### Patches + +- Updated focus state border for detailslist ([PR #28966](https://github.com/microsoft/fluentui/pull/28966) by 30805892+Jacqueline-ms@users.noreply.github.com) + ## [8.6.30](https://github.com/microsoft/fluentui/tree/@fluentui/azure-themes_v8.6.30) Wed, 23 Aug 2023 07:36:23 GMT diff --git a/packages/azure-themes/package.json b/packages/azure-themes/package.json index d3663a6c5e4e90..fdc422f78892de 100644 --- a/packages/azure-themes/package.json +++ b/packages/azure-themes/package.json @@ -1,6 +1,6 @@ { "name": "@fluentui/azure-themes", - "version": "8.6.30", + "version": "8.6.31", "description": "Azure themes for Fluent UI React", "main": "lib-commonjs/index.js", "module": "lib/index.js", diff --git a/packages/react-examples/package.json b/packages/react-examples/package.json index f58a9043264075..2c908974944199 100644 --- a/packages/react-examples/package.json +++ b/packages/react-examples/package.json @@ -27,7 +27,7 @@ "@fluentui/scripts-tasks": "*" }, "dependencies": { - "@fluentui/azure-themes": "^8.6.30", + "@fluentui/azure-themes": "^8.6.31", "@fluentui/date-time-utilities": "^8.5.13", "@fluentui/dom-utilities": "^2.2.11", "@fluentui/example-data": "^8.4.12", diff --git a/packages/storybook/package.json b/packages/storybook/package.json index c93a7e3cdf9046..3eba730fb96b0e 100644 --- a/packages/storybook/package.json +++ b/packages/storybook/package.json @@ -27,7 +27,7 @@ "@storybook/addon-knobs": "6.4.0", "@storybook/addon-essentials": "6.5.15", "@storybook/addons": "6.5.15", - "@fluentui/azure-themes": "^8.6.30", + "@fluentui/azure-themes": "^8.6.31", "@fluentui/theme-samples": "^8.7.108", "tslib": "^2.1.0" }, From 44789c103b2c4a05c026c72f4a594a291fdb0141 Mon Sep 17 00:00:00 2001 From: Marcos Moura Date: Thu, 24 Aug 2023 10:37:29 +0200 Subject: [PATCH 02/26] =?UTF-8?q?docs(react-card):=20improve=20storybook?= =?UTF-8?q?=20and=20examples=20to=20better=20align=20with=E2=80=A6=20(#289?= =?UTF-8?q?69)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...-cdcfa155-17c0-496e-9721-679a95dc295d.json | 7 +++++ .../react-components/react-card/README.md | 2 +- .../src/components/Card/Card.cy.tsx | 4 +-- .../stories/Card/CardAppearance.stories.tsx | 4 +-- .../stories/Card/CardDefault.stories.tsx | 2 +- .../stories/Card/CardFocusMode.stories.tsx | 6 ++--- .../stories/Card/CardOrientation.stories.tsx | 10 ++++---- .../stories/Card/CardSelectable.stories.tsx | 4 +-- .../Card/CardSelectableIndicator.stories.tsx | 10 ++++---- .../stories/Card/CardTemplates.stories.tsx | 14 +++++----- .../CardFooter/CardFooterDefault.stories.tsx | 4 +-- .../CardHeader/CardHeaderDefault.stories.tsx | 12 ++++----- .../CardPreviewDefault.stories.tsx | 2 +- .../react-card/stories/assets/docx.png | Bin 0 -> 654 bytes .../react-card/stories/assets/excel_logo.svg | 24 ------------------ .../stories/assets/powerpoint_logo.svg | 9 ------- .../react-card/stories/assets/pptx.png | Bin 0 -> 643 bytes .../react-card/stories/assets/word_logo.svg | 9 ------- .../react-card/stories/assets/xlsx.png | Bin 0 -> 684 bytes 19 files changed, 44 insertions(+), 79 deletions(-) create mode 100644 change/@fluentui-react-card-cdcfa155-17c0-496e-9721-679a95dc295d.json create mode 100644 packages/react-components/react-card/stories/assets/docx.png delete mode 100644 packages/react-components/react-card/stories/assets/excel_logo.svg delete mode 100644 packages/react-components/react-card/stories/assets/powerpoint_logo.svg create mode 100644 packages/react-components/react-card/stories/assets/pptx.png delete mode 100644 packages/react-components/react-card/stories/assets/word_logo.svg create mode 100644 packages/react-components/react-card/stories/assets/xlsx.png diff --git a/change/@fluentui-react-card-cdcfa155-17c0-496e-9721-679a95dc295d.json b/change/@fluentui-react-card-cdcfa155-17c0-496e-9721-679a95dc295d.json new file mode 100644 index 00000000000000..f497afcee1a4b1 --- /dev/null +++ b/change/@fluentui-react-card-cdcfa155-17c0-496e-9721-679a95dc295d.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "docs: improve storybook and examples to better align with design guidelines", + "packageName": "@fluentui/react-card", + "email": "marcosvmmoura@gmail.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-card/README.md b/packages/react-components/react-card/README.md index cddf8d9466625c..741ee859ce8031 100644 --- a/packages/react-components/react-card/README.md +++ b/packages/react-components/react-card/README.md @@ -41,7 +41,7 @@ const App = () => ( } diff --git a/packages/react-components/react-card/src/components/Card/Card.cy.tsx b/packages/react-components/react-card/src/components/Card/Card.cy.tsx index 99bc6667ad5606..793e0ce533dcc4 100644 --- a/packages/react-components/react-card/src/components/Card/Card.cy.tsx +++ b/packages/react-components/react-card/src/components/Card/Card.cy.tsx @@ -34,7 +34,7 @@ const CardSample = (props: CardProps) => ( } + image={Microsoft PowerPoint logo} header={App Name} description={Developer} /> @@ -71,7 +71,7 @@ const CardWithCustomHeader = ({ } + image={Microsoft PowerPoint logo} header={App Name} description={Developer} /> diff --git a/packages/react-components/react-card/stories/Card/CardAppearance.stories.tsx b/packages/react-components/react-card/stories/Card/CardAppearance.stories.tsx index ae933f61455377..dc059961419bf3 100644 --- a/packages/react-components/react-card/stories/Card/CardAppearance.stories.tsx +++ b/packages/react-components/react-card/stories/Card/CardAppearance.stories.tsx @@ -10,7 +10,7 @@ import { Body1, mergeClasses, } from '@fluentui/react-components'; -import { MoreHorizontal20Filled } from '@fluentui/react-icons'; +import { MoreHorizontal20Regular } from '@fluentui/react-icons'; import { Card, CardHeader, CardProps } from '@fluentui/react-components'; const resolveAsset = (asset: string) => { @@ -88,7 +88,7 @@ const CardExample = ({ className, ...props }: CardProps) => { image={App name logo} header={App Name} description={Developer} - action={ diff --git a/packages/react-components/react-card/stories/CardHeader/CardHeaderDefault.stories.tsx b/packages/react-components/react-card/stories/CardHeader/CardHeaderDefault.stories.tsx index 3fe20144f8e8c2..aa53b29b5e55f8 100644 --- a/packages/react-components/react-card/stories/CardHeader/CardHeaderDefault.stories.tsx +++ b/packages/react-components/react-card/stories/CardHeader/CardHeaderDefault.stories.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { CardHeader } from '@fluentui/react-components'; import { makeStyles, shorthands, Button, Body1, Caption1 } from '@fluentui/react-components'; -import { MoreHorizontal20Filled } from '@fluentui/react-icons'; +import { MoreHorizontal20Regular } from '@fluentui/react-icons'; const useStyles = makeStyles({ container: { @@ -25,7 +25,7 @@ const resolveAsset = (asset: string) => { export const Default = () => { const styles = useStyles(); - const powerpointLogoURL = resolveAsset('powerpoint_logo.svg'); + const powerpointLogoURL = resolveAsset('pptx.png'); return (
@@ -38,7 +38,7 @@ export const Default = () => { } description={Developer} - action={
`; @@ -104,80 +183,159 @@ exports[`PieChart snapShot testing renders with colors, width and height data co width: 670px; } > - - - - - A - - - 50 - - - - + + A-50 + + + - - B - - - 25 - - - - + + B-25 + + + - - C - - - 25 - + + + C-25 + + - - + + `; diff --git a/packages/react-charting/src/components/PieChart/__snapshots__/PieChartRTL.test.tsx.snap b/packages/react-charting/src/components/PieChart/__snapshots__/PieChartRTL.test.tsx.snap index e730fc97eced35..70492e99956e88 100644 --- a/packages/react-charting/src/components/PieChart/__snapshots__/PieChartRTL.test.tsx.snap +++ b/packages/react-charting/src/components/PieChart/__snapshots__/PieChartRTL.test.tsx.snap @@ -4,7 +4,7 @@ exports[`Pie chart rendering Should re-render the Pie chart with data 1`] = `
`; @@ -118,81 +180,160 @@ exports[`PieChart snapShot testing renders PieChart correctly 1`] = ` width: 670px; } > - - - - - A - - - 50 - - - - + + A-50 + + + - - B - - - 25 - - - - + + B-25 + + + - - C - - - 25 - + + + C-25 + + - - + + `; @@ -209,80 +350,159 @@ exports[`PieChart snapShot testing renders with colors, width and height data co width: 670px; } > - - - - - A - - - 50 - - - - + + A-50 + + + - - B - - - 25 - - - - + + B-25 + + + - - C - - - 25 - + + + C-25 + + - - + + `; diff --git a/packages/react-charting/src/utilities/SVGTooltipText.tsx b/packages/react-charting/src/utilities/SVGTooltipText.tsx index 463ead3dfc257b..eb625317a5465b 100644 --- a/packages/react-charting/src/utilities/SVGTooltipText.tsx +++ b/packages/react-charting/src/utilities/SVGTooltipText.tsx @@ -41,6 +41,22 @@ interface ISVGTooltipTextProps { */ maxHeight?: number; + /** + * Pass false to make prevent the tooptip from receiving focus through keyboard + * Eg: In Pie Chart, the focus should only land on the arcs and not on the text to + * avoid repitition of the same datapoint + * @defaultvalue true + */ + shouldReceiveFocus?: boolean; + + /** + * Pass true to show tooltip directly + * Eg: In Pie Chart, the tooltip is shown when the arc is focussed, so the prop is set to true, + * to directly show the tooltip from this component + * @defaultvalue false + */ + isTooltipVisibleProp?: boolean; + /** * Function to wrap text within specified width and height * and return a boolean value indicating whether the text overflowed @@ -88,7 +104,7 @@ export class SVGTooltipText } public render(): React.ReactNode { - const { content, tooltipProps, textProps } = this.props; + const { content, tooltipProps, textProps, shouldReceiveFocus = true } = this.props; const { isTooltipVisible } = this.state; const tooltipRenderProps: ITooltipProps = { content, @@ -103,7 +119,8 @@ export class SVGTooltipText ...tooltipProps, }; - const showTooltip = isTooltipVisible && !!content; + const showTooltip = + (!!this.props.isTooltipVisibleProp && this.state.isOverflowing && !!content) || (isTooltipVisible && !!content); return ( <> @@ -116,7 +133,7 @@ export class SVGTooltipText onMouseEnter={this._onTooltipMouseEnter} onMouseLeave={this._onTooltipMouseLeave} onKeyDown={this._onTooltipKeyDown} - data-is-focusable={this.state.isOverflowing} + data-is-focusable={shouldReceiveFocus && this.state.isOverflowing} > {content} diff --git a/packages/react-examples/src/react-charting/PieChart/PieChart.Basic.Example.tsx b/packages/react-examples/src/react-charting/PieChart/PieChart.Basic.Example.tsx index 9aa1661cbfda8d..0499be1fc2b45e 100644 --- a/packages/react-examples/src/react-charting/PieChart/PieChart.Basic.Example.tsx +++ b/packages/react-examples/src/react-charting/PieChart/PieChart.Basic.Example.tsx @@ -1,26 +1,65 @@ import * as React from 'react'; import { PieChart, IPieChartProps } from '@fluentui/react-charting'; -import { DefaultPalette } from '@fluentui/react/lib/Styling'; +import { Stack, StackItem } from '@fluentui/react'; -export class PieChartBasicExample extends React.Component { +export class PieChartBasicExample extends React.Component { constructor(props: IPieChartProps) { super(props); + this.state = { + height: 350, + width: 600, + }; } public render(): JSX.Element { const points = [ - { y: 50, x: 'A' }, - { y: 25, x: 'B' }, - { y: 25, x: 'C' }, + { y: 50, x: 'ABCD' }, + { y: 25, x: 'EFGH' }, + { y: 25, x: 'IJKL' }, ]; - const colors = [DefaultPalette.red, DefaultPalette.blue, DefaultPalette.green]; return ( - + + + + + + + + + + + + + ); } + + private _onWidthChange = (e: React.ChangeEvent) => { + this.setState({ width: parseInt(e.target.value, 10) }); + }; + private _onHeightChange = (e: React.ChangeEvent) => { + this.setState({ height: parseInt(e.target.value, 10) }); + }; } diff --git a/packages/react-examples/src/react-charting/PieChart/PieChart.Dynamic.Example.tsx b/packages/react-examples/src/react-charting/PieChart/PieChart.Dynamic.Example.tsx index 1514361e474d55..d79b767c6eef86 100644 --- a/packages/react-examples/src/react-charting/PieChart/PieChart.Dynamic.Example.tsx +++ b/packages/react-examples/src/react-charting/PieChart/PieChart.Dynamic.Example.tsx @@ -1,25 +1,21 @@ import * as React from 'react'; -import { IDataPoint, PieChart, IPieChartProps } from '@fluentui/react-charting'; -import { DefaultPalette } from '@fluentui/react/lib/Styling'; +import { IDataPoint, PieChart, IPieChartProps, DataVizPalette } from '@fluentui/react-charting'; import { DefaultButton } from '@fluentui/react/lib/Button'; +import { Stack, StackItem } from '@fluentui/react'; export interface IExampleState { dynamicData: IDataPoint[]; colors: string[]; + width: number; + height: number; } export class PieChartDynamicExample extends React.Component { private _colors = [ - [ - DefaultPalette.blueLight, - DefaultPalette.blue, - DefaultPalette.tealLight, - DefaultPalette.teal, - DefaultPalette.greenLight, - ], - [DefaultPalette.purpleLight, DefaultPalette.purple, DefaultPalette.magentaLight, DefaultPalette.magenta], - [DefaultPalette.yellowLight, DefaultPalette.yellow, DefaultPalette.orangeLighter, DefaultPalette.orangeLight], - [DefaultPalette.neutralLight, DefaultPalette.neutralQuaternary, DefaultPalette.neutralTertiary], + [DataVizPalette.color1, DataVizPalette.color2, DataVizPalette.color3, DataVizPalette.color4, DataVizPalette.color5], + [DataVizPalette.color6, DataVizPalette.color7, DataVizPalette.color8, DataVizPalette.color9], + [DataVizPalette.color10, DataVizPalette.color11, DataVizPalette.color12, DataVizPalette.color13], + [DataVizPalette.color30], ]; constructor(props: IPieChartProps) { @@ -31,12 +27,9 @@ export class PieChartDynamicExample extends React.Component - + + + + + + + + + + + @@ -82,4 +107,11 @@ export class PieChartDynamicExample extends React.Component) => { + this.setState({ width: parseInt(e.target.value, 10) }); + }; + private _onHeightChange = (e: React.ChangeEvent) => { + this.setState({ height: parseInt(e.target.value, 10) }); + }; } From 78808a4e906580cd2b7a946b8be359eb548206bc Mon Sep 17 00:00:00 2001 From: Yush singla <70366079+yush-singla@users.noreply.github.com> Date: Thu, 24 Aug 2023 16:20:44 +0530 Subject: [PATCH 06/26] Focus indicator bug in bar charts (#28414) * focus indicator bug fix in bar chart * added bars spacing adjustment factor * resolving eslint issues * updated snapshots, for horizontal bar chart and multistacked bar chart * pixel design issue fixed * snapshot updated * added change, and fixed stroke thickness in horizontal bar chart * focus bug fixed * added support for dark mode, fixed few PR comments * updated snapshots * removed dark mode * fixed linting error * bar chart fixes * fixed the focus indicator width in horizontal bar chart * updated snapshots * resolved snapshots * fixed the focus indicator bug with different mathematical approach * removed emptychart flag * stacked bar chart focus indicator bug resolved * stacked bar chart bug fix * fixed the outline bug in dark mode * multistaked bar chart variable initialisation --------- Co-authored-by: Yush Singla Co-authored-by: yush singla --- ...-20c8ae70-f2a4-4ef4-89b6-7ca932f7481d.json | 7 ++ .../HorizontalBarChart.base.tsx | 42 +++++++- .../HorizontalBarChart.styles.ts | 5 +- .../HorizontalBarChart.test.tsx.snap | 60 +++--------- .../MultiStackedBarChart.base.tsx | 52 ++++++++-- .../MultiStackedBarChart.styles.ts | 4 - .../StackedBarChart/StackedBarChart.base.tsx | 46 ++++++++- .../StackedBarChart/StackedBarChart.styles.ts | 3 +- .../MultiStackedBarChart.test.tsx.snap | 74 +------------- .../MultiStackedBarChartRTL.test.tsx.snap | 96 ------------------- .../StackedBarChart.test.tsx.snap | 45 ++------- .../StackedBarChartRTL.test.tsx.snap | 39 +------- .../MultiStackedBarChart.Example.tsx | 60 ++++++++++-- .../MultiStackedBarChartPage.tsx | 4 +- 14 files changed, 220 insertions(+), 317 deletions(-) create mode 100644 change/@fluentui-react-charting-20c8ae70-f2a4-4ef4-89b6-7ca932f7481d.json diff --git a/change/@fluentui-react-charting-20c8ae70-f2a4-4ef4-89b6-7ca932f7481d.json b/change/@fluentui-react-charting-20c8ae70-f2a4-4ef4-89b6-7ca932f7481d.json new file mode 100644 index 00000000000000..609bfb15d61b81 --- /dev/null +++ b/change/@fluentui-react-charting-20c8ae70-f2a4-4ef4-89b6-7ca932f7481d.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Fixed the focus indicator bug in horizontal bar chart and multi stack bar chart", + "packageName": "@fluentui/react-charting", + "email": "yushsingla@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-charting/src/components/HorizontalBarChart/HorizontalBarChart.base.tsx b/packages/react-charting/src/components/HorizontalBarChart/HorizontalBarChart.base.tsx index c9208fb9235334..72f3f627659feb 100644 --- a/packages/react-charting/src/components/HorizontalBarChart/HorizontalBarChart.base.tsx +++ b/packages/react-charting/src/components/HorizontalBarChart/HorizontalBarChart.base.tsx @@ -30,6 +30,7 @@ export interface IHorizontalBarChartState { yCalloutValue?: string; barCalloutProps?: IChartDataPoint; callOutAccessibilityData?: IAccessibilityProps; + barSpacingInPercent: number; } export class HorizontalBarChartBase extends React.Component { @@ -40,6 +41,7 @@ export class HorizontalBarChartBase extends React.Component; private _emptyChartId: string; constructor(props: IHorizontalBarChartProps) { @@ -54,12 +56,23 @@ export class HorizontalBarChartBase extends React.Component(); + } + + public componentDidMount(): void { + const svgWidth = this.barChartSvgRef.current?.getBoundingClientRect().width || 0; + const MARGIN_WIDTH_IN_PX = 3; + if (svgWidth) { + const currentBarSpacing = (MARGIN_WIDTH_IN_PX / svgWidth) * 100; + this.setState({ barSpacingInPercent: currentBarSpacing }); + } } public render(): JSX.Element { @@ -113,7 +126,7 @@ export class HorizontalBarChartBase extends React.Component {points!.chartData![0].data && this._createBenchmark(points!)} - + elements, which form the bars + * For each bar an x value, and a width needs to be specified + * The computations are done based on percentages + * Extra margin is also provided, in the x value to provide some spacing in between the bars + */ + private _createBars(data: IChartProps, palette: IPalette): JSX.Element[] { + const noOfBars = + data.chartData?.reduce((count: number, point: IChartDataPoint) => (count += (point.data || 0) > 0 ? 1 : 0), 0) || + 1; + const totalMarginPercent = this.state.barSpacingInPercent * (noOfBars - 1); const defaultPalette: string[] = [palette.blueLight, palette.blue, palette.blueMid, palette.red, palette.black]; // calculating starting point of each bar and it's range const startingPoint: number[] = []; @@ -312,7 +336,15 @@ export class HorizontalBarChartBase extends React.Component This needs to be scaled down to 95%, not 100% + * since that's only space available to the bars + */ + const scalingRatio = sumOfPercent !== 0 ? (sumOfPercent - totalMarginPercent) / 100 : 1; const bars = data.chartData!.map((point: IChartDataPoint, index: number) => { const color: string = point.color ? point.color : defaultPalette[Math.floor(Math.random() * 4 + 1)]; @@ -359,7 +391,11 @@ export class HorizontalBarChartBase extends React.Component { @@ -52,6 +53,7 @@ export class MultiStackedBarChartBase extends React.Component; private _emptyChartId: string; private _barId: string; private _barIdPlaceholderPartToWhole: string; @@ -70,16 +72,27 @@ export class MultiStackedBarChartBase extends React.Component(); this._emptyChartId = getId('_MSBC_empty'); this._barId = getId('_MSBC_rect_'); this._barIdPlaceholderPartToWhole = getId('_MSBC_rect_partToWhole_'); this._barIdEmpty = getId('_MSBC_rect_empty'); } + public componentDidMount(): void { + const svgWidth = this.barChartSvgRef.current?.getBoundingClientRect().width || 0; + const MARGIN_WIDTH_IN_PX = 3; + if (svgWidth) { + const currentBarSpacing = (MARGIN_WIDTH_IN_PX / svgWidth) * 100; + this.setState({ barSpacingInPercent: currentBarSpacing }); + } + } + public render(): JSX.Element { if (!this._isChartEmpty()) { const { data, theme, culture } = this.props; @@ -155,6 +168,13 @@ export class MultiStackedBarChartBase extends React.Component elements, which form the bars + * For each bar an x value, and a width needs to be specified + * The computations are done based on percentages + * Extra margin is also provided, in the x value to provide some spacing + */ + private _createBarsAndLegends( data: IChartProps, barHeight: number, @@ -163,6 +183,10 @@ export class MultiStackedBarChartBase extends React.Component (count += (point.data || 0) > 0 ? 1 : 0), 0) || + 1; + const totalMarginPercent = this.state.barSpacingInPercent * (noOfBars - 1); const { culture } = this.props; const defaultPalette: string[] = [palette.blueLight, palette.blue, palette.blueMid, palette.red, palette.black]; // calculating starting point of each bar and it's range @@ -177,7 +201,9 @@ export class MultiStackedBarChartBase extends React.Component { const pointData = point.data ? point.data : 0; - let value = (pointData / total) * 100 ? (pointData / total) * 100 : 0; + const currValue = (pointData / total) * 100; + let value = currValue ? currValue : 0; + if (value < 1 && value !== 0) { value = 1; } else if (value > 99 && value !== 100) { @@ -201,7 +227,16 @@ export class MultiStackedBarChartBase extends React.Component This needs to be scaled down to 95%, not 100% + * since that's only space available to the bars + */ + + const scalingRatio = sumOfPercent !== 0 ? sumOfPercent / (100 - totalMarginPercent) : 1; let prevPosition = 0; let value = 0; @@ -257,7 +292,11 @@ export class MultiStackedBarChartBase extends React.Component
- + {bars}
diff --git a/packages/react-charting/src/components/StackedBarChart/MultiStackedBarChart.styles.ts b/packages/react-charting/src/components/StackedBarChart/MultiStackedBarChart.styles.ts index 39c68270760b95..e571b68a29e660 100644 --- a/packages/react-charting/src/components/StackedBarChart/MultiStackedBarChart.styles.ts +++ b/packages/react-charting/src/components/StackedBarChart/MultiStackedBarChart.styles.ts @@ -49,8 +49,6 @@ export const getMultiStackedBarChartStyles = (props: IMultiStackedBarChartStyleP opacityChangeOnHover: { opacity: shouldHighlight ? '' : '0.1', cursor: href ? 'pointer' : 'default', - stroke: theme.palette.white, - strokeWidth: 2, selectors: { '&:focus': { stroke: theme.palette.black, @@ -70,8 +68,6 @@ export const getMultiStackedBarChartStyles = (props: IMultiStackedBarChartStyleP placeHolderOnHover: { opacity: shouldHighlight ? '' : '0.1', cursor: 'default', - stroke: theme.palette.white, - strokeWidth: '2', selectors: { '&:focus': { stroke: theme.palette.black, diff --git a/packages/react-charting/src/components/StackedBarChart/StackedBarChart.base.tsx b/packages/react-charting/src/components/StackedBarChart/StackedBarChart.base.tsx index 7ddd4ccd358fe7..fe71c5212a60c6 100644 --- a/packages/react-charting/src/components/StackedBarChart/StackedBarChart.base.tsx +++ b/packages/react-charting/src/components/StackedBarChart/StackedBarChart.base.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { IProcessedStyleSet, IPalette } from '@fluentui/react/lib/Styling'; -import { classNamesFunction, getId } from '@fluentui/react/lib/Utilities'; +import { classNamesFunction, getId, getRTL } from '@fluentui/react/lib/Utilities'; import { ILegend, Legends } from '../Legends/index'; import { IAccessibilityProps, IChartDataPoint, IChartProps } from './index'; import { IRefArrayData, IStackedBarChartProps, IStackedBarChartStyleProps, IStackedBarChartStyles } from '../../index'; @@ -23,6 +23,7 @@ export interface IStackedBarChartState { dataPointCalloutProps?: IChartDataPoint; callOutAccessibilityData?: IAccessibilityProps; calloutLegend: string; + barSpacingInPercent: number; } export class StackedBarChartBase extends React.Component { @@ -37,6 +38,8 @@ export class StackedBarChartBase extends React.Component; + private _isRTL = getRTL(); public constructor(props: IStackedBarChartProps) { super(props); @@ -50,6 +53,7 @@ export class StackedBarChartBase extends React.Component(); + } + + public componentDidMount(): void { + const svgWidth = this.barChartSvgRef.current?.getBoundingClientRect().width || 0; + const MARGIN_WIDTH_IN_PX = 3; + if (svgWidth) { + const currentBarSpacing = (MARGIN_WIDTH_IN_PX / svgWidth) * 100; + this.setState({ barSpacingInPercent: currentBarSpacing }); + } } public render(): JSX.Element { @@ -145,7 +159,7 @@ export class StackedBarChartBase extends React.Component
- + {bars[0]} elements, which form the bars + * For each bar an x value, and a width needs to be specified + * The computations are done based on percentages + * Extra margin is also provided, in the x value to provide some spacing + */ + private _createBarsAndLegends( data: IChartProps, barHeight: number, @@ -209,6 +230,11 @@ export class StackedBarChartBase extends React.Component (count += (point.data || 0) > 0 ? 1 : 0), 0) || + 1; + const totalMarginPercent = this.state.barSpacingInPercent * (noOfBars - 1); + const defaultPalette: string[] = [palette.blueLight, palette.blue, palette.blueMid, palette.red, palette.black]; const legendDataItems: ILegend[] = []; // calculating starting point of each bar and it's range @@ -234,7 +260,15 @@ export class StackedBarChartBase extends React.Component This needs to be scaled down to 95%, not 100% + * since that's only space available to the bars + */ + const scalingRatio = sumOfPercent !== 0 ? sumOfPercent / (100 - totalMarginPercent) : 1; const bars = data.chartData!.map((point: IChartDataPoint, index: number) => { const color: string = point.color ? point.color : defaultPalette[Math.floor(Math.random() * 4 + 1)]; @@ -307,7 +341,11 @@ export class StackedBarChartBase extends React.Component @@ -142,8 +143,6 @@ exports[`StackedBarChart - mouse events Should render callout correctly on mouse { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -176,8 +175,6 @@ exports[`StackedBarChart - mouse events Should render callout correctly on mouse { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -503,6 +500,7 @@ exports[`StackedBarChart - mouse events Should render customized callout on mous display: block; height: 12px; margin-bottom: 10px; + overflow: visible; width: 100%; } > @@ -514,8 +512,6 @@ exports[`StackedBarChart - mouse events Should render customized callout on mous { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -548,8 +544,6 @@ exports[`StackedBarChart - mouse events Should render customized callout on mous { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -792,6 +786,7 @@ exports[`StackedBarChart snapShot testing renders StackedBarChart correctly 1`] display: block; height: 12px; margin-bottom: 10px; + overflow: visible; width: 100%; } > @@ -803,8 +798,6 @@ exports[`StackedBarChart snapShot testing renders StackedBarChart correctly 1`] { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -835,8 +828,6 @@ exports[`StackedBarChart snapShot testing renders StackedBarChart correctly 1`] { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -1001,6 +992,7 @@ exports[`StackedBarChart snapShot testing renders enabledLegendsWrapLines correc display: block; height: 12px; margin-bottom: 10px; + overflow: visible; width: 100%; } > @@ -1012,8 +1004,6 @@ exports[`StackedBarChart snapShot testing renders enabledLegendsWrapLines correc { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -1044,8 +1034,6 @@ exports[`StackedBarChart snapShot testing renders enabledLegendsWrapLines correc { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -1200,6 +1188,7 @@ exports[`StackedBarChart snapShot testing renders hideDenominator correctly 1`] display: block; height: 12px; margin-bottom: 10px; + overflow: visible; width: 100%; } > @@ -1211,8 +1200,6 @@ exports[`StackedBarChart snapShot testing renders hideDenominator correctly 1`] { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -1243,8 +1230,6 @@ exports[`StackedBarChart snapShot testing renders hideDenominator correctly 1`] { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -1409,6 +1394,7 @@ exports[`StackedBarChart snapShot testing renders hideLegend correctly 1`] = ` display: block; height: 12px; margin-bottom: 10px; + overflow: visible; width: 100%; } > @@ -1420,8 +1406,6 @@ exports[`StackedBarChart snapShot testing renders hideLegend correctly 1`] = ` { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -1452,8 +1436,6 @@ exports[`StackedBarChart snapShot testing renders hideLegend correctly 1`] = ` { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -1592,6 +1574,7 @@ exports[`StackedBarChart snapShot testing renders hideNumberDisplay correctly 1` display: block; height: 12px; margin-bottom: 10px; + overflow: visible; width: 100%; } > @@ -1603,8 +1586,6 @@ exports[`StackedBarChart snapShot testing renders hideNumberDisplay correctly 1` { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -1635,8 +1616,6 @@ exports[`StackedBarChart snapShot testing renders hideNumberDisplay correctly 1` { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -1801,6 +1780,7 @@ exports[`StackedBarChart snapShot testing renders hideTooltip correctly 1`] = ` display: block; height: 12px; margin-bottom: 10px; + overflow: visible; width: 100%; } > @@ -1812,8 +1792,6 @@ exports[`StackedBarChart snapShot testing renders hideTooltip correctly 1`] = ` { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -1844,8 +1822,6 @@ exports[`StackedBarChart snapShot testing renders hideTooltip correctly 1`] = ` { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -1984,6 +1960,7 @@ exports[`StackedBarChart snapShot testing renders ignoreFixStyle correctly 1`] = display: block; height: 12px; margin-bottom: 10px; + overflow: visible; width: 100%; } > @@ -1995,8 +1972,6 @@ exports[`StackedBarChart snapShot testing renders ignoreFixStyle correctly 1`] = { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -2027,8 +2002,6 @@ exports[`StackedBarChart snapShot testing renders ignoreFixStyle correctly 1`] = { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; diff --git a/packages/react-charting/src/components/StackedBarChart/__snapshots__/StackedBarChartRTL.test.tsx.snap b/packages/react-charting/src/components/StackedBarChart/__snapshots__/StackedBarChartRTL.test.tsx.snap index 9c19f42a1b8718..204fd4efc7b33a 100644 --- a/packages/react-charting/src/components/StackedBarChart/__snapshots__/StackedBarChartRTL.test.tsx.snap +++ b/packages/react-charting/src/components/StackedBarChart/__snapshots__/StackedBarChartRTL.test.tsx.snap @@ -84,6 +84,7 @@ exports[`Screen resolution Should remain unchanged on zoom in 1`] = ` display: block; height: 12px; margin-bottom: 10px; + overflow: visible; width: 100%; } focusable="false" @@ -96,8 +97,6 @@ exports[`Screen resolution Should remain unchanged on zoom in 1`] = ` { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -124,8 +123,6 @@ exports[`Screen resolution Should remain unchanged on zoom in 1`] = ` { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -152,8 +149,6 @@ exports[`Screen resolution Should remain unchanged on zoom in 1`] = ` { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -180,8 +175,6 @@ exports[`Screen resolution Should remain unchanged on zoom in 1`] = ` { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -700,6 +693,7 @@ exports[`Screen resolution Should remain unchanged on zoom out 1`] = ` display: block; height: 12px; margin-bottom: 10px; + overflow: visible; width: 100%; } focusable="false" @@ -712,8 +706,6 @@ exports[`Screen resolution Should remain unchanged on zoom out 1`] = ` { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -740,8 +732,6 @@ exports[`Screen resolution Should remain unchanged on zoom out 1`] = ` { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -768,8 +758,6 @@ exports[`Screen resolution Should remain unchanged on zoom out 1`] = ` { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -796,8 +784,6 @@ exports[`Screen resolution Should remain unchanged on zoom out 1`] = ` { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -1329,6 +1315,7 @@ exports[`Should reflect theme change 1`] = ` display: block; height: 12px; margin-bottom: 10px; + overflow: visible; width: 100%; } focusable="false" @@ -1341,8 +1328,6 @@ exports[`Should reflect theme change 1`] = ` { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #1b1a19; } &:focus { stroke-width: 2px; @@ -1369,8 +1354,6 @@ exports[`Should reflect theme change 1`] = ` { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #1b1a19; } &:focus { stroke-width: 2px; @@ -1397,8 +1380,6 @@ exports[`Should reflect theme change 1`] = ` { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #1b1a19; } &:focus { stroke-width: 2px; @@ -1425,8 +1406,6 @@ exports[`Should reflect theme change 1`] = ` { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #1b1a19; } &:focus { stroke-width: 2px; @@ -1946,6 +1925,7 @@ exports[`Stacked bar chart rendering Should render the stacked bar chart with em display: block; height: 12px; margin-bottom: 10px; + overflow: visible; width: 100%; } focusable="false" @@ -1957,8 +1937,6 @@ exports[`Stacked bar chart rendering Should render the stacked bar chart with em { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -2473,6 +2451,7 @@ exports[`Stacked bar chart rendering Should render the stacked bar chart with no display: block; height: 12px; margin-bottom: 10px; + overflow: visible; width: 100%; } focusable="false" @@ -2485,8 +2464,6 @@ exports[`Stacked bar chart rendering Should render the stacked bar chart with no { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -2513,8 +2490,6 @@ exports[`Stacked bar chart rendering Should render the stacked bar chart with no { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -2541,8 +2516,6 @@ exports[`Stacked bar chart rendering Should render the stacked bar chart with no { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; @@ -2569,8 +2542,6 @@ exports[`Stacked bar chart rendering Should render the stacked bar chart with no { cursor: default; opacity: ; - stroke-width: 2px; - stroke: #ffffff; } &:focus { stroke-width: 2px; diff --git a/packages/react-examples/src/react-charting/MultiStackedBarChart/MultiStackedBarChart.Example.tsx b/packages/react-examples/src/react-charting/MultiStackedBarChart/MultiStackedBarChart.Example.tsx index e9c9973474660a..d168bde86803db 100644 --- a/packages/react-examples/src/react-charting/MultiStackedBarChart/MultiStackedBarChart.Example.tsx +++ b/packages/react-examples/src/react-charting/MultiStackedBarChart/MultiStackedBarChart.Example.tsx @@ -1,37 +1,85 @@ import * as React from 'react'; import { IChartDataPoint, MultiStackedBarChart, IChartProps } from '@fluentui/react-charting'; -export const MultiStackedBarChartExample: React.FunctionComponent = () => { +export const MultiStackedBarChartBasicExample: React.FunctionComponent = () => { const firstChartPoints: IChartDataPoint[] = [ { legend: 'Debit card numbers (EU and USA)', data: 40, color: '#0099BC', - callOutAccessibilityData: { ariaLabel: 'Bar series 1 of 5 Debit card numbers (EU and USA) 40' }, + callOutAccessibilityData: { ariaLabel: 'Bar series 1 of 13 Debit card numbers (EU and USA) 40' }, }, { legend: 'Passport numbers (USA)', data: 23, color: '#77004D', - callOutAccessibilityData: { ariaLabel: 'Bar series 2 of 5 Passport numbers (USA) 23' }, + callOutAccessibilityData: { ariaLabel: 'Bar series 2 of 13 Passport numbers (USA) 23' }, }, { legend: 'Social security numbers', data: 35, color: '#4F68ED', - callOutAccessibilityData: { ariaLabel: 'Bar series 3 of 5 Social security numbers 35' }, + callOutAccessibilityData: { ariaLabel: 'Bar series 3 of 13 Social security numbers 35' }, }, { legend: 'Credit card numbers', data: 87, color: '#AE8C00', - callOutAccessibilityData: { ariaLabel: 'Bar series 4 of 5 Credit card numbers 87' }, + callOutAccessibilityData: { ariaLabel: 'Bar series 4 of 13 Credit card numbers 87' }, }, { legend: 'Tax identification numbers (USA)', data: 87, color: '#004E8C', - callOutAccessibilityData: { ariaLabel: 'Bar series 5 of 5 Tax identification numbers (USA) 87' }, + callOutAccessibilityData: { ariaLabel: 'Bar series 5 of 13 Tax identification numbers (USA) 87' }, + }, + { + legend: "Driver's license numbers (USA)", + data: 0.5, + color: '#00A6A6', + callOutAccessibilityData: { ariaLabel: "Bar series 6 of 13 Driver's license numbers (USA) 0.5" }, + }, + { + legend: 'Email addresses', + data: 0.5, + color: '#FF5733', + callOutAccessibilityData: { ariaLabel: 'Bar series 7 of 13 Email addresses 0.5' }, + }, + { + legend: 'Phone numbers', + data: 0.5, + color: '#7E2F8E', + callOutAccessibilityData: { ariaLabel: 'Bar series 8 of 13 Phone numbers 0.5' }, + }, + { + legend: 'Health insurance numbers', + data: 0.5, + color: '#00B300', + callOutAccessibilityData: { ariaLabel: 'Bar series 9 of 13 Health insurance numbers 0.5' }, + }, + { + legend: 'Bank account numbers', + data: 0.5, + color: '#8C4D00', + callOutAccessibilityData: { ariaLabel: 'Bar series 10 of 13 Bank account numbers 0.5' }, + }, + { + legend: 'Employee identification numbers', + data: 0.5, + color: '#B34D9A', + callOutAccessibilityData: { ariaLabel: 'Bar series 11 of 13 Employee identification numbers 0.5' }, + }, + { + legend: 'Vehicle registration numbers', + data: 0.5, + color: '#FF9A00', + callOutAccessibilityData: { ariaLabel: 'Bar series 12 of 13 Vehicle registration numbers 0.5' }, + }, + { + legend: 'Student identification numbers', + data: 0.5, + color: '#007E00', + callOutAccessibilityData: { ariaLabel: 'Bar series 13 of 13 Student identification numbers 0.5' }, }, ]; const firstChartPoints1: IChartDataPoint[] = [ diff --git a/packages/react-examples/src/react-charting/MultiStackedBarChart/MultiStackedBarChartPage.tsx b/packages/react-examples/src/react-charting/MultiStackedBarChart/MultiStackedBarChartPage.tsx index 91bb42c6b7b5bd..c83c24cad82e0d 100644 --- a/packages/react-examples/src/react-charting/MultiStackedBarChart/MultiStackedBarChartPage.tsx +++ b/packages/react-examples/src/react-charting/MultiStackedBarChart/MultiStackedBarChartPage.tsx @@ -6,7 +6,7 @@ import { PropertiesTableSet, } from '@fluentui/react-docsite-components'; -import { MultiStackedBarChartExample } from './MultiStackedBarChart.Example'; +import { MultiStackedBarChartBasicExample } from './MultiStackedBarChart.Example'; import { MultiStackedBarChartWithPlaceholderExample } from './MultiStackedBarChartWithPlaceHolder.Example'; import { MultiStackedBarChartVariantExample } from './MultiStackedBarChart.Variant.Example'; @@ -26,7 +26,7 @@ export class MultiStackedBarChartPage extends React.Component - + Date: Thu, 24 Aug 2023 13:05:00 +0200 Subject: [PATCH 07/26] Table/DataGrid: fix visuals for overflow (#28940) * Table/DataGrid: fix visuals for overflow * only use fit-content for resizable columns * props order * fix storybook examples * formatting * fix missing default state * fix unit tests * dashed border in vr test --- .../src/stories/Table.stories.tsx | 135 +++++++++++++++++- ...-1a06bc91-0c0f-464f-a1c3-4523427d45a1.json | 7 + .../src/components/DataGrid/useDataGrid.ts | 1 + .../react-table/src/hooks/types.ts | 4 +- .../src/hooks/useTableColumnSizing.test.ts | 1 + .../src/hooks/useTableColumnSizing.tsx | 14 +- .../DataGrid/ResizableColumns.stories.tsx | 82 +++++------ .../ResizableColumnsControlled.stories.tsx | 78 +++++----- .../ResizableColumnsUncontrolled.stories.tsx | 106 +++++++------- 9 files changed, 295 insertions(+), 133 deletions(-) create mode 100644 change/@fluentui-react-table-1a06bc91-0c0f-464f-a1c3-4523427d45a1.json diff --git a/apps/vr-tests-react-components/src/stories/Table.stories.tsx b/apps/vr-tests-react-components/src/stories/Table.stories.tsx index a4141467d2a5e1..17d5238e7e2c9e 100644 --- a/apps/vr-tests-react-components/src/stories/Table.stories.tsx +++ b/apps/vr-tests-react-components/src/stories/Table.stories.tsx @@ -23,12 +23,43 @@ import { TableCellActions, TableProps, TableRowProps, + useTableColumnSizing_unstable, + useTableFeatures, + TableColumnDefinition, + createTableColumn, } from '@fluentui/react-table'; import { Button } from '@fluentui/react-button'; import { storiesOf } from '@storybook/react'; import { Steps, StoryWright } from 'storywright'; -const items = [ +type FileCell = { + label: string; + icon: JSX.Element; +}; + +type LastUpdatedCell = { + label: string; + timestamp: number; +}; + +type LastUpdateCell = { + label: string; + icon: JSX.Element; +}; + +type AuthorCell = { + label: string; + status: PresenceBadgeStatus; +}; + +type Item = { + file: FileCell; + author: AuthorCell; + lastUpdated: LastUpdatedCell; + lastUpdate: LastUpdateCell; +}; + +const items: Item[] = [ { file: { label: 'Meeting notes', icon: }, author: { label: 'Max Mustermann', status: 'available' }, @@ -74,6 +105,25 @@ const columns = [ { columnKey: 'lastUpdate', label: 'Last update' }, ]; +const columnsDef: TableColumnDefinition[] = [ + createTableColumn({ + columnId: 'file', + renderHeaderCell: () => <>File, + }), + createTableColumn({ + columnId: 'author', + renderHeaderCell: () => <>Author, + }), + createTableColumn({ + columnId: 'lastUpdated', + renderHeaderCell: () => <>Last updated, + }), + createTableColumn({ + columnId: 'lastUpdate', + renderHeaderCell: () => <>Last update, + }), +]; + interface SharedVrTestArgs { noNativeElements: TableProps['noNativeElements']; selectedRowAppearance?: TableRowProps['appearance']; @@ -634,6 +684,85 @@ const Truncate: React.FC = ({ noNativ ); +const ResizableColumns: React.FC = ({ + noNativeElements, + scrollToEnd, +}) => { + const [columnSizingOptions] = React.useState({ + file: { + idealWidth: 300, + minWidth: 300, + }, + }); + + const { columnSizing_unstable: columnSizing, tableRef } = useTableFeatures( + { + columns: columnsDef, + items, + }, + [ + useTableColumnSizing_unstable({ + columnSizingOptions, + }), + ], + ); + return ( +
+ + + + {columns.map(column => ( + + {column.label} + + ))} + + + + {items.map((item, i) => ( + + + + {item.file.label} + +
+
+ ); +}; + ([true, false] as const).forEach(noNativeElements => { const layoutName = noNativeElements ? 'flex' : 'table'; storiesOf(`Table layout ${layoutName} - cell actions`, module) @@ -760,4 +889,8 @@ const Truncate: React.FC = ({ noNativ .addStory('default (disabled)', () => ) .addStory('false', () => ) .addStory('true', () => ); + + storiesOf(`Table layout ${layoutName} - resizable columns`, module) + .addStory('default', () => ) + .addStory('end', () => ); }); diff --git a/change/@fluentui-react-table-1a06bc91-0c0f-464f-a1c3-4523427d45a1.json b/change/@fluentui-react-table-1a06bc91-0c0f-464f-a1c3-4523427d45a1.json new file mode 100644 index 00000000000000..e5b367f414a594 --- /dev/null +++ b/change/@fluentui-react-table-1a06bc91-0c0f-464f-a1c3-4523427d45a1.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "fix: Improve visuals when Table/DataGrid overflows it's parent", + "packageName": "@fluentui/react-table", + "email": "jirivyhnalek@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-table/src/components/DataGrid/useDataGrid.ts b/packages/react-components/react-table/src/components/DataGrid/useDataGrid.ts index 039d058be6bacd..acf991ca4359f6 100644 --- a/packages/react-components/react-table/src/components/DataGrid/useDataGrid.ts +++ b/packages/react-components/react-table/src/components/DataGrid/useDataGrid.ts @@ -112,6 +112,7 @@ export const useDataGrid_unstable = (props: DataGridProps, ref: React.Ref; export type ColumnSizingTableHeaderCellProps = Pick; export type ColumnSizingTableCellProps = Pick; @@ -184,6 +185,7 @@ export interface TableColumnSizingState { getOnMouseDown: (columnId: TableColumnId) => (e: React.MouseEvent | React.TouchEvent) => void; setColumnWidth: (columnId: TableColumnId, newSize: number) => void; getColumnWidths: () => ColumnWidthState[]; + getTableProps: (props?: Partial) => ColumnSizingTableProps; getTableHeaderCellProps: (columnId: TableColumnId) => ColumnSizingTableHeaderCellProps; getTableCellProps: (columnId: TableColumnId) => ColumnSizingTableCellProps; enableKeyboardMode: ( diff --git a/packages/react-components/react-table/src/hooks/useTableColumnSizing.test.ts b/packages/react-components/react-table/src/hooks/useTableColumnSizing.test.ts index 66502b4399c78c..7f3669171bce08 100644 --- a/packages/react-components/react-table/src/hooks/useTableColumnSizing.test.ts +++ b/packages/react-components/react-table/src/hooks/useTableColumnSizing.test.ts @@ -62,6 +62,7 @@ describe('useTableColumnSizing', () => { "getOnMouseDown": [MockFunction], "getTableCellProps": [Function], "getTableHeaderCellProps": [Function], + "getTableProps": [Function], "setColumnWidth": [Function], } `); diff --git a/packages/react-components/react-table/src/hooks/useTableColumnSizing.tsx b/packages/react-components/react-table/src/hooks/useTableColumnSizing.tsx index 2c1a3cfe3e120c..1f63ef74d398ed 100644 --- a/packages/react-components/react-table/src/hooks/useTableColumnSizing.tsx +++ b/packages/react-components/react-table/src/hooks/useTableColumnSizing.tsx @@ -18,6 +18,7 @@ export const defaultColumnSizingState: TableColumnSizingState = { getColumnWidths: () => [], getOnMouseDown: () => () => null, setColumnWidth: () => null, + getTableProps: () => ({}), getTableHeaderCellProps: () => ({ style: {}, columnId: '' }), getTableCellProps: () => ({ style: {}, columnId: '' }), enableKeyboardMode: () => () => null, @@ -75,16 +76,27 @@ function useTableColumnSizingState( setColumnWidth: (columnId: TableColumnId, w: number) => columnResizeState.setColumnWidth(undefined, { columnId, width: w }), getColumnWidths: columnResizeState.getColumns, + getTableProps: (props = {}) => { + return { + ...props, + style: { + minWidth: 'fit-content', + ...(props.style || {}), + }, + }; + }, getTableHeaderCellProps: (columnId: TableColumnId) => { const col = columnResizeState.getColumnById(columnId); + const isLastColumn = columns[columns.length - 1]?.columnId === columnId; - const aside = ( + const aside = isLastColumn ? null : ( ); + return col ? { style: getColumnStyles(col), diff --git a/packages/react-components/react-table/stories/DataGrid/ResizableColumns.stories.tsx b/packages/react-components/react-table/stories/DataGrid/ResizableColumns.stories.tsx index 94df950d89f9b9..a9c0f19313329c 100644 --- a/packages/react-components/react-table/stories/DataGrid/ResizableColumns.stories.tsx +++ b/packages/react-components/react-table/stories/DataGrid/ResizableColumns.stories.tsx @@ -178,47 +178,49 @@ export const ResizableColumns = () => { const refMap = React.useRef>({}); return ( - item.file.label} - selectionMode="multiselect" - resizableColumns - columnSizingOptions={columnSizingOptions} - > - - - {({ renderHeaderCell, columnId }, dataGrid) => - dataGrid.resizableColumns ? ( - - - (refMap.current[columnId] = el)}> - {renderHeaderCell()} - - - - - - Keyboard Column Resizing - - - - - ) : ( - {renderHeaderCell()} - ) - } - - - > - {({ item, rowId }) => ( - key={rowId} selectionCell={{ 'aria-label': 'Select row' }}> - {({ renderCell }) => {renderCell(item)}} +
+ item.file.label} + selectionMode="multiselect" + resizableColumns + columnSizingOptions={columnSizingOptions} + > + + + {({ renderHeaderCell, columnId }, dataGrid) => + dataGrid.resizableColumns ? ( + + + (refMap.current[columnId] = el)}> + {renderHeaderCell()} + + + + + + Keyboard Column Resizing + + + + + ) : ( + {renderHeaderCell()} + ) + } - )} - - + + > + {({ item, rowId }) => ( + key={rowId} selectionCell={{ 'aria-label': 'Select row' }}> + {({ renderCell }) => {renderCell(item)}} + + )} + + +
); }; diff --git a/packages/react-components/react-table/stories/Table/ResizableColumnsControlled.stories.tsx b/packages/react-components/react-table/stories/Table/ResizableColumnsControlled.stories.tsx index 7661bd6657680f..5fda7f533f0628 100644 --- a/packages/react-components/react-table/stories/Table/ResizableColumnsControlled.stories.tsx +++ b/packages/react-components/react-table/stories/Table/ResizableColumnsControlled.stories.tsx @@ -272,46 +272,48 @@ export const ResizableColumnsControlled = () => { Add removed column

- - - - {columns.map((column, index) => ( - - - - {column.renderHeaderCell()} - removeColumn(index)}> - x - - - - - - - Keyboard Column Resizing - - - - - ))} - - - - {rows.map(({ item }) => ( - - {columns.map(column => ( - - {column.renderCell(item)} - +
+
+ + + {columns.map((column, index) => ( + + + + {column.renderHeaderCell()} + removeColumn(index)}> + x + + + + + + + Keyboard Column Resizing + + + + ))} - ))} - -
+ + + {rows.map(({ item }) => ( + + {columns.map(column => ( + + {column.renderCell(item)} + + ))} + + ))} + + +
); }; diff --git a/packages/react-components/react-table/stories/Table/ResizableColumnsUncontrolled.stories.tsx b/packages/react-components/react-table/stories/Table/ResizableColumnsUncontrolled.stories.tsx index db34111c955683..03416a45201829 100644 --- a/packages/react-components/react-table/stories/Table/ResizableColumnsUncontrolled.stories.tsx +++ b/packages/react-components/react-table/stories/Table/ResizableColumnsUncontrolled.stories.tsx @@ -161,60 +161,62 @@ export const ResizableColumnsUncontrolled = () => {

- - - - {columns.map(column => ( - - - +
+ + + {columns.map(column => ( + + + + {column.renderHeaderCell()} + + + + + + Keyboard Column Resizing + + + + + ))} + + + + {rows.map(({ item }) => ( + + + + {item.file.label} + + + + + } > - {column.renderHeaderCell()} - - - - - - Keyboard Column Resizing - - - - + {item.author.label} + + + + {item.lastUpdated.label} + + + + {item.lastUpdate.label} + + + ))} - - - - {rows.map(({ item }) => ( - - - - {item.file.label} - - - - - } - > - {item.author.label} - - - - {item.lastUpdated.label} - - - - {item.lastUpdate.label} - - - - ))} - -
+ + + ); }; From 20fb56a5d484e9a502bbce500530ab8653fbb1d6 Mon Sep 17 00:00:00 2001 From: Marcos Moura Date: Thu, 24 Aug 2023 14:18:01 +0200 Subject: [PATCH 08/26] docs: update drawer spec to be inline with changes to component (#28934) --- .../react-drawer/docs/Spec.md | 137 ++++++++++++------ 1 file changed, 92 insertions(+), 45 deletions(-) diff --git a/packages/react-components/react-drawer/docs/Spec.md b/packages/react-components/react-drawer/docs/Spec.md index ed2fc7a4d71b0a..cea633851a37c6 100644 --- a/packages/react-components/react-drawer/docs/Spec.md +++ b/packages/react-components/react-drawer/docs/Spec.md @@ -47,11 +47,11 @@ There is not prior implementation for this component in v0 ### Type -`overlay`: +`DrawerOverlay`: Opens on top of everything like a dialog and blocks all the page content. Can be dismissed. ![Example of Drawer as overlay](assets/overlay.png) -`inline`: +`DrawerInline`: Push the siblings content when open and it is non-blocking. Can be hidden to bring focus to the main content of the page. ![Example of Drawer as inline content](assets/inline.png) @@ -61,47 +61,90 @@ Push the siblings content when open and it is non-blocking. Can be hidden to bri - `medium`: 592px - `large`: 940px - `full`: 100vw -- `custom`: Can be freely customized by providing a number. It cannot be extended beyond screen limits. If the size is larger than the screen size, it'll act as a `full` Drawer. -### Modal +For any custom size, a style can be provided overriding the `width` of drawer. Drawer can never be extended beyond screen limits and in case the size is larger than the screen size, it'll act as a `full` Drawer. -By default, the `overlay` acts as a modal, rendering an overlay scrim behind the drawer surface. This can be toggled off. \* +### Modal -\* This prop DO NOT affect `inline` Drawers in any way. +By default, the `DrawerOverlay` acts as a modal, rendering an overlay scrim behind the drawer surface. This can be toggled off. ## API ### Drawer -| Property | Values | Default | Description | -| ------------ | ------------------------------------------ | --------- | ------------------------------------------------------- | -| type | `overlay`, `inline` | `overlay` | Set the [type](#type) of Drawer | -| position | `start`, `end` | `start` | Set the position of the Drawer | -| size | `small`, `medium`, `large`, `full`, number | `small` | The drawer width [size](#size) | -| modal | boolean | `true` | Set the visibility of the `overlay` scrim | -| open | boolean | `false` | Define the Drawer visibility | -| defaultOpen | boolean | `false` | Define the Drawer visibility on first render | -| onOpenChange | function | undefined | Callback called when drawer changes its visibility | -| separator | boolean | `false` | Define if the `inline` drawer should render a separator | - -| Slots | Values | Default | Description | -| ------------- | --------------- | --------------- | ------------------------------------------------- | -| root | `div` | `div` | The root drawer element | -| dialog | `Dialog` | `Dialog` | The dialog element for the `overlay` type | -| dialogSurface | `DialogSurface` | `DialogSurface` | The dialog surface element for the `overlay` type | +This component is a combination of both `DrawerInline` and `DrawerOverlay` + +| Property | Values | Default | Description | +| -------------- | ---------------------------------- | --------- | -------------------------------------------------------------------------------------- | +| type | `overlay`, `inline` | `overlay` | Set the [type](#type) of Drawer | +| position | `start`, `end` | `start` | Set the position of the Drawer | +| size | `small`, `medium`, `large`, `full` | `small` | The drawer width [size](#size) | +| modalType | boolean | `true` | Set the visibility of the backdrop scrim. Only for `type="overlay"` | +| inertTrapFocus | boolean | `true` | Enables standard behavior according to the HTML dialog spec. Only for `type="overlay"` | +| open | boolean | `false` | Define the Drawer visibility | +| defaultOpen | boolean | `false` | Define the Drawer visibility on first render | +| onOpenChange | function | undefined | Callback called when drawer changes its visibility. Only for `type="overlay"` | +| separator | boolean | `false` | Define if the `type="inline"` drawer should render a separator | + +| Slots | Values | Default | Description | +| ----- | ------ | ------- | ----------------------- | +| root | `div` | `div` | The root drawer element | + +### DrawerOverlay + +| Property | Values | Default | Description | +| -------------- | ---------------------------------- | --------- | ----------------------------------------------------------- | +| position | `start`, `end` | `start` | Set the position of the Drawer | +| size | `small`, `medium`, `large`, `full` | `small` | The drawer width [size](#size) | +| modalType | boolean | `true` | Set the visibility of the backdrop scrim | +| inertTrapFocus | boolean | `true` | Enables standard behavior according to the HTML dialog spec | +| open | boolean | `false` | Define the Drawer visibility | +| defaultOpen | boolean | `false` | Define the Drawer visibility on first render | +| onOpenChange | function | undefined | Callback called when drawer changes its visibility | + +| Slots | Values | Default | Description | +| ----- | ------ | ------- | ------------------------------- | +| root | `div` | `div` | The root overlay drawer element | + +### DrawerInline + +| Property | Values | Default | Description | +| ----------- | ---------------------------------- | ------- | ------------------------------------------------------- | +| position | `start`, `end` | `start` | Set the position of the Drawer | +| size | `small`, `medium`, `large`, `full` | `small` | The drawer width [size](#size) | +| open | boolean | `false` | Define the Drawer visibility | +| defaultOpen | boolean | `false` | Define the Drawer visibility on first render | +| separator | boolean | `false` | Define if the `inline` drawer should render a separator | + +| Slots | Values | Default | Description | +| ----- | ------ | ------- | ------------------------------ | +| root | `div` | `div` | The root inline drawer element | ### DrawerHeader -| Slots | Values | Default | Description | -| ---------- | -------- | -------- | -------------------------------------------------------- | -| root | `header` | `header` | The root drawer element | -| title | `div` | `div` | The drawer title | -| navigation | `div` | `div` | The drawer top navigation | -| actions | `div` | `div` | The drawer actions to be rendered side-by-side the title | +| Slots | Values | Default | Description | +| ----- | -------- | -------- | ----------------------- | +| root | `header` | `header` | The root drawer element | + +### DrawerHeaderNavigation + +| Slots | Values | Default | Description | +| ----- | ------ | ------- | ---------------------------------- | +| root | `nav` | `nav` | The root drawer navigation element | + +- [DrawerHeaderNavigation types](../src/components/DrawerHeaderNavigation/DrawerHeaderNavigation.types.ts) + +### DrawerHeaderTitle + +| Slots | Values | Default | Description | +| ------- | ----------------------------------------- | ------- | ------------------------------------- | +| root | `div` | `div` | The root drawer title element | +| heading | `h2`, `h1`, `h3`, `h4`, `h5`, `h6`, `div` | `h2` | The root drawer title heading element | +| action | `div` | `div` | Action slot for the close button | -- [DrawerHeader types](../src/components/DrawerHeader/DrawerHeader.types.ts) +- [DrawerHeaderTitle types](../src/components/DrawerHeaderTitle/DrawerHeaderTitle.types.ts) -### DrawerContent +### DrawerBody No props @@ -109,7 +152,7 @@ No props | ----- | ------ | ------- | ------------------------------- | | root | `div` | `div` | The root drawer content element | -- [DrawerContent types](../src/components/DrawerContent/DrawerContent.types.ts) +- [DrawerBody types](../src/components/DrawerBody/DrawerBody.types.ts) ### DrawerFooter @@ -125,29 +168,33 @@ No props ### Components -| Component | Purpose | -| ------------- | ---------------------------------------------------------------------------------------------------------------------- | -| Drawer | Renders a plain Drawer and render its children | -| DrawerHeader | Renders a `header` in a structured way. Ideal to display title and actions | -| DrawerContent | Renders a scrollable `div` that holds the drawer main content | -| DrawerFooter | Renders a `footer` element that holds the drawer main actions. Often used to have buttons such as confirmation actions | +| Component | Purpose | +| ---------------------- | ---------------------------------------------------------------------------------------------------------------------- | +| Drawer | Renders a plain inline or overlay Drawer and render its children | +| DrawerInline | Renders a plain inline Drawer and render its children | +| DrawerOverlay | Renders a plain overlay Drawer and render its children | +| DrawerHeader | Renders a `header` in a structured way. Ideal to display title and actions | +| DrawerHeaderNavigation | Renders a `header` in a structured way. Ideal to display title and actions | +| DrawerHeaderTitle | Renders a `header` in a structured way. Ideal to display title and actions | +| DrawerBody | Renders a scrollable `div` that holds the drawer main content | +| DrawerFooter | Renders a `footer` element that holds the drawer main actions. Often used to have buttons such as confirmation actions | #### Drawer component ![Drawer Anatomy](assets/drawer-anatomy.png) -- `overlay` type: +- DrawerOverlay or Drawer with `type="overlay"`: ```html - - - -`; - -exports[`AreaChart - mouse events Should render callout correctly on mouseover 1`] = ` - -`; - -exports[`AreaChart snapShot testing Should not render circles when optimizeLargeData is true 1`] = ` - -`; - -exports[`AreaChart snapShot testing Should render with default colors when line color is not provided 1`] = ` - -`; - -exports[`AreaChart snapShot testing renders Areachart correctly 1`] = ` -