From 097b4da13ca5a64cfe4cde45614ab91f63187295 Mon Sep 17 00:00:00 2001 From: Fluent UI Build Date: Thu, 23 Jan 2025 07:21:48 +0000 Subject: [PATCH 01/13] release: applying package updates - react v8 --- ...-5f3118c9-244c-41d1-8067-bca1566ec9bd.json | 7 ------- ...-e1bc4943-8298-429b-b844-5503943dff7c.json | 7 ------- packages/charts/react-charting/CHANGELOG.json | 21 +++++++++++++++++++ packages/charts/react-charting/CHANGELOG.md | 12 ++++++++++- packages/charts/react-charting/package.json | 2 +- .../react-docsite-components/CHANGELOG.json | 15 +++++++++++++ .../react-docsite-components/CHANGELOG.md | 11 +++++++++- .../react-docsite-components/package.json | 4 ++-- packages/react-examples/package.json | 4 ++-- packages/react-monaco-editor/CHANGELOG.json | 15 +++++++++++++ packages/react-monaco-editor/CHANGELOG.md | 11 +++++++++- packages/react-monaco-editor/package.json | 4 ++-- 12 files changed, 89 insertions(+), 24 deletions(-) delete mode 100644 change/@fluentui-react-charting-5f3118c9-244c-41d1-8067-bca1566ec9bd.json delete mode 100644 change/@fluentui-react-charting-e1bc4943-8298-429b-b844-5503943dff7c.json diff --git a/change/@fluentui-react-charting-5f3118c9-244c-41d1-8067-bca1566ec9bd.json b/change/@fluentui-react-charting-5f3118c9-244c-41d1-8067-bca1566ec9bd.json deleted file mode 100644 index 62e2f67fdb0cb4..00000000000000 --- a/change/@fluentui-react-charting-5f3118c9-244c-41d1-8067-bca1566ec9bd.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "patch", - "comment": "Support for dashed and dotted line in Declarative chart", - "packageName": "@fluentui/react-charting", - "email": "74965306+Anush2303@users.noreply.github.com", - "dependentChangeType": "patch" -} diff --git a/change/@fluentui-react-charting-e1bc4943-8298-429b-b844-5503943dff7c.json b/change/@fluentui-react-charting-e1bc4943-8298-429b-b844-5503943dff7c.json deleted file mode 100644 index 6197adf65a9d81..00000000000000 --- a/change/@fluentui-react-charting-e1bc4943-8298-429b-b844-5503943dff7c.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "patch", - "comment": "Heatmap text color based on contrast ratio", - "packageName": "@fluentui/react-charting", - "email": "74965306+Anush2303@users.noreply.github.com", - "dependentChangeType": "patch" -} diff --git a/packages/charts/react-charting/CHANGELOG.json b/packages/charts/react-charting/CHANGELOG.json index 8db0554ca711ad..c6b473cfbf45d5 100644 --- a/packages/charts/react-charting/CHANGELOG.json +++ b/packages/charts/react-charting/CHANGELOG.json @@ -1,6 +1,27 @@ { "name": "@fluentui/react-charting", "entries": [ + { + "date": "Thu, 23 Jan 2025 07:21:31 GMT", + "tag": "@fluentui/react-charting_v5.23.45", + "version": "5.23.45", + "comments": { + "patch": [ + { + "author": "74965306+Anush2303@users.noreply.github.com", + "package": "@fluentui/react-charting", + "commit": "82ef8b9000a1223756a4253aacde35fe4eaea401", + "comment": "Support for dashed and dotted line in Declarative chart" + }, + { + "author": "74965306+Anush2303@users.noreply.github.com", + "package": "@fluentui/react-charting", + "commit": "af631b94cfaa3e9a9d79160236a7f0679240777b", + "comment": "Heatmap text color based on contrast ratio" + } + ] + } + }, { "date": "Wed, 22 Jan 2025 07:21:49 GMT", "tag": "@fluentui/react-charting_v5.23.44", diff --git a/packages/charts/react-charting/CHANGELOG.md b/packages/charts/react-charting/CHANGELOG.md index a0a47695911967..6f2730f0d840bf 100644 --- a/packages/charts/react-charting/CHANGELOG.md +++ b/packages/charts/react-charting/CHANGELOG.md @@ -1,9 +1,19 @@ # Change Log - @fluentui/react-charting -This log was last generated on Wed, 22 Jan 2025 07:21:49 GMT and should not be manually modified. +This log was last generated on Thu, 23 Jan 2025 07:21:31 GMT and should not be manually modified. +## [5.23.45](https://github.com/microsoft/fluentui/tree/@fluentui/react-charting_v5.23.45) + +Thu, 23 Jan 2025 07:21:31 GMT +[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-charting_v5.23.44..@fluentui/react-charting_v5.23.45) + +### Patches + +- Support for dashed and dotted line in Declarative chart ([PR #33694](https://github.com/microsoft/fluentui/pull/33694) by 74965306+Anush2303@users.noreply.github.com) +- Heatmap text color based on contrast ratio ([PR #33659](https://github.com/microsoft/fluentui/pull/33659) by 74965306+Anush2303@users.noreply.github.com) + ## [5.23.44](https://github.com/microsoft/fluentui/tree/@fluentui/react-charting_v5.23.44) Wed, 22 Jan 2025 07:21:49 GMT diff --git a/packages/charts/react-charting/package.json b/packages/charts/react-charting/package.json index 3538c4ed6ed6d1..2d374462e78815 100644 --- a/packages/charts/react-charting/package.json +++ b/packages/charts/react-charting/package.json @@ -1,6 +1,6 @@ { "name": "@fluentui/react-charting", - "version": "5.23.44", + "version": "5.23.45", "description": "React web charting controls for Microsoft fluentui system.", "main": "lib-commonjs/index.js", "module": "lib/index.js", diff --git a/packages/react-docsite-components/CHANGELOG.json b/packages/react-docsite-components/CHANGELOG.json index 4e4713abc16d2d..d4c08b027ab584 100644 --- a/packages/react-docsite-components/CHANGELOG.json +++ b/packages/react-docsite-components/CHANGELOG.json @@ -1,6 +1,21 @@ { "name": "@fluentui/react-docsite-components", "entries": [ + { + "date": "Thu, 23 Jan 2025 07:21:32 GMT", + "tag": "@fluentui/react-docsite-components_v8.13.165", + "version": "8.13.165", + "comments": { + "patch": [ + { + "author": "beachball", + "package": "@fluentui/react-docsite-components", + "comment": "Bump @fluentui/react-monaco-editor to v1.7.283", + "commit": "af631b94cfaa3e9a9d79160236a7f0679240777b" + } + ] + } + }, { "date": "Wed, 22 Jan 2025 07:21:49 GMT", "tag": "@fluentui/react-docsite-components_v8.13.164", diff --git a/packages/react-docsite-components/CHANGELOG.md b/packages/react-docsite-components/CHANGELOG.md index 1ef89494b13355..6c96f151b7306c 100644 --- a/packages/react-docsite-components/CHANGELOG.md +++ b/packages/react-docsite-components/CHANGELOG.md @@ -1,9 +1,18 @@ # Change Log - @fluentui/react-docsite-components -This log was last generated on Wed, 22 Jan 2025 07:21:49 GMT and should not be manually modified. +This log was last generated on Thu, 23 Jan 2025 07:21:32 GMT and should not be manually modified. +## [8.13.165](https://github.com/microsoft/fluentui/tree/@fluentui/react-docsite-components_v8.13.165) + +Thu, 23 Jan 2025 07:21:32 GMT +[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-docsite-components_v8.13.164..@fluentui/react-docsite-components_v8.13.165) + +### Patches + +- Bump @fluentui/react-monaco-editor to v1.7.283 ([PR #33659](https://github.com/microsoft/fluentui/pull/33659) by beachball) + ## [8.13.164](https://github.com/microsoft/fluentui/tree/@fluentui/react-docsite-components_v8.13.164) Wed, 22 Jan 2025 07:21:49 GMT diff --git a/packages/react-docsite-components/package.json b/packages/react-docsite-components/package.json index abab114325df30..5327ed0cba431c 100644 --- a/packages/react-docsite-components/package.json +++ b/packages/react-docsite-components/package.json @@ -1,6 +1,6 @@ { "name": "@fluentui/react-docsite-components", - "version": "8.13.164", + "version": "8.13.165", "description": "Fluent UI React components for building documentation sites.", "main": "lib-commonjs/index.js", "module": "lib/index.js", @@ -42,7 +42,7 @@ "@fluentui/public-docsite-setup": "^0.3.34", "@fluentui/react-hooks": "^8.8.16", "@fluentui/set-version": "^8.2.23", - "@fluentui/react-monaco-editor": "^1.7.282", + "@fluentui/react-monaco-editor": "^1.7.283", "color-check": "0.0.2", "markdown-to-jsx": "^7.0.0", "office-ui-fabric-core": "^11.0.0", diff --git a/packages/react-examples/package.json b/packages/react-examples/package.json index 6bacbfd4dff619..465425a634cb68 100644 --- a/packages/react-examples/package.json +++ b/packages/react-examples/package.json @@ -36,8 +36,8 @@ "@fluentui/merge-styles": "^8.6.13", "@fluentui/react": "^8.122.8", "@fluentui/react-cards": "^0.205.197", - "@fluentui/react-charting": "^5.23.44", - "@fluentui/react-docsite-components": "^8.13.164", + "@fluentui/react-charting": "^5.23.45", + "@fluentui/react-docsite-components": "^8.13.165", "@fluentui/react-experiments": "^8.14.194", "@fluentui/react-file-type-icons": "^8.12.7", "@fluentui/react-focus": "^8.9.20", diff --git a/packages/react-monaco-editor/CHANGELOG.json b/packages/react-monaco-editor/CHANGELOG.json index 520705d278ed88..9108149b222ec4 100644 --- a/packages/react-monaco-editor/CHANGELOG.json +++ b/packages/react-monaco-editor/CHANGELOG.json @@ -1,6 +1,21 @@ { "name": "@fluentui/react-monaco-editor", "entries": [ + { + "date": "Thu, 23 Jan 2025 07:21:32 GMT", + "tag": "@fluentui/react-monaco-editor_v1.7.283", + "version": "1.7.283", + "comments": { + "patch": [ + { + "author": "beachball", + "package": "@fluentui/react-monaco-editor", + "comment": "Bump @fluentui/react-charting to v5.23.45", + "commit": "af631b94cfaa3e9a9d79160236a7f0679240777b" + } + ] + } + }, { "date": "Wed, 22 Jan 2025 07:21:49 GMT", "tag": "@fluentui/react-monaco-editor_v1.7.282", diff --git a/packages/react-monaco-editor/CHANGELOG.md b/packages/react-monaco-editor/CHANGELOG.md index 7455c40d5f1fd0..7e26d254ed8986 100644 --- a/packages/react-monaco-editor/CHANGELOG.md +++ b/packages/react-monaco-editor/CHANGELOG.md @@ -1,9 +1,18 @@ # Change Log - @fluentui/react-monaco-editor -This log was last generated on Wed, 22 Jan 2025 07:21:49 GMT and should not be manually modified. +This log was last generated on Thu, 23 Jan 2025 07:21:32 GMT and should not be manually modified. +## [1.7.283](https://github.com/microsoft/fluentui/tree/@fluentui/react-monaco-editor_v1.7.283) + +Thu, 23 Jan 2025 07:21:32 GMT +[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-monaco-editor_v1.7.282..@fluentui/react-monaco-editor_v1.7.283) + +### Patches + +- Bump @fluentui/react-charting to v5.23.45 ([PR #33659](https://github.com/microsoft/fluentui/pull/33659) by beachball) + ## [1.7.282](https://github.com/microsoft/fluentui/tree/@fluentui/react-monaco-editor_v1.7.282) Wed, 22 Jan 2025 07:21:49 GMT diff --git a/packages/react-monaco-editor/package.json b/packages/react-monaco-editor/package.json index 8c8ed891c4b016..9590d1fa7ced77 100644 --- a/packages/react-monaco-editor/package.json +++ b/packages/react-monaco-editor/package.json @@ -1,6 +1,6 @@ { "name": "@fluentui/react-monaco-editor", - "version": "1.7.282", + "version": "1.7.283", "description": "Live React example editing using monaco", "main": "lib-commonjs/index.js", "module": "lib/index.js", @@ -34,7 +34,7 @@ "@fluentui/example-data": "^8.4.25", "@fluentui/monaco-editor": "^1.3.24", "@fluentui/react-hooks": "^8.8.16", - "@fluentui/react-charting": "^5.23.44", + "@fluentui/react-charting": "^5.23.45", "raw-loader": "4.0.2", "react-syntax-highlighter": "^10.1.3", "tslib": "^2.1.0" From 397cadb61e559beb44da9d8a445cb99ffa4ae284 Mon Sep 17 00:00:00 2001 From: krkshitij <110246001+krkshitij@users.noreply.github.com> Date: Thu, 23 Jan 2025 16:14:17 +0530 Subject: [PATCH 02/13] fix(vr-tests): set a fixed value for culture prop in charts (#33690) --- .../src/stories/Charts/DonutChart.stories.tsx | 2 +- .../src/stories/Charts/HorizontalBarChart.stories.tsx | 2 +- .../src/stories/Charts/LineChart.stories.tsx | 2 +- .../src/stories/Charts/VerticalBarChart.stories.tsx | 2 +- .../src/stories/react-charting/AreaChart.stories.tsx | 2 +- .../src/stories/react-charting/DonutChart.stories.tsx | 2 +- .../src/stories/react-charting/HeatMapChart.stories.tsx | 2 +- .../react-charting/HorizontalBarChart.stories.tsx | 9 ++------- .../src/stories/react-charting/LineChart.stories.tsx | 2 +- .../src/stories/react-charting/Piechart.stories.tsx | 7 +------ .../stories/react-charting/StackedBarChart.stories.tsx | 4 ++-- .../stories/react-charting/VerticalBarChart.stories.tsx | 8 ++++---- 12 files changed, 17 insertions(+), 27 deletions(-) diff --git a/apps/vr-tests-react-components/src/stories/Charts/DonutChart.stories.tsx b/apps/vr-tests-react-components/src/stories/Charts/DonutChart.stories.tsx index d8f99d1ea3d3de..ebe06600298d19 100644 --- a/apps/vr-tests-react-components/src/stories/Charts/DonutChart.stories.tsx +++ b/apps/vr-tests-react-components/src/stories/Charts/DonutChart.stories.tsx @@ -29,7 +29,7 @@ export const Basic = () => { return (
{ return (
- +
); }; diff --git a/apps/vr-tests-react-components/src/stories/Charts/LineChart.stories.tsx b/apps/vr-tests-react-components/src/stories/Charts/LineChart.stories.tsx index 13736f225af00b..4896d53a1ca04f 100644 --- a/apps/vr-tests-react-components/src/stories/Charts/LineChart.stories.tsx +++ b/apps/vr-tests-react-components/src/stories/Charts/LineChart.stories.tsx @@ -149,7 +149,7 @@ export const Basic = () => { return (
{ return (
{ return (
{ return (
{ return (
ypointMapping[point as string]} diff --git a/apps/vr-tests/src/stories/react-charting/HorizontalBarChart.stories.tsx b/apps/vr-tests/src/stories/react-charting/HorizontalBarChart.stories.tsx index ff2ca9da844aec..c3cd51db8b8faa 100644 --- a/apps/vr-tests/src/stories/react-charting/HorizontalBarChart.stories.tsx +++ b/apps/vr-tests/src/stories/react-charting/HorizontalBarChart.stories.tsx @@ -136,12 +136,7 @@ export const Basic = () => { return (
- +
); }; @@ -345,7 +340,7 @@ export const WithAxis = () => { return (
{ return (
{ ]; const colors = ['#e81123', '#0078d4', '#107c10']; return ( - + ); }; diff --git a/apps/vr-tests/src/stories/react-charting/StackedBarChart.stories.tsx b/apps/vr-tests/src/stories/react-charting/StackedBarChart.stories.tsx index 960adc4b3c67f7..db3792dbde6e1c 100644 --- a/apps/vr-tests/src/stories/react-charting/StackedBarChart.stories.tsx +++ b/apps/vr-tests/src/stories/react-charting/StackedBarChart.stories.tsx @@ -45,14 +45,14 @@ export const Basic = () => { return (

{ return (
{ return (
{ return (
{ <>
Date: Thu, 23 Jan 2025 17:08:34 +0530 Subject: [PATCH 03/13] fix(react-charting): Centre align Gauge chart (#33710) --- ...-7de5fc28-d928-44e4-ae42-5c51737d6af8.json | 7 ++++ .../DeclarativeChartRTL.test.tsx.snap | 3 ++ .../GaugeChart/GaugeChart.styles.ts | 3 ++ .../__snapshots__/GaugeChart.test.tsx.snap | 33 +++++++++++++++++++ 4 files changed, 46 insertions(+) create mode 100644 change/@fluentui-react-charting-7de5fc28-d928-44e4-ae42-5c51737d6af8.json diff --git a/change/@fluentui-react-charting-7de5fc28-d928-44e4-ae42-5c51737d6af8.json b/change/@fluentui-react-charting-7de5fc28-d928-44e4-ae42-5c51737d6af8.json new file mode 100644 index 00000000000000..d07984401b110d --- /dev/null +++ b/change/@fluentui-react-charting-7de5fc28-d928-44e4-ae42-5c51737d6af8.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Centre align gauge chart", + "packageName": "@fluentui/react-charting", + "email": "74965306+Anush2303@users.noreply.github.com", + "dependentChangeType": "patch" +} 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 e6c11ebe4c8f29..cf92ce1f59e5a4 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 @@ -4026,6 +4026,9 @@ exports[`DeclarativeChart Should render gaugechart in DeclarativeChart 1`] = ` { -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; + align-items: center; + display: flex; + flex-direction: column; font-family: 'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif; font-size: 14px; font-weight: 400; diff --git a/packages/charts/react-charting/src/components/GaugeChart/GaugeChart.styles.ts b/packages/charts/react-charting/src/components/GaugeChart/GaugeChart.styles.ts index ba28944b57db0a..6819c7ea51051d 100644 --- a/packages/charts/react-charting/src/components/GaugeChart/GaugeChart.styles.ts +++ b/packages/charts/react-charting/src/components/GaugeChart/GaugeChart.styles.ts @@ -20,6 +20,9 @@ export const getStyles = (props: IGaugeChartStyleProps): IGaugeChartStyles => { theme.fonts.medium, 'ms-GaugeChart', { + alignItems: 'center', + display: 'flex', + flexDirection: 'column', width: '100%', height: '100%', }, diff --git a/packages/charts/react-charting/src/components/GaugeChart/__snapshots__/GaugeChart.test.tsx.snap b/packages/charts/react-charting/src/components/GaugeChart/__snapshots__/GaugeChart.test.tsx.snap index 41ff22e9be5407..b000897d82e23c 100644 --- a/packages/charts/react-charting/src/components/GaugeChart/__snapshots__/GaugeChart.test.tsx.snap +++ b/packages/charts/react-charting/src/components/GaugeChart/__snapshots__/GaugeChart.test.tsx.snap @@ -9,6 +9,9 @@ exports[`GaugeChart interaction and accessibility tests should show a callout wh { -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; + align-items: center; + display: flex; + flex-direction: column; font-family: 'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif; font-size: 14px; font-weight: 400; @@ -828,6 +831,9 @@ exports[`GaugeChart snapshot tests should not render min and max values of the g { -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; + align-items: center; + display: flex; + flex-direction: column; font-family: 'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif; font-size: 14px; font-weight: 400; @@ -1372,6 +1378,9 @@ exports[`GaugeChart snapshot tests should not render the legends when the hideLe { -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; + align-items: center; + display: flex; + flex-direction: column; font-family: 'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif; font-size: 14px; font-weight: 400; @@ -1563,6 +1572,9 @@ exports[`GaugeChart snapshot tests should render GaugeChart correctly 1`] = ` { -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; + align-items: center; + display: flex; + flex-direction: column; font-family: 'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif; font-size: 14px; font-weight: 400; @@ -2152,6 +2164,9 @@ exports[`GaugeChart snapshot tests should render GaugeChart correctly in dark th { -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; + align-items: center; + display: flex; + flex-direction: column; font-family: 'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif; font-size: 14px; font-weight: 400; @@ -2729,6 +2744,9 @@ exports[`GaugeChart snapshot tests should render GaugeChart correctly when the l { -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; + align-items: center; + display: flex; + flex-direction: column; font-family: 'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif; font-size: 14px; font-weight: 400; @@ -3305,6 +3323,9 @@ exports[`GaugeChart snapshot tests should render a color from DataVizPalette for { -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; + align-items: center; + display: flex; + flex-direction: column; font-family: 'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif; font-size: 14px; font-weight: 400; @@ -3758,6 +3779,9 @@ exports[`GaugeChart snapshot tests should render a placeholder segment when the { -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; + align-items: center; + display: flex; + flex-direction: column; font-family: 'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif; font-size: 14px; font-weight: 400; @@ -4210,6 +4234,9 @@ exports[`GaugeChart snapshot tests should render the chart title correctly 1`] = { -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; + align-items: center; + display: flex; + flex-direction: column; font-family: 'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif; font-size: 14px; font-weight: 400; @@ -4800,6 +4827,9 @@ exports[`GaugeChart snapshot tests should render the chart value in fraction for { -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; + align-items: center; + display: flex; + flex-direction: column; font-family: 'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif; font-size: 14px; font-weight: 400; @@ -5376,6 +5406,9 @@ exports[`GaugeChart snapshot tests should render the sublabel correctly 1`] = ` { -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; + align-items: center; + display: flex; + flex-direction: column; font-family: 'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif; font-size: 14px; font-weight: 400; From af2beb890815cc83b3426e266106bd3c57b4c7c6 Mon Sep 17 00:00:00 2001 From: Valentyna Date: Thu, 23 Jan 2025 05:20:44 -0800 Subject: [PATCH 04/13] test(react-color-picker): Added cy and a11y tests for sliders (#33609) --- .../components/AlphaSlider/AlphaSlider.cy.tsx | 192 ++++++++++++++++++ .../components/ColorSlider/ColorSlider.cy.tsx | 125 ++++++++++++ 2 files changed, 317 insertions(+) create mode 100644 packages/react-components/react-color-picker-preview/library/src/components/AlphaSlider/AlphaSlider.cy.tsx create mode 100644 packages/react-components/react-color-picker-preview/library/src/components/ColorSlider/ColorSlider.cy.tsx diff --git a/packages/react-components/react-color-picker-preview/library/src/components/AlphaSlider/AlphaSlider.cy.tsx b/packages/react-components/react-color-picker-preview/library/src/components/AlphaSlider/AlphaSlider.cy.tsx new file mode 100644 index 00000000000000..50dbbd82223578 --- /dev/null +++ b/packages/react-components/react-color-picker-preview/library/src/components/AlphaSlider/AlphaSlider.cy.tsx @@ -0,0 +1,192 @@ +import * as React from 'react'; +import { mount } from '@cypress/react'; +import { FluentProvider } from '@fluentui/react-provider'; +import { webLightTheme } from '@fluentui/react-theme'; +import { AlphaSlider } from './AlphaSlider'; +import type { AlphaSliderProps } from './AlphaSlider.types'; +import { calculateTransparencyValue } from './alphaSliderUtils'; +import { INITIAL_COLOR_HSV } from '../../utils/constants'; + +const mountFluent = (element: JSX.Element) => { + mount({element}); +}; + +const AlphaSliderExample = (props: AlphaSliderProps) => { + const { transparency = false } = props; + const [color, setColor] = React.useState(props.color ?? INITIAL_COLOR_HSV); + return ( + setColor(data.color)} + id="alpha-slider" + aria-label="Alpha" + aria-valuetext={`${calculateTransparencyValue(transparency, color.a ?? 1)}%`} + transparency={transparency} + /> + ); +}; + +describe('AlphaSlider', () => { + describe('keyboard navigation', () => { + it('has correct focus behavior', () => { + mountFluent( + <> +

+ Before +

+ +

+ After +

+ , + ); + cy.get('#before').focus(); + cy.realPress('Tab'); + cy.get('#alpha-slider').should('have.focus'); + cy.realPress('Tab'); + cy.get('#alpha-slider').should('not.have.focus'); + cy.get('#after').should('have.focus'); + }); + + describe('alpha channel', () => { + it('selected correctly', () => { + mountFluent(); + cy.get('.fui-AlphaSlider__input').focus(); + + // decrements the value two times + cy.realPress('ArrowLeft'); + cy.realPress('ArrowLeft'); + assertSliderValue('48'); + + // increments the value + cy.realPress('ArrowRight'); + assertSliderValue('49'); + + // increments the value with arrowUp + cy.realPress('ArrowUp'); + assertSliderValue('50'); + + // decrements the value with arrowDown + cy.realPress('ArrowDown'); + assertSliderValue('49'); + }); + + it('selected on left edge correctly', () => { + mountFluent(); + cy.get('.fui-AlphaSlider__input').focus(); + + // decrements the value two times + cy.realPress('ArrowLeft'); + cy.realPress('ArrowLeft'); + assertSliderValue('0'); + + // decrements the value on left edge + cy.realPress('ArrowLeft'); + assertSliderValue('0'); + + // increments the value + cy.realPress('ArrowRight'); + assertSliderValue('1'); + }); + + it('selected on right edge correctly', () => { + mountFluent(); + cy.get('.fui-AlphaSlider__input').focus(); + + // increments the value + cy.realPress('ArrowRight'); + assertSliderValue('99'); + + // increments the value + cy.realPress('ArrowRight'); + assertSliderValue('100'); + + // increments the value on right edge + cy.realPress('ArrowRight'); + assertSliderValue('100'); + + // decrements the value + cy.realPress('ArrowLeft'); + assertSliderValue('99'); + }); + }); + }); + + describe('transparency', () => { + it('selected correctly', () => { + mountFluent(); + cy.get('.fui-AlphaSlider__input').focus(); + + // decrements the value two times + cy.realPress('ArrowLeft'); + cy.realPress('ArrowLeft'); + assertSliderValue('28'); + + // increments the value + cy.realPress('ArrowRight'); + assertSliderValue('29'); + + // increments the value with arrowUp + cy.realPress('ArrowUp'); + assertSliderValue('30'); + + // decrements the value with arrowDown + cy.realPress('ArrowDown'); + assertSliderValue('29'); + }); + + it('selected on left edge correctly', () => { + mountFluent(); + cy.get('.fui-AlphaSlider__input').focus(); + + // decrements the value two times + cy.realPress('ArrowLeft'); + cy.realPress('ArrowLeft'); + assertSliderValue('0'); + + // decrements the value on left edge + cy.realPress('ArrowLeft'); + assertSliderValue('0'); + + // increments the value + cy.realPress('ArrowRight'); + assertSliderValue('1'); + }); + + it('selected on right edge correctly', () => { + mountFluent(); + cy.get('.fui-AlphaSlider__input').focus(); + + // increments the value + cy.realPress('ArrowRight'); + assertSliderValue('99'); + + // increments the value + cy.realPress('ArrowRight'); + assertSliderValue('100'); + + // increments the value on right edge + cy.realPress('ArrowRight'); + assertSliderValue('100'); + + // decrements the value + cy.realPress('ArrowLeft'); + assertSliderValue('99'); + }); + }); + + describe('mouse navigation', () => { + it('has correct a11y attributes', () => { + mountFluent(); + cy.get('#alpha-slider').should('have.attr', 'aria-label', 'Alpha'); + assertSliderValue('100'); + cy.get('#alpha-slider').realClick(); + assertSliderValue('50'); + }); + }); +}); + +function assertSliderValue(value: string) { + cy.get('#alpha-slider').should('have.attr', 'aria-valuetext', `${value}%`); + cy.get('#alpha-slider').should('have.attr', 'value', value); +} diff --git a/packages/react-components/react-color-picker-preview/library/src/components/ColorSlider/ColorSlider.cy.tsx b/packages/react-components/react-color-picker-preview/library/src/components/ColorSlider/ColorSlider.cy.tsx new file mode 100644 index 00000000000000..1a5a7903817b27 --- /dev/null +++ b/packages/react-components/react-color-picker-preview/library/src/components/ColorSlider/ColorSlider.cy.tsx @@ -0,0 +1,125 @@ +import * as React from 'react'; +import { mount } from '@cypress/react'; +import { FluentProvider } from '@fluentui/react-provider'; +import { webLightTheme } from '@fluentui/react-theme'; +import { ColorSlider } from './ColorSlider'; +import type { ColorSliderProps } from './ColorSlider.types'; +import { INITIAL_COLOR_HSV } from '../../utils/constants'; + +const mountFluent = (element: JSX.Element) => { + mount({element}); +}; + +const ColorSliderExample = (props: ColorSliderProps) => { + const [color, setColor] = React.useState(props.color ?? INITIAL_COLOR_HSV); + return ( + setColor(data.color)} + id="color-slider" + aria-label="Hue" + aria-valuetext={`${color.h}°`} + /> + ); +}; + +describe('ColorSlider', () => { + describe('keyboard navigation', () => { + it('has correct focus behavior', () => { + mountFluent( + <> +

+ Before +

+ +

+ After +

+ , + ); + cy.get('#before').focus(); + cy.realPress('Tab'); + cy.get('#color-slider').should('have.focus'); + cy.realPress('Tab'); + cy.get('#color-slider').should('not.have.focus'); + cy.get('#after').should('have.focus'); + }); + + it('hue channel selected correctly', () => { + mountFluent(); + cy.get('.fui-ColorSlider__input').focus(); + + // decrements the value two times + cy.realPress('ArrowLeft'); + cy.realPress('ArrowLeft'); + assertSliderValue('104'); + + // increments the value + cy.realPress('ArrowRight'); + assertSliderValue('105'); + + // increments the value with arrowUp + cy.realPress('ArrowUp'); + assertSliderValue('106'); + + // decrements the value with arrowDown + cy.realPress('ArrowDown'); + assertSliderValue('105'); + }); + + it('hue channel selected on left edge correctly', () => { + mountFluent(); + cy.get('.fui-ColorSlider__input').focus(); + + // decrements the value two times + cy.realPress('ArrowLeft'); + cy.realPress('ArrowLeft'); + assertSliderValue('0'); + + // decrements the value on left edge + cy.realPress('ArrowLeft'); + assertSliderValue('0'); + + // increments the value + cy.realPress('ArrowRight'); + assertSliderValue('1'); + }); + + it('hue channel selected on right edge correctly', () => { + mountFluent(); + cy.get('.fui-ColorSlider__input').focus(); + + // increments the value + cy.realPress('ArrowRight'); + assertSliderValue('359'); + + // increments the value + cy.realPress('ArrowRight'); + assertSliderValue('360'); + + // increments the value on right edge + cy.realPress('ArrowRight'); + assertSliderValue('360'); + + // decrements the value + cy.realPress('ArrowLeft'); + assertSliderValue('359'); + }); + }); + + describe('mouse navigation', () => { + it('has correct a11y attributes', () => { + mountFluent(); + cy.get('#color-slider').should('have.attr', 'aria-label', 'Hue'); + assertSliderValue('324'); + + cy.get('#color-slider').realClick(); + assertSliderValue('180'); + }); + }); +}); + +function assertSliderValue(value: string) { + cy.get('#color-slider').should('have.attr', 'aria-valuetext', `${value}°`); + cy.get('#color-slider').should('have.attr', 'value', value); +} From cb0f0c9653a8a5c53012d35d81498de263a8f3cf Mon Sep 17 00:00:00 2001 From: Valentyna Date: Thu, 23 Jan 2025 09:00:45 -0800 Subject: [PATCH 05/13] docs(react-card): added aria-label to the action button in CardFooter (#33717) --- .../stories/src/CardFooter/CardFooterDefault.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-components/react-card/stories/src/CardFooter/CardFooterDefault.stories.tsx b/packages/react-components/react-card/stories/src/CardFooter/CardFooterDefault.stories.tsx index bc1f2167d38ec4..84359a729fb5e7 100644 --- a/packages/react-components/react-card/stories/src/CardFooter/CardFooterDefault.stories.tsx +++ b/packages/react-components/react-card/stories/src/CardFooter/CardFooterDefault.stories.tsx @@ -15,7 +15,7 @@ export const Default = () => { return ( } />} + action={ From 74d0fd8d80d723424a33e31b00683bfdd4ad7aa7 Mon Sep 17 00:00:00 2001 From: Fluent UI Build Date: Fri, 24 Jan 2025 07:20:54 +0000 Subject: [PATCH 06/13] release: applying package updates - react v8 --- ...ting-7de5fc28-d928-44e4-ae42-5c51737d6af8.json | 7 ------- packages/charts/react-charting/CHANGELOG.json | 15 +++++++++++++++ packages/charts/react-charting/CHANGELOG.md | 11 ++++++++++- packages/charts/react-charting/package.json | 2 +- packages/react-docsite-components/CHANGELOG.json | 15 +++++++++++++++ packages/react-docsite-components/CHANGELOG.md | 11 ++++++++++- packages/react-docsite-components/package.json | 4 ++-- packages/react-examples/package.json | 4 ++-- packages/react-monaco-editor/CHANGELOG.json | 15 +++++++++++++++ packages/react-monaco-editor/CHANGELOG.md | 11 ++++++++++- packages/react-monaco-editor/package.json | 4 ++-- 11 files changed, 82 insertions(+), 17 deletions(-) delete mode 100644 change/@fluentui-react-charting-7de5fc28-d928-44e4-ae42-5c51737d6af8.json diff --git a/change/@fluentui-react-charting-7de5fc28-d928-44e4-ae42-5c51737d6af8.json b/change/@fluentui-react-charting-7de5fc28-d928-44e4-ae42-5c51737d6af8.json deleted file mode 100644 index d07984401b110d..00000000000000 --- a/change/@fluentui-react-charting-7de5fc28-d928-44e4-ae42-5c51737d6af8.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "patch", - "comment": "Centre align gauge chart", - "packageName": "@fluentui/react-charting", - "email": "74965306+Anush2303@users.noreply.github.com", - "dependentChangeType": "patch" -} diff --git a/packages/charts/react-charting/CHANGELOG.json b/packages/charts/react-charting/CHANGELOG.json index c6b473cfbf45d5..0e35b815417dd6 100644 --- a/packages/charts/react-charting/CHANGELOG.json +++ b/packages/charts/react-charting/CHANGELOG.json @@ -1,6 +1,21 @@ { "name": "@fluentui/react-charting", "entries": [ + { + "date": "Fri, 24 Jan 2025 07:20:37 GMT", + "tag": "@fluentui/react-charting_v5.23.46", + "version": "5.23.46", + "comments": { + "patch": [ + { + "author": "74965306+Anush2303@users.noreply.github.com", + "package": "@fluentui/react-charting", + "commit": "0cca67396f110239e39d8cc5de96c9b128ca07de", + "comment": "Centre align gauge chart" + } + ] + } + }, { "date": "Thu, 23 Jan 2025 07:21:31 GMT", "tag": "@fluentui/react-charting_v5.23.45", diff --git a/packages/charts/react-charting/CHANGELOG.md b/packages/charts/react-charting/CHANGELOG.md index 6f2730f0d840bf..b1780055d0cfdd 100644 --- a/packages/charts/react-charting/CHANGELOG.md +++ b/packages/charts/react-charting/CHANGELOG.md @@ -1,9 +1,18 @@ # Change Log - @fluentui/react-charting -This log was last generated on Thu, 23 Jan 2025 07:21:31 GMT and should not be manually modified. +This log was last generated on Fri, 24 Jan 2025 07:20:37 GMT and should not be manually modified. +## [5.23.46](https://github.com/microsoft/fluentui/tree/@fluentui/react-charting_v5.23.46) + +Fri, 24 Jan 2025 07:20:37 GMT +[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-charting_v5.23.45..@fluentui/react-charting_v5.23.46) + +### Patches + +- Centre align gauge chart ([PR #33710](https://github.com/microsoft/fluentui/pull/33710) by 74965306+Anush2303@users.noreply.github.com) + ## [5.23.45](https://github.com/microsoft/fluentui/tree/@fluentui/react-charting_v5.23.45) Thu, 23 Jan 2025 07:21:31 GMT diff --git a/packages/charts/react-charting/package.json b/packages/charts/react-charting/package.json index 2d374462e78815..e684171bcf5271 100644 --- a/packages/charts/react-charting/package.json +++ b/packages/charts/react-charting/package.json @@ -1,6 +1,6 @@ { "name": "@fluentui/react-charting", - "version": "5.23.45", + "version": "5.23.46", "description": "React web charting controls for Microsoft fluentui system.", "main": "lib-commonjs/index.js", "module": "lib/index.js", diff --git a/packages/react-docsite-components/CHANGELOG.json b/packages/react-docsite-components/CHANGELOG.json index d4c08b027ab584..7cabe24b98da22 100644 --- a/packages/react-docsite-components/CHANGELOG.json +++ b/packages/react-docsite-components/CHANGELOG.json @@ -1,6 +1,21 @@ { "name": "@fluentui/react-docsite-components", "entries": [ + { + "date": "Fri, 24 Jan 2025 07:20:37 GMT", + "tag": "@fluentui/react-docsite-components_v8.13.166", + "version": "8.13.166", + "comments": { + "patch": [ + { + "author": "beachball", + "package": "@fluentui/react-docsite-components", + "comment": "Bump @fluentui/react-monaco-editor to v1.7.284", + "commit": "cb0f0c9653a8a5c53012d35d81498de263a8f3cf" + } + ] + } + }, { "date": "Thu, 23 Jan 2025 07:21:32 GMT", "tag": "@fluentui/react-docsite-components_v8.13.165", diff --git a/packages/react-docsite-components/CHANGELOG.md b/packages/react-docsite-components/CHANGELOG.md index 6c96f151b7306c..bb0c0dbf48d91c 100644 --- a/packages/react-docsite-components/CHANGELOG.md +++ b/packages/react-docsite-components/CHANGELOG.md @@ -1,9 +1,18 @@ # Change Log - @fluentui/react-docsite-components -This log was last generated on Thu, 23 Jan 2025 07:21:32 GMT and should not be manually modified. +This log was last generated on Fri, 24 Jan 2025 07:20:37 GMT and should not be manually modified. +## [8.13.166](https://github.com/microsoft/fluentui/tree/@fluentui/react-docsite-components_v8.13.166) + +Fri, 24 Jan 2025 07:20:37 GMT +[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-docsite-components_v8.13.165..@fluentui/react-docsite-components_v8.13.166) + +### Patches + +- Bump @fluentui/react-monaco-editor to v1.7.284 ([PR #33717](https://github.com/microsoft/fluentui/pull/33717) by beachball) + ## [8.13.165](https://github.com/microsoft/fluentui/tree/@fluentui/react-docsite-components_v8.13.165) Thu, 23 Jan 2025 07:21:32 GMT diff --git a/packages/react-docsite-components/package.json b/packages/react-docsite-components/package.json index 5327ed0cba431c..87b6d92d67f959 100644 --- a/packages/react-docsite-components/package.json +++ b/packages/react-docsite-components/package.json @@ -1,6 +1,6 @@ { "name": "@fluentui/react-docsite-components", - "version": "8.13.165", + "version": "8.13.166", "description": "Fluent UI React components for building documentation sites.", "main": "lib-commonjs/index.js", "module": "lib/index.js", @@ -42,7 +42,7 @@ "@fluentui/public-docsite-setup": "^0.3.34", "@fluentui/react-hooks": "^8.8.16", "@fluentui/set-version": "^8.2.23", - "@fluentui/react-monaco-editor": "^1.7.283", + "@fluentui/react-monaco-editor": "^1.7.284", "color-check": "0.0.2", "markdown-to-jsx": "^7.0.0", "office-ui-fabric-core": "^11.0.0", diff --git a/packages/react-examples/package.json b/packages/react-examples/package.json index 465425a634cb68..03cb95a9913de4 100644 --- a/packages/react-examples/package.json +++ b/packages/react-examples/package.json @@ -36,8 +36,8 @@ "@fluentui/merge-styles": "^8.6.13", "@fluentui/react": "^8.122.8", "@fluentui/react-cards": "^0.205.197", - "@fluentui/react-charting": "^5.23.45", - "@fluentui/react-docsite-components": "^8.13.165", + "@fluentui/react-charting": "^5.23.46", + "@fluentui/react-docsite-components": "^8.13.166", "@fluentui/react-experiments": "^8.14.194", "@fluentui/react-file-type-icons": "^8.12.7", "@fluentui/react-focus": "^8.9.20", diff --git a/packages/react-monaco-editor/CHANGELOG.json b/packages/react-monaco-editor/CHANGELOG.json index 9108149b222ec4..64c72b368b3779 100644 --- a/packages/react-monaco-editor/CHANGELOG.json +++ b/packages/react-monaco-editor/CHANGELOG.json @@ -1,6 +1,21 @@ { "name": "@fluentui/react-monaco-editor", "entries": [ + { + "date": "Fri, 24 Jan 2025 07:20:37 GMT", + "tag": "@fluentui/react-monaco-editor_v1.7.284", + "version": "1.7.284", + "comments": { + "patch": [ + { + "author": "beachball", + "package": "@fluentui/react-monaco-editor", + "comment": "Bump @fluentui/react-charting to v5.23.46", + "commit": "cb0f0c9653a8a5c53012d35d81498de263a8f3cf" + } + ] + } + }, { "date": "Thu, 23 Jan 2025 07:21:32 GMT", "tag": "@fluentui/react-monaco-editor_v1.7.283", diff --git a/packages/react-monaco-editor/CHANGELOG.md b/packages/react-monaco-editor/CHANGELOG.md index 7e26d254ed8986..df035313f71848 100644 --- a/packages/react-monaco-editor/CHANGELOG.md +++ b/packages/react-monaco-editor/CHANGELOG.md @@ -1,9 +1,18 @@ # Change Log - @fluentui/react-monaco-editor -This log was last generated on Thu, 23 Jan 2025 07:21:32 GMT and should not be manually modified. +This log was last generated on Fri, 24 Jan 2025 07:20:37 GMT and should not be manually modified. +## [1.7.284](https://github.com/microsoft/fluentui/tree/@fluentui/react-monaco-editor_v1.7.284) + +Fri, 24 Jan 2025 07:20:37 GMT +[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-monaco-editor_v1.7.283..@fluentui/react-monaco-editor_v1.7.284) + +### Patches + +- Bump @fluentui/react-charting to v5.23.46 ([PR #33717](https://github.com/microsoft/fluentui/pull/33717) by beachball) + ## [1.7.283](https://github.com/microsoft/fluentui/tree/@fluentui/react-monaco-editor_v1.7.283) Thu, 23 Jan 2025 07:21:32 GMT diff --git a/packages/react-monaco-editor/package.json b/packages/react-monaco-editor/package.json index 9590d1fa7ced77..dce7f2c006e2a0 100644 --- a/packages/react-monaco-editor/package.json +++ b/packages/react-monaco-editor/package.json @@ -1,6 +1,6 @@ { "name": "@fluentui/react-monaco-editor", - "version": "1.7.283", + "version": "1.7.284", "description": "Live React example editing using monaco", "main": "lib-commonjs/index.js", "module": "lib/index.js", @@ -34,7 +34,7 @@ "@fluentui/example-data": "^8.4.25", "@fluentui/monaco-editor": "^1.3.24", "@fluentui/react-hooks": "^8.8.16", - "@fluentui/react-charting": "^5.23.45", + "@fluentui/react-charting": "^5.23.46", "raw-loader": "4.0.2", "react-syntax-highlighter": "^10.1.3", "tslib": "^2.1.0" From 57165f4aa96f1417347275e52262f6de755225d5 Mon Sep 17 00:00:00 2001 From: krkshitij <110246001+krkshitij@users.noreply.github.com> Date: Fri, 24 Jan 2025 12:50:59 +0530 Subject: [PATCH 07/13] fix(react-charting): ensure text elements use the correct font-family in SVG export (#33719) --- ...eact-charting-ef56337f-c8bb-48ee-94f5-75abe0aa1d3b.json | 7 +++++++ .../src/components/DeclarativeChart/imageExporter.ts | 2 ++ 2 files changed, 9 insertions(+) create mode 100644 change/@fluentui-react-charting-ef56337f-c8bb-48ee-94f5-75abe0aa1d3b.json diff --git a/change/@fluentui-react-charting-ef56337f-c8bb-48ee-94f5-75abe0aa1d3b.json b/change/@fluentui-react-charting-ef56337f-c8bb-48ee-94f5-75abe0aa1d3b.json new file mode 100644 index 00000000000000..e8006f3935cb83 --- /dev/null +++ b/change/@fluentui-react-charting-ef56337f-c8bb-48ee-94f5-75abe0aa1d3b.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "fix: ensure text elements use the correct font-family in SVG export", + "packageName": "@fluentui/react-charting", + "email": "110246001+krkshitij@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/packages/charts/react-charting/src/components/DeclarativeChart/imageExporter.ts b/packages/charts/react-charting/src/components/DeclarativeChart/imageExporter.ts index ef5716d9fa2af4..f3416feb0609b6 100644 --- a/packages/charts/react-charting/src/components/DeclarativeChart/imageExporter.ts +++ b/packages/charts/react-charting/src/components/DeclarativeChart/imageExporter.ts @@ -53,7 +53,9 @@ function toSVG(chartContainer: HTMLElement, background: string) { .attr('width', null) .attr('height', null) .attr('viewBox', null); + const { fontFamily } = getComputedStyle(chartContainer); + clonedSvg.selectAll('text').style('font-family', fontFamily); if (legendGroup.node) { clonedSvg.append(() => legendGroup.node); } From d8e6230e7e0b504a9651d10b15860ccaf0a87824 Mon Sep 17 00:00:00 2001 From: Valentyna Date: Fri, 24 Jan 2025 03:48:12 -0800 Subject: [PATCH 08/13] fix(react-color-picker): default state of ColorPicker (#33715) --- ...icker-preview-0c1f8cab-ce3f-4b53-a9d0-08e7c1907218.json | 7 +++++++ .../library/etc/react-color-picker-preview.api.md | 2 +- .../src/components/AlphaSlider/useAlphaSliderState.ts | 4 ++-- .../src/components/ColorPicker/ColorPicker.types.ts | 2 +- .../library/src/components/ColorSlider/useColorSlider.ts | 3 ++- .../library/src/contexts/colorPicker.ts | 6 ++---- .../library/src/utils/createHsvColor.ts | 5 +++++ 7 files changed, 20 insertions(+), 9 deletions(-) create mode 100644 change/@fluentui-react-color-picker-preview-0c1f8cab-ce3f-4b53-a9d0-08e7c1907218.json create mode 100644 packages/react-components/react-color-picker-preview/library/src/utils/createHsvColor.ts diff --git a/change/@fluentui-react-color-picker-preview-0c1f8cab-ce3f-4b53-a9d0-08e7c1907218.json b/change/@fluentui-react-color-picker-preview-0c1f8cab-ce3f-4b53-a9d0-08e7c1907218.json new file mode 100644 index 00000000000000..411ee67c9b45aa --- /dev/null +++ b/change/@fluentui-react-color-picker-preview-0c1f8cab-ce3f-4b53-a9d0-08e7c1907218.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "fix: default state for ColorSliders", + "packageName": "@fluentui/react-color-picker-preview", + "email": "v.kozlova13@gmail.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-color-picker-preview/library/etc/react-color-picker-preview.api.md b/packages/react-components/react-color-picker-preview/library/etc/react-color-picker-preview.api.md index 8190eeb7f921ca..38caa1b4fcd294 100644 --- a/packages/react-components/react-color-picker-preview/library/etc/react-color-picker-preview.api.md +++ b/packages/react-components/react-color-picker-preview/library/etc/react-color-picker-preview.api.md @@ -62,7 +62,7 @@ export const colorPickerClassNames: SlotClassNames; // @public export type ColorPickerProps = Omit>, 'color'> & { - color: HsvColor; + color?: HsvColor; onColorChange?: EventHandler; shape?: 'rounded' | 'square'; }; diff --git a/packages/react-components/react-color-picker-preview/library/src/components/AlphaSlider/useAlphaSliderState.ts b/packages/react-components/react-color-picker-preview/library/src/components/AlphaSlider/useAlphaSliderState.ts index c1654f5eef77c2..05a1feb20cd0dc 100644 --- a/packages/react-components/react-color-picker-preview/library/src/components/AlphaSlider/useAlphaSliderState.ts +++ b/packages/react-components/react-color-picker-preview/library/src/components/AlphaSlider/useAlphaSliderState.ts @@ -7,8 +7,8 @@ import type { AlphaSliderState, AlphaSliderProps } from './AlphaSlider.types'; import { useColorPickerContextValue_unstable } from '../../contexts/colorPicker'; import { MIN, MAX } from '../../utils/constants'; import { getPercent } from '../../utils/getPercent'; -import type { HsvColor } from '../../types/color'; import { adjustToTransparency, calculateTransparencyValue, getSliderDirection } from './alphaSliderUtils'; +import { createHsvColor } from '../../utils/createHsvColor'; export const useAlphaSliderState_unstable = (state: AlphaSliderState, props: AlphaSliderProps) => { 'use no memo'; @@ -33,7 +33,7 @@ export const useAlphaSliderState_unstable = (state: AlphaSliderState, props: Alp const _onChange: React.ChangeEventHandler = useEventCallback(event => { const newValue = adjustToTransparency(Number(event.target.value), transparency); - const newColor: HsvColor = { ...hsvColor, a: newValue / 100 }; + const newColor = createHsvColor({ ...hsvColor, a: newValue / 100 }); setCurrentValue(newValue); inputOnChange?.(event); onChange?.(event, { type: 'change', event, color: newColor }); diff --git a/packages/react-components/react-color-picker-preview/library/src/components/ColorPicker/ColorPicker.types.ts b/packages/react-components/react-color-picker-preview/library/src/components/ColorPicker/ColorPicker.types.ts index 1e76870ecd77ed..5c47504a7feca2 100644 --- a/packages/react-components/react-color-picker-preview/library/src/components/ColorPicker/ColorPicker.types.ts +++ b/packages/react-components/react-color-picker-preview/library/src/components/ColorPicker/ColorPicker.types.ts @@ -18,7 +18,7 @@ export type ColorPickerProps = Omit>, ' /** * Selected color. */ - color: HsvColor; + color?: HsvColor; /** * Callback for when the user changes the color. diff --git a/packages/react-components/react-color-picker-preview/library/src/components/ColorSlider/useColorSlider.ts b/packages/react-components/react-color-picker-preview/library/src/components/ColorSlider/useColorSlider.ts index 0d59f6c3529ba6..0a18e476f4b858 100644 --- a/packages/react-components/react-color-picker-preview/library/src/components/ColorSlider/useColorSlider.ts +++ b/packages/react-components/react-color-picker-preview/library/src/components/ColorSlider/useColorSlider.ts @@ -13,6 +13,7 @@ import type { ColorSliderProps, ColorSliderState } from './ColorSlider.types'; import { useColorPickerContextValue_unstable } from '../../contexts/colorPicker'; import { MIN, HUE_MAX as MAX } from '../../utils/constants'; import { getPercent } from '../../utils/getPercent'; +import { createHsvColor } from '../../utils/createHsvColor'; /** * Create the state required to render ColorSlider. @@ -65,7 +66,7 @@ export const useColorSlider_unstable = ( const _onChange: React.ChangeEventHandler = useEventCallback(event => { const newValue = Number(event.target.value); - const newColor = { ...hsvColor, h: newValue }; + const newColor = createHsvColor({ ...hsvColor, h: newValue }); setCurrentValue(newValue); inputOnChange?.(event); onChange?.(event, { type: 'change', event, color: newColor }); diff --git a/packages/react-components/react-color-picker-preview/library/src/contexts/colorPicker.ts b/packages/react-components/react-color-picker-preview/library/src/contexts/colorPicker.ts index 9175ff7c75693d..a64a140e21c845 100644 --- a/packages/react-components/react-color-picker-preview/library/src/contexts/colorPicker.ts +++ b/packages/react-components/react-color-picker-preview/library/src/contexts/colorPicker.ts @@ -3,13 +3,11 @@ import { createContext, useContextSelector } from '@fluentui/react-context-selec import type { ContextSelector, Context } from '@fluentui/react-context-selector'; import type { ColorPickerState, ColorPickerProps } from '../components/ColorPicker/ColorPicker.types'; import type { HsvColor } from '../types/color'; -import { INITIAL_COLOR_HSV } from '../utils/constants'; /** * The context through which individual color controls communicate with the picker. */ -export type ColorPickerContextValue = Pick & { - color: HsvColor; +export type ColorPickerContextValue = Pick & { /** * @internal * Callback used by Sliders to request a change on it's selected value @@ -35,7 +33,7 @@ export const colorPickerContextDefaultValue: ColorPickerContextValue = { requestChange: () => { /*noop*/ }, - color: { ...INITIAL_COLOR_HSV }, + color: undefined, shape: 'rounded', }; diff --git a/packages/react-components/react-color-picker-preview/library/src/utils/createHsvColor.ts b/packages/react-components/react-color-picker-preview/library/src/utils/createHsvColor.ts new file mode 100644 index 00000000000000..6c3d7601c7a083 --- /dev/null +++ b/packages/react-components/react-color-picker-preview/library/src/utils/createHsvColor.ts @@ -0,0 +1,5 @@ +import { HsvColor } from '../types/color'; + +export function createHsvColor({ h = 0, s = 0, v = 0, a = 1 }: Partial): HsvColor { + return { h, s, v, a }; +} From 1466381afda4e941e87afa3d1ff61200022e8fac Mon Sep 17 00:00:00 2001 From: ling1726 Date: Fri, 24 Jan 2025 15:29:09 +0100 Subject: [PATCH 09/13] feat: Add `subText` slot to enable multiline menu layout (#33704) --- .../Menu/MenuMultilineItems.stories.tsx | 372 ++++++++++++++++++ ...-d1fb9131-5d59-4c7d-a44c-4f27d980655c.json | 7 + .../react-menu/library/etc/react-menu.api.md | 9 +- .../src/components/MenuItem/MenuItem.test.tsx | 1 + .../src/components/MenuItem/MenuItem.types.ts | 5 + .../components/MenuItem/renderMenuItem.tsx | 7 +- .../src/components/MenuItem/useMenuItem.tsx | 49 ++- .../MenuItem/useMenuItemStyles.styles.ts | 45 ++- .../MenuItemCheckbox.test.tsx | 1 + .../renderMenuItemCheckbox.tsx | 7 +- .../useMenuItemCheckboxStyles.styles.ts | 5 + .../MenuItemRadio/MenuItemRadio.test.tsx | 1 + .../MenuItemRadio/renderMenuItemRadio.tsx | 7 +- .../useMenuItemRadioStyles.styles.ts | 5 + .../MenuItemSwitch/MenuItemSwitch.test.tsx | 1 + .../MenuItemSwitch/MenuItemSwitch.types.ts | 2 +- .../MenuItemSwitch/renderMenuItemSwitch.tsx | 7 +- .../useMenuItemSwitchStyles.styles.ts | 18 +- .../MenuSplitGroup/MenuSplitGroup.tsx | 3 +- .../MenuSplitGroup/MenuSplitGroup.types.ts | 8 +- .../MenuSplitGroup/renderMenuSplitGroup.tsx | 11 +- .../MenuSplitGroup/useMenuSplitGroup.ts | 39 +- .../useMenuSplitGroupContextValues.ts | 14 + .../useMenuSplitGroupStyles.styles.ts | 10 +- .../src/contexts/menuSplitGroupContext.ts | 25 ++ .../src/Menu/MenuMultilineItems.stories.tsx | 38 ++ .../stories/src/Menu/index.stories.tsx | 1 + 27 files changed, 674 insertions(+), 24 deletions(-) create mode 100644 apps/vr-tests-react-components/src/stories/Menu/MenuMultilineItems.stories.tsx create mode 100644 change/@fluentui-react-menu-d1fb9131-5d59-4c7d-a44c-4f27d980655c.json create mode 100644 packages/react-components/react-menu/library/src/components/MenuSplitGroup/useMenuSplitGroupContextValues.ts create mode 100644 packages/react-components/react-menu/library/src/contexts/menuSplitGroupContext.ts create mode 100644 packages/react-components/react-menu/stories/src/Menu/MenuMultilineItems.stories.tsx diff --git a/apps/vr-tests-react-components/src/stories/Menu/MenuMultilineItems.stories.tsx b/apps/vr-tests-react-components/src/stories/Menu/MenuMultilineItems.stories.tsx new file mode 100644 index 00000000000000..470efdec3b3858 --- /dev/null +++ b/apps/vr-tests-react-components/src/stories/Menu/MenuMultilineItems.stories.tsx @@ -0,0 +1,372 @@ +import * as React from 'react'; +import type { Meta } from '@storybook/react'; +import { Steps } from 'storywright'; +import { + Menu, + MenuTrigger, + MenuPopover, + MenuList, + MenuItem, + MenuGroupHeader, + MenuGroup, + MenuDivider, + MenuSplitGroup, + MenuItemSwitch, + MenuItemCheckbox, +} from '@fluentui/react-menu'; +import { EditFilled, EditRegular, bundleIcon } from '@fluentui/react-icons'; +import { getStoryVariant, RTL, withStoryWrightSteps } from '../../utilities'; + +export default { + title: 'Menu Multiline items', + + decorators: [ + story => + withStoryWrightSteps({ story, steps: new Steps().hover('[role="menuitem"]').snapshot('hover menuitem').end() }), + ], +} satisfies Meta; + +const EditIcon = bundleIcon(EditFilled, EditRegular); + +const TextOnly = () => ( + + Text only + Copy + Copy + +); + +const TextWithIcon = () => ( + + Text with Icon + }>Copy + }> + Copy + + +); + +const TextOnlySubmenu = () => ( + + Text only submenu + + + Open + + + + Open in browser + Open in desktop + + + + + + Open + + + + Open in browser + Open in desktop + + + + +); + +const IconAndSubmenu = () => ( + + Icon and submenu + + + }>Open + + + + Open in browser + Open in desktop + + + + + + }> + Open + + + + + Open in browser + Open in desktop + + + + +); + +const IconAndSecondary = () => ( + + Icon and secondary + } secondaryContent="Ctrl+C"> + Copy + + } subText="Copy text" secondaryContent="Ctrl+C"> + Copy + + +); + +const SplitWithEverything = () => ( + + Split with everything + + + } secondaryContent="Ctrl+N"> + New folder + + + + + + + + New folder + New folder + New folder + + + + + + } subText="Creates a new folder" secondaryContent="Ctrl+N"> + New folder + + + + + + + + New folder + New folder + New folder + + + + +); + +const SplitWithSecondary = () => ( + + Split with secondary + + + New folder + + + + + + + New folder + New folder + New folder + + + + + + + New folder + + + + + + + + New folder + New folder + New folder + + + + +); + +const SplitTextOnly = () => ( + + Split text only + + + New folder + + + + + + + New folder + New folder + New folder + + + + + + New folder + + + + + + + New folder + New folder + New folder + + + + +); + +const SelectableTextOnly = () => ( + + Selectable text only + + Select this thing + + + Select this thing + + +); + +const SelectableWithIcon = () => ( + + Selectable with Icon + }> + Select this thing + + }> + Select this thing + + +); + +const SelectableWithIconAndSecondary = () => ( + + Selectable with icon and secondary + } value="foo" name="bac" secondaryContent="Ctrl+Spacebar"> + Select this thing + + } value="foo" name="bac" subText="Selection" secondaryContent="Ctrl+Spacebar"> + Select this thing + + +); + +const SelectableWithSecondary = () => ( + + Selectable with secondary + + Select this thing + + + Select this thing + + +); + +const SwitchTextOnly = () => ( + + SwitchTextOnly + + Select this thing + + + Select this thing + + +); + +const SwitchWithIcon = () => ( + + SwitchTextOnly + } value="foo" name="switch1"> + Select this thing + + } value="foo" name="switch1" subText="Selection"> + Select this thing + + +); + +const SwitchWithIconAndSecondary = () => ( + + SwitchTextOnly + } value="foo" name="switch2" secondaryContent="Ctrl+Spacebar"> + Select this thing + + } value="foo" name="switch2" subText="Selection" secondaryContent="Ctrl+Spacebar"> + Select this thing + + +); + +export const Default = () => { + return ( +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ ); +}; + +Default.storyName = 'default'; + +export const DefaultRTL = getStoryVariant(Default, RTL); diff --git a/change/@fluentui-react-menu-d1fb9131-5d59-4c7d-a44c-4f27d980655c.json b/change/@fluentui-react-menu-d1fb9131-5d59-4c7d-a44c-4f27d980655c.json new file mode 100644 index 00000000000000..55faeb77fa50d9 --- /dev/null +++ b/change/@fluentui-react-menu-d1fb9131-5d59-4c7d-a44c-4f27d980655c.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "feat: Add `subText` slot to enable multiline menu layout", + "packageName": "@fluentui/react-menu", + "email": "lingfangao@hotmail.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-menu/library/etc/react-menu.api.md b/packages/react-components/react-menu/library/etc/react-menu.api.md index 10ce069c886e84..c6b8c4d7e27593 100644 --- a/packages/react-components/react-menu/library/etc/react-menu.api.md +++ b/packages/react-components/react-menu/library/etc/react-menu.api.md @@ -19,7 +19,7 @@ import { PositioningVirtualElement } from '@fluentui/react-positioning'; import * as React_2 from 'react'; import { SetVirtualMouseTarget } from '@fluentui/react-positioning'; import type { Slot } from '@fluentui/react-utilities'; -import type { SlotClassNames } from '@fluentui/react-utilities'; +import { SlotClassNames } from '@fluentui/react-utilities'; import type { TriggerProps } from '@fluentui/react-utilities'; import type { UseOnClickOrScrollOutsideOptions } from '@fluentui/react-utilities'; @@ -195,6 +195,7 @@ export type MenuItemSlots = { submenuIndicator?: Slot<'span'>; content?: Slot<'span'>; secondaryContent?: Slot<'span'>; + subText?: Slot<'span'>; }; // @public (undocumented) @@ -210,7 +211,7 @@ export const menuItemSwitchClassNames: SlotClassNames; export type MenuItemSwitchProps = ComponentProps & Pick; // @public (undocumented) -export type MenuItemSwitchSlots = Pick & { +export type MenuItemSwitchSlots = Pick & { switchIndicator?: Slot<'span'>; }; @@ -365,7 +366,7 @@ export type MenuSplitGroupSlots = { }; // @public -export type MenuSplitGroupState = ComponentState; +export type MenuSplitGroupState = ComponentState & Pick; // @public (undocumented) export type MenuState = ComponentState & Required> & { @@ -445,7 +446,7 @@ export const renderMenuList_unstable: (state: MenuListState, contextValues: Menu export const renderMenuPopover_unstable: (state: MenuPopoverState) => JSX.Element; // @public -export const renderMenuSplitGroup_unstable: (state: MenuSplitGroupState) => JSX.Element; +export const renderMenuSplitGroup_unstable: (state: MenuSplitGroupState, contexts?: MenuSplitGroupContextValues) => JSX.Element; // @public export const renderMenuTrigger_unstable: (state: MenuTriggerState) => JSX.Element; diff --git a/packages/react-components/react-menu/library/src/components/MenuItem/MenuItem.test.tsx b/packages/react-components/react-menu/library/src/components/MenuItem/MenuItem.test.tsx index c5d7ace4ef6678..6095e5869210f5 100644 --- a/packages/react-components/react-menu/library/src/components/MenuItem/MenuItem.test.tsx +++ b/packages/react-components/react-menu/library/src/components/MenuItem/MenuItem.test.tsx @@ -24,6 +24,7 @@ describe('MenuItem', () => { submenuIndicator: 'Test Submenu Indicator', content: 'Test Content', secondaryContent: 'Test Secondary Content', + subText: 'Sub text', }, }, ], diff --git a/packages/react-components/react-menu/library/src/components/MenuItem/MenuItem.types.ts b/packages/react-components/react-menu/library/src/components/MenuItem/MenuItem.types.ts index 91b79e12ab3fb0..f8e0576690f440 100644 --- a/packages/react-components/react-menu/library/src/components/MenuItem/MenuItem.types.ts +++ b/packages/react-components/react-menu/library/src/components/MenuItem/MenuItem.types.ts @@ -29,6 +29,11 @@ export type MenuItemSlots = { * Secondary content rendered opposite the primary content (e.g Shortcut text) */ secondaryContent?: Slot<'span'>; + + /** + * Additional descriptor to main content that creates a multiline layout + */ + subText?: Slot<'span'>; }; export type MenuItemProps = Omit>, 'content'> & diff --git a/packages/react-components/react-menu/library/src/components/MenuItem/renderMenuItem.tsx b/packages/react-components/react-menu/library/src/components/MenuItem/renderMenuItem.tsx index b6c4e6359c6ae5..e0f0908197c705 100644 --- a/packages/react-components/react-menu/library/src/components/MenuItem/renderMenuItem.tsx +++ b/packages/react-components/react-menu/library/src/components/MenuItem/renderMenuItem.tsx @@ -13,7 +13,12 @@ export const renderMenuItem_unstable = (state: MenuItemState) => { {state.checkmark && } {state.icon && } - {state.content && } + {state.content && ( + + {state.content.children} + {state.subText && } + + )} {state.secondaryContent && } {state.submenuIndicator && } diff --git a/packages/react-components/react-menu/library/src/components/MenuItem/useMenuItem.tsx b/packages/react-components/react-menu/library/src/components/MenuItem/useMenuItem.tsx index 7794817ba8e39b..8140489b99816d 100644 --- a/packages/react-components/react-menu/library/src/components/MenuItem/useMenuItem.tsx +++ b/packages/react-components/react-menu/library/src/components/MenuItem/useMenuItem.tsx @@ -1,5 +1,11 @@ import * as React from 'react'; -import { useEventCallback, useMergedRefs, getIntrinsicElementProps, slot } from '@fluentui/react-utilities'; +import { + useEventCallback, + useMergedRefs, + getIntrinsicElementProps, + slot, + useIsomorphicLayoutEffect, +} from '@fluentui/react-utilities'; import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts'; import { useCharacterSearch } from './useCharacterSearch'; import { useMenuTriggerContext_unstable } from '../../contexts/menuTriggerContext'; @@ -20,6 +26,7 @@ import { useARIAButtonProps, } from '@fluentui/react-aria'; import { Enter, Space } from '@fluentui/keyboard-keys'; +import { useIsInMenuSplitGroup, useMenuSplitGroupContext_unstable } from '../../contexts/menuSplitGroupContext'; const ChevronRightIcon = bundleIcon(ChevronRightFilled, ChevronRightRegular); const ChevronLeftIcon = bundleIcon(ChevronLeftFilled, ChevronLeftRegular); @@ -31,9 +38,9 @@ export const useMenuItem_unstable = (props: MenuItemProps, ref: React.Ref context.persistOnItemClick); const { as = 'div', disabled = false, hasSubmenu = isSubmenuTrigger, persistOnClick = persistOnClickContext } = props; - const hasIcons = useMenuListContext_unstable(context => context.hasIcons); - const hasCheckmarks = useMenuListContext_unstable(context => context.hasCheckmarks); + const { hasIcons, hasCheckmarks } = useIconAndCheckmarkAlignment({ hasSubmenu }); const setOpen = useMenuContext_unstable(context => context.setOpen); + useNotifySplitItemMultiline({ multiline: !!props.subText, hasSubmenu }); const { dir } = useFluent(); const innerRef = React.useRef>(null); @@ -50,6 +57,7 @@ export const useMenuItem_unstable = (props: MenuItemProps, ref: React.Ref { + const { hasSubmenu, multiline } = options; + const isSplitItemTrigger = useIsInMenuSplitGroup() && hasSubmenu; + + const { setMultiline } = useMenuSplitGroupContext_unstable(); + + useIsomorphicLayoutEffect(() => { + if (!isSplitItemTrigger) { + setMultiline(multiline); + } + }, [setMultiline, multiline, isSplitItemTrigger]); +}; + +const useIconAndCheckmarkAlignment = (options: { hasSubmenu: boolean }) => { + const { hasSubmenu } = options; + const hasIcons = useMenuListContext_unstable(context => context.hasIcons); + const hasCheckmarks = useMenuListContext_unstable(context => context.hasCheckmarks); + const isSplitItemTrigger = useIsInMenuSplitGroup() && hasSubmenu; + + return { + hasIcons: hasIcons && !isSplitItemTrigger, + hasCheckmarks: hasCheckmarks && !isSplitItemTrigger, + }; +}; diff --git a/packages/react-components/react-menu/library/src/components/MenuItem/useMenuItemStyles.styles.ts b/packages/react-components/react-menu/library/src/components/MenuItem/useMenuItemStyles.styles.ts index 66310cecf70d91..fca9ed9dd16d43 100644 --- a/packages/react-components/react-menu/library/src/components/MenuItem/useMenuItemStyles.styles.ts +++ b/packages/react-components/react-menu/library/src/components/MenuItem/useMenuItemStyles.styles.ts @@ -14,6 +14,7 @@ export const menuItemClassNames: SlotClassNames = { submenuIndicator: 'fui-MenuItem__submenuIndicator', content: 'fui-MenuItem__content', secondaryContent: 'fui-MenuItem__secondaryContent', + subText: 'fui-MenuItem__subText', }; const useRootBaseStyles = makeResetStyles({ @@ -48,11 +49,19 @@ const useRootBaseStyles = makeResetStyles({ [`& .${menuItemClassNames.icon}`]: { color: tokens.colorNeutralForeground2BrandSelected, }, + + [`& .${menuItemClassNames.subText}`]: { + color: tokens.colorNeutralForeground3Hover, + }, }, ':hover:active': { backgroundColor: tokens.colorNeutralBackground1Pressed, color: tokens.colorNeutralForeground2Pressed, + + [`& .${menuItemClassNames.subText}`]: { + color: tokens.colorNeutralForeground3Pressed, + }, }, // High contrast styles @@ -111,6 +120,11 @@ const useSubmenuIndicatorBaseStyles = makeResetStyles({ justifyContent: 'center', }); +const useSubtextBaseStyles = makeResetStyles({ + ...typographyStyles.caption2, + color: tokens.colorNeutralForeground3, +}); + const useStyles = makeStyles({ checkmark: { marginTop: '2px', @@ -175,6 +189,21 @@ const useStyles = makeStyles({ }, }); +const useMultilineStyles = makeStyles({ + content: { + display: 'flex', + flexDirection: 'column', + }, + + secondaryContent: { + alignSelf: 'center', + }, + + submenuIndicator: { + alignSelf: 'center', + }, +}); + /** Applies style classnames to slots */ export const useMenuItemStyles_unstable = (state: MenuItemState): MenuItemState => { 'use no memo'; @@ -185,6 +214,9 @@ export const useMenuItemStyles_unstable = (state: MenuItemState): MenuItemState const secondaryContentBaseStyles = useSecondaryContentBaseStyles(); const iconBaseStyles = useIconBaseStyles(); const submenuIndicatorBaseStyles = useSubmenuIndicatorBaseStyles(); + const multilineStyles = useMultilineStyles(); + const subtextBaseStyles = useSubtextBaseStyles(); + const multiline = !!state.subText; state.root.className = mergeClasses( menuItemClassNames.root, rootBaseStyles, @@ -193,7 +225,12 @@ export const useMenuItemStyles_unstable = (state: MenuItemState): MenuItemState ); if (state.content) { - state.content.className = mergeClasses(menuItemClassNames.content, contentBaseStyles, state.content.className); + state.content.className = mergeClasses( + menuItemClassNames.content, + contentBaseStyles, + state.content.className, + multiline && multilineStyles.content, + ); } if (state.checkmark) { @@ -205,6 +242,7 @@ export const useMenuItemStyles_unstable = (state: MenuItemState): MenuItemState menuItemClassNames.secondaryContent, !state.disabled && secondaryContentBaseStyles, state.secondaryContent.className, + multiline && multilineStyles.secondaryContent, ); } @@ -217,9 +255,14 @@ export const useMenuItemStyles_unstable = (state: MenuItemState): MenuItemState menuItemClassNames.submenuIndicator, submenuIndicatorBaseStyles, state.submenuIndicator.className, + multiline && multilineStyles.submenuIndicator, ); } + if (state.subText) { + state.subText.className = mergeClasses(menuItemClassNames.subText, state.subText.className, subtextBaseStyles); + } + useCheckmarkStyles_unstable(state as MenuItemCheckboxState); return state; diff --git a/packages/react-components/react-menu/library/src/components/MenuItemCheckbox/MenuItemCheckbox.test.tsx b/packages/react-components/react-menu/library/src/components/MenuItemCheckbox/MenuItemCheckbox.test.tsx index e8f8dd8be52edb..6b5e35df4d6b84 100644 --- a/packages/react-components/react-menu/library/src/components/MenuItemCheckbox/MenuItemCheckbox.test.tsx +++ b/packages/react-components/react-menu/library/src/components/MenuItemCheckbox/MenuItemCheckbox.test.tsx @@ -28,6 +28,7 @@ describe('MenuItemCheckbox conformance', () => { submenuIndicator: 'Test Submenu Indicator', content: 'Test Content', secondaryContent: 'Test Secondary Content', + subText: 'Sub text', }, }, ], diff --git a/packages/react-components/react-menu/library/src/components/MenuItemCheckbox/renderMenuItemCheckbox.tsx b/packages/react-components/react-menu/library/src/components/MenuItemCheckbox/renderMenuItemCheckbox.tsx index c39aee33ae400f..8b91d8d4315a29 100644 --- a/packages/react-components/react-menu/library/src/components/MenuItemCheckbox/renderMenuItemCheckbox.tsx +++ b/packages/react-components/react-menu/library/src/components/MenuItemCheckbox/renderMenuItemCheckbox.tsx @@ -12,7 +12,12 @@ export const renderMenuItemCheckbox_unstable = (state: MenuItemCheckboxState) => {state.checkmark && } {state.icon && } - {state.content && } + {state.content && ( + + {state.content.children} + {state.subText && } + + )} {state.secondaryContent && } ); diff --git a/packages/react-components/react-menu/library/src/components/MenuItemCheckbox/useMenuItemCheckboxStyles.styles.ts b/packages/react-components/react-menu/library/src/components/MenuItemCheckbox/useMenuItemCheckboxStyles.styles.ts index 236db2527d5fac..f0394b5703eaea 100644 --- a/packages/react-components/react-menu/library/src/components/MenuItemCheckbox/useMenuItemCheckboxStyles.styles.ts +++ b/packages/react-components/react-menu/library/src/components/MenuItemCheckbox/useMenuItemCheckboxStyles.styles.ts @@ -11,6 +11,7 @@ export const menuItemCheckboxClassNames: SlotClassNames { @@ -37,6 +38,10 @@ export const useMenuItemCheckboxStyles_unstable = (state: MenuItemCheckboxState) state.checkmark.className = mergeClasses(menuItemCheckboxClassNames.checkmark, state.checkmark.className); } + if (state.subText) { + state.subText.className = mergeClasses(menuItemCheckboxClassNames.subText, state.subText.className); + } + useMenuItemStyles_unstable(state); useCheckmarkStyles_unstable(state); diff --git a/packages/react-components/react-menu/library/src/components/MenuItemRadio/MenuItemRadio.test.tsx b/packages/react-components/react-menu/library/src/components/MenuItemRadio/MenuItemRadio.test.tsx index 6f506aa5e487bc..4add33e4c367f7 100644 --- a/packages/react-components/react-menu/library/src/components/MenuItemRadio/MenuItemRadio.test.tsx +++ b/packages/react-components/react-menu/library/src/components/MenuItemRadio/MenuItemRadio.test.tsx @@ -25,6 +25,7 @@ describe('MenuItemRadio', () => { submenuIndicator: 'Test Submenu Indicator', content: 'Test Content', secondaryContent: 'Test Secondary Content', + subText: 'Sub text', }, }, ], diff --git a/packages/react-components/react-menu/library/src/components/MenuItemRadio/renderMenuItemRadio.tsx b/packages/react-components/react-menu/library/src/components/MenuItemRadio/renderMenuItemRadio.tsx index a37aad6382b02c..bfb123c4f30d69 100644 --- a/packages/react-components/react-menu/library/src/components/MenuItemRadio/renderMenuItemRadio.tsx +++ b/packages/react-components/react-menu/library/src/components/MenuItemRadio/renderMenuItemRadio.tsx @@ -15,7 +15,12 @@ export const renderMenuItemRadio_unstable = (state: MenuItemRadioState) => { {state.checkmark && } {state.icon && } - {state.content && } + {state.content && ( + + {state.content.children} + {state.subText && } + + )} {state.secondaryContent && } ); diff --git a/packages/react-components/react-menu/library/src/components/MenuItemRadio/useMenuItemRadioStyles.styles.ts b/packages/react-components/react-menu/library/src/components/MenuItemRadio/useMenuItemRadioStyles.styles.ts index 95ba0df44f2424..e6e867ea697ff7 100644 --- a/packages/react-components/react-menu/library/src/components/MenuItemRadio/useMenuItemRadioStyles.styles.ts +++ b/packages/react-components/react-menu/library/src/components/MenuItemRadio/useMenuItemRadioStyles.styles.ts @@ -11,6 +11,7 @@ export const menuItemRadioClassNames: SlotClassNames { @@ -37,6 +38,10 @@ export const useMenuItemRadioStyles_unstable = (state: MenuItemRadioState) => { state.checkmark.className = mergeClasses(menuItemRadioClassNames.checkmark, state.checkmark.className); } + if (state.subText) { + state.subText.className = mergeClasses(menuItemRadioClassNames.subText, state.subText.className); + } + useMenuItemStyles_unstable(state); useCheckmarkStyles_unstable(state); }; diff --git a/packages/react-components/react-menu/library/src/components/MenuItemSwitch/MenuItemSwitch.test.tsx b/packages/react-components/react-menu/library/src/components/MenuItemSwitch/MenuItemSwitch.test.tsx index 875b1247358464..9e9e462737b084 100644 --- a/packages/react-components/react-menu/library/src/components/MenuItemSwitch/MenuItemSwitch.test.tsx +++ b/packages/react-components/react-menu/library/src/components/MenuItemSwitch/MenuItemSwitch.test.tsx @@ -24,6 +24,7 @@ describe('MenuItemSwitch', () => { icon: 'Test Icon', content: 'Test Content', secondaryContent: 'Test Secondary Content', + subText: 'Sub text', }, }, ], diff --git a/packages/react-components/react-menu/library/src/components/MenuItemSwitch/MenuItemSwitch.types.ts b/packages/react-components/react-menu/library/src/components/MenuItemSwitch/MenuItemSwitch.types.ts index 85db09500b195b..499871031020fa 100644 --- a/packages/react-components/react-menu/library/src/components/MenuItemSwitch/MenuItemSwitch.types.ts +++ b/packages/react-components/react-menu/library/src/components/MenuItemSwitch/MenuItemSwitch.types.ts @@ -3,7 +3,7 @@ import { MenuItemSlots } from '../MenuItem/MenuItem.types'; import { MenuItemSelectableState } from '../../selectable/types'; import { MenuItemCheckboxProps } from '../MenuItemCheckbox/MenuItemCheckbox.types'; -export type MenuItemSwitchSlots = Pick & { +export type MenuItemSwitchSlots = Pick & { switchIndicator?: Slot<'span'>; }; diff --git a/packages/react-components/react-menu/library/src/components/MenuItemSwitch/renderMenuItemSwitch.tsx b/packages/react-components/react-menu/library/src/components/MenuItemSwitch/renderMenuItemSwitch.tsx index 2d28128030ffd6..a86b0f5262f9f4 100644 --- a/packages/react-components/react-menu/library/src/components/MenuItemSwitch/renderMenuItemSwitch.tsx +++ b/packages/react-components/react-menu/library/src/components/MenuItemSwitch/renderMenuItemSwitch.tsx @@ -12,7 +12,12 @@ export const renderMenuItemSwitch_unstable = (state: MenuItemSwitchState) => { return ( {state.icon && } - {state.content && } + {state.content && ( + + {state.content.children} + {state.subText && } + + )} {state.secondaryContent && } {state.switchIndicator && } diff --git a/packages/react-components/react-menu/library/src/components/MenuItemSwitch/useMenuItemSwitchStyles.styles.ts b/packages/react-components/react-menu/library/src/components/MenuItemSwitch/useMenuItemSwitchStyles.styles.ts index 5cd02f289895f7..eca6a62d4704d6 100644 --- a/packages/react-components/react-menu/library/src/components/MenuItemSwitch/useMenuItemSwitchStyles.styles.ts +++ b/packages/react-components/react-menu/library/src/components/MenuItemSwitch/useMenuItemSwitchStyles.styles.ts @@ -1,6 +1,6 @@ import { makeStyles, makeResetStyles, mergeClasses, shorthands } from '@griffel/react'; import { tokens } from '@fluentui/react-theme'; -import type { SlotClassNames } from '@fluentui/react-utilities'; +import { type SlotClassNames } from '@fluentui/react-utilities'; import type { MenuItemSwitchSlots, MenuItemSwitchState } from './MenuItemSwitch.types'; import { useMenuItemStyles_unstable } from '../MenuItem/useMenuItemStyles.styles'; @@ -10,6 +10,7 @@ export const menuItemSwitchClassNames: SlotClassNames = { content: 'fui-MenuItemSwitch__content', secondaryContent: 'fui-MenuItemSwitch__secondaryContent', switchIndicator: 'fui-MenuItemSwitch__switchIndicator', + subText: 'fui-MenuItemSwitch__subText', }; export const circleFilledClassName = 'fui-MenuItemSwitch__switchIndicator__circleFilled'; @@ -84,15 +85,23 @@ const useSwitchIndicatorStyles = makeStyles({ }, }); +const useMultilineStyles = makeStyles({ + switch: { + alignSelf: 'center', + }, +}); + /** * Apply styling to the MenuItemSwitch slots based on the state */ export const useMenuItemSwitchStyles_unstable = (state: MenuItemSwitchState): MenuItemSwitchState => { 'use no memo'; - const { checked } = state; + const { checked, subText } = state; + const multiline = !!subText; const switchIndicatorStyles = useSwitchIndicatorStyles(); const switchIndicatorBaseStyles = useSwitchIndicatorBaseClassName(); + const multilineStyles = useMultilineStyles(); state.root.className = mergeClasses(menuItemSwitchClassNames.root, state.root.className); if (state.content) { state.content.className = mergeClasses(menuItemSwitchClassNames.content, state.content.className); @@ -109,12 +118,17 @@ export const useMenuItemSwitchStyles_unstable = (state: MenuItemSwitchState): Me state.icon.className = mergeClasses(menuItemSwitchClassNames.icon, state.icon.className); } + if (state.subText) { + state.subText.className = mergeClasses(menuItemSwitchClassNames.subText, state.subText.className); + } + if (state.switchIndicator) { state.switchIndicator.className = mergeClasses( menuItemSwitchClassNames.switchIndicator, switchIndicatorBaseStyles, checked && switchIndicatorStyles.checked, state.switchIndicator.className, + multiline && multilineStyles.switch, ); } diff --git a/packages/react-components/react-menu/library/src/components/MenuSplitGroup/MenuSplitGroup.tsx b/packages/react-components/react-menu/library/src/components/MenuSplitGroup/MenuSplitGroup.tsx index fc090d1da217e2..3268052d24cfa3 100644 --- a/packages/react-components/react-menu/library/src/components/MenuSplitGroup/MenuSplitGroup.tsx +++ b/packages/react-components/react-menu/library/src/components/MenuSplitGroup/MenuSplitGroup.tsx @@ -5,6 +5,7 @@ import { useMenuSplitGroupStyles_unstable } from './useMenuSplitGroupStyles.styl import type { MenuSplitGroupProps } from './MenuSplitGroup.types'; import type { ForwardRefComponent } from '@fluentui/react-utilities'; import { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts'; +import { useMenuSplitGroupContextValues } from './useMenuSplitGroupContextValues'; /** * Layout wrapper that provides extra keyboard navigation behavior for two `MenuItem` components. @@ -16,7 +17,7 @@ export const MenuSplitGroup: ForwardRefComponent = React.fo useCustomStyleHook_unstable('useMenuSplitGroupStyles_unstable')(state); - return renderMenuSplitGroup_unstable(state); + return renderMenuSplitGroup_unstable(state, useMenuSplitGroupContextValues(state)); }); MenuSplitGroup.displayName = 'MenuSplitGroup'; diff --git a/packages/react-components/react-menu/library/src/components/MenuSplitGroup/MenuSplitGroup.types.ts b/packages/react-components/react-menu/library/src/components/MenuSplitGroup/MenuSplitGroup.types.ts index acbe3bf2f7d255..0dbb0f0f9b5aa9 100644 --- a/packages/react-components/react-menu/library/src/components/MenuSplitGroup/MenuSplitGroup.types.ts +++ b/packages/react-components/react-menu/library/src/components/MenuSplitGroup/MenuSplitGroup.types.ts @@ -1,9 +1,14 @@ import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities'; +import { MenuSplitGroupContextValue } from '../../contexts/menuSplitGroupContext'; export type MenuSplitGroupSlots = { root: Slot<'div'>; }; +export type MenuSplitGroupContextValues = { + menuSplitGroup: MenuSplitGroupContextValue; +}; + /** * MenuSplitGroup Props */ @@ -12,4 +17,5 @@ export type MenuSplitGroupProps = ComponentProps; /** * State used in rendering MenuSplitGroup */ -export type MenuSplitGroupState = ComponentState; +export type MenuSplitGroupState = ComponentState & + Pick; diff --git a/packages/react-components/react-menu/library/src/components/MenuSplitGroup/renderMenuSplitGroup.tsx b/packages/react-components/react-menu/library/src/components/MenuSplitGroup/renderMenuSplitGroup.tsx index 374157be917ef2..c8292f992d19c1 100644 --- a/packages/react-components/react-menu/library/src/components/MenuSplitGroup/renderMenuSplitGroup.tsx +++ b/packages/react-components/react-menu/library/src/components/MenuSplitGroup/renderMenuSplitGroup.tsx @@ -1,13 +1,18 @@ /** @jsxRuntime automatic */ /** @jsxImportSource @fluentui/react-jsx-runtime */ import { assertSlots } from '@fluentui/react-utilities'; -import type { MenuSplitGroupState, MenuSplitGroupSlots } from './MenuSplitGroup.types'; +import type { MenuSplitGroupState, MenuSplitGroupSlots, MenuSplitGroupContextValues } from './MenuSplitGroup.types'; +import { menuSplitGroupContextDefaultValue, MenuSplitGroupContextProvider } from '../../contexts/menuSplitGroupContext'; /** * Render the final JSX of MenuSplitGroup */ -export const renderMenuSplitGroup_unstable = (state: MenuSplitGroupState) => { +export const renderMenuSplitGroup_unstable = (state: MenuSplitGroupState, contexts?: MenuSplitGroupContextValues) => { assertSlots(state); - return ; + return ( + + + + ); }; diff --git a/packages/react-components/react-menu/library/src/components/MenuSplitGroup/useMenuSplitGroup.ts b/packages/react-components/react-menu/library/src/components/MenuSplitGroup/useMenuSplitGroup.ts index 8605590d3b2b0a..cace8e456a8d7a 100644 --- a/packages/react-components/react-menu/library/src/components/MenuSplitGroup/useMenuSplitGroup.ts +++ b/packages/react-components/react-menu/library/src/components/MenuSplitGroup/useMenuSplitGroup.ts @@ -4,6 +4,7 @@ import { useFocusFinders } from '@fluentui/react-tabster'; import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts'; import type { MenuSplitGroupProps, MenuSplitGroupState } from './MenuSplitGroup.types'; import { ArrowRight, ArrowLeft } from '@fluentui/keyboard-keys'; +import { menuSplitGroupMultilineAttr } from './useMenuSplitGroupStyles.styles'; /** * Create the state required to render MenuSplitGroup. @@ -18,13 +19,14 @@ export const useMenuSplitGroup_unstable = ( props: MenuSplitGroupProps, ref: React.Ref, ): MenuSplitGroupState => { - const innerRef = React.useRef(); + const innerRef = React.useRef(); const { dir, targetDocument } = useFluent(); const nextArrowKey = getRTLSafeKey(ArrowRight, dir); const prevArrowKey = getRTLSafeKey(ArrowLeft, dir); const { findNextFocusable, findPrevFocusable } = useFocusFinders(); + const { multilineRef, setMultiline } = useHandleMultilineMenuItem(); const onKeyDown = React.useCallback( (e: React.KeyboardEvent) => { @@ -54,13 +56,14 @@ export const useMenuSplitGroup_unstable = ( components: { root: 'div', }, + setMultiline, root: slot.always( getIntrinsicElementProps('div', { role: 'group', // FIXME: // `ref` is wrongly assigned to be `HTMLElement` instead of `HTMLDivElement` // but since it would be a breaking change to fix it, we are casting ref to it's proper type - ref: useMergedRefs(ref, innerRef) as React.Ref, + ref: useMergedRefs(ref, innerRef, multilineRef) as React.Ref, onKeyDown, ...props, }), @@ -68,3 +71,35 @@ export const useMenuSplitGroup_unstable = ( ), }; }; + +/** + * Creates a callback that lets a multiline menu item child set an attribute on this component + * Children can mount before parents so we need to store the value and apply it when the parent is mounted + */ +const useHandleMultilineMenuItem = () => { + const [handle] = React.useState(() => { + let isMultiline = false; + let multilineNode: HTMLElement | null = null; + + function applyAttr() { + multilineNode?.toggleAttribute(menuSplitGroupMultilineAttr, isMultiline); + } + + return { + multilineRef: (node: HTMLDivElement | null) => { + if (node) { + multilineNode = node; + applyAttr(); + } else { + multilineNode = null; + } + }, + setMultiline: (value: boolean) => { + isMultiline = value; + applyAttr(); + }, + }; + }); + + return handle; +}; diff --git a/packages/react-components/react-menu/library/src/components/MenuSplitGroup/useMenuSplitGroupContextValues.ts b/packages/react-components/react-menu/library/src/components/MenuSplitGroup/useMenuSplitGroupContextValues.ts new file mode 100644 index 00000000000000..f100fc6b1ebeba --- /dev/null +++ b/packages/react-components/react-menu/library/src/components/MenuSplitGroup/useMenuSplitGroupContextValues.ts @@ -0,0 +1,14 @@ +import * as React from 'react'; +import { MenuSplitGroupContextValues, MenuSplitGroupState } from './MenuSplitGroup.types'; + +export const useMenuSplitGroupContextValues = (state: MenuSplitGroupState): MenuSplitGroupContextValues => { + 'use no memo'; + + return React.useMemo(() => { + return { + menuSplitGroup: { + setMultiline: state.setMultiline, + }, + }; + }, [state.setMultiline]); +}; diff --git a/packages/react-components/react-menu/library/src/components/MenuSplitGroup/useMenuSplitGroupStyles.styles.ts b/packages/react-components/react-menu/library/src/components/MenuSplitGroup/useMenuSplitGroupStyles.styles.ts index 9c0fb2435e9b41..e67ff778ad4450 100644 --- a/packages/react-components/react-menu/library/src/components/MenuSplitGroup/useMenuSplitGroupStyles.styles.ts +++ b/packages/react-components/react-menu/library/src/components/MenuSplitGroup/useMenuSplitGroupStyles.styles.ts @@ -4,17 +4,25 @@ import { menuItemClassNames } from '../MenuItem/useMenuItemStyles.styles'; import type { MenuSplitGroupSlots, MenuSplitGroupState } from './MenuSplitGroup.types'; import type { SlotClassNames } from '@fluentui/react-utilities'; +export const menuSplitGroupMultilineAttr = 'data-multiline'; + export const menuSplitGroupClassNames: SlotClassNames = { root: 'fui-MenuSplitGroup', }; /** * Styles for the root slot + * TODO - remove the use of nested combinators to style child menu items */ const useStyles = makeStyles({ root: { + [`[${menuSplitGroupMultilineAttr}]`]: { + [`& > .${menuItemClassNames.root}:nth-of-type(2)`]: { + alignSelf: 'center', + }, + }, display: 'flex', [`& > .${menuItemClassNames.root}:nth-of-type(1)`]: { - flexGrow: 1, + flex: 1, }, [`& > .${menuItemClassNames.root}:nth-of-type(2)`]: { borderTopLeftRadius: 0, diff --git a/packages/react-components/react-menu/library/src/contexts/menuSplitGroupContext.ts b/packages/react-components/react-menu/library/src/contexts/menuSplitGroupContext.ts new file mode 100644 index 00000000000000..74c894a50a71d3 --- /dev/null +++ b/packages/react-components/react-menu/library/src/contexts/menuSplitGroupContext.ts @@ -0,0 +1,25 @@ +import * as React from 'react'; + +export type MenuSplitGroupContextValue = { + setMultiline: (multiline: boolean) => void; +}; + +/** + * Context used communicate with a child menu item that it is a trigger for a submenu + */ +const MenuSplitGroupContext = React.createContext( + undefined, +) as React.Context; + +export const menuSplitGroupContextDefaultValue = { + setMultiline: () => null, +}; + +export const MenuSplitGroupContextProvider = MenuSplitGroupContext.Provider; +export const useMenuSplitGroupContext_unstable = () => + React.useContext(MenuSplitGroupContext) ?? menuSplitGroupContextDefaultValue; + +export const useIsInMenuSplitGroup = () => { + const context = useMenuSplitGroupContext_unstable(); + return context !== menuSplitGroupContextDefaultValue; +}; diff --git a/packages/react-components/react-menu/stories/src/Menu/MenuMultilineItems.stories.tsx b/packages/react-components/react-menu/stories/src/Menu/MenuMultilineItems.stories.tsx new file mode 100644 index 00000000000000..89bd0fad8b62be --- /dev/null +++ b/packages/react-components/react-menu/stories/src/Menu/MenuMultilineItems.stories.tsx @@ -0,0 +1,38 @@ +import * as React from 'react'; +import { MenuList, MenuItem, MenuPopover, MenuTrigger, Menu, Button } from '@fluentui/react-components'; +import { + EditRegular, + EditFilled, + bundleIcon, + CutRegular, + CutFilled, + ClipboardPasteRegular, + ClipboardPasteFilled, +} from '@fluentui/react-icons'; + +const EditIcon = bundleIcon(EditFilled, EditRegular); +const CutIcon = bundleIcon(CutFilled, CutRegular); +const PasteIcon = bundleIcon(ClipboardPasteFilled, ClipboardPasteRegular); + +export const MultilineItems = () => { + return ( + + + + + + + }> + Cut + + }> + Paste + + }> + Edit + + + + + ); +}; diff --git a/packages/react-components/react-menu/stories/src/Menu/index.stories.tsx b/packages/react-components/react-menu/stories/src/Menu/index.stories.tsx index 5804d5557e8f3b..f6bf01427c187b 100644 --- a/packages/react-components/react-menu/stories/src/Menu/index.stories.tsx +++ b/packages/react-components/react-menu/stories/src/Menu/index.stories.tsx @@ -23,6 +23,7 @@ export { MenuItemsWithIcons } from './MenuMenuItemsWithIcons.stories'; export { AligningWithIcons } from './MenuAligningWithIcons.stories'; export { AligningWithSelectableItems } from './MenuAligningWithSelectableItems.stories'; export { SecondaryContentForMenuItems } from './MenuSecondaryContentForMenuItems.stories'; +export { MultilineItems } from './MenuMultilineItems.stories'; export { ControllingOpenAndClose } from './MenuControllingOpenAndClose.stories'; export { GroupingItems } from './MenuGroupingItems.stories'; export { VisualDividerOnly } from './MenuVisualDividerOnly.stories'; From ab504b182ef3b6c7594fce9aa91948dac8332dd5 Mon Sep 17 00:00:00 2001 From: Anush Gupta <74965306+Anush2303@users.noreply.github.com> Date: Fri, 24 Jan 2025 21:32:16 +0530 Subject: [PATCH 10/13] fix(declarative-chart): Remove Duplicate keys warning (#33722) --- ...eact-charting-2caf6b30-798c-40cb-98ca-64aade9cc329.json | 7 +++++++ .../components/VerticalBarChart/VerticalBarChart.base.tsx | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 change/@fluentui-react-charting-2caf6b30-798c-40cb-98ca-64aade9cc329.json diff --git a/change/@fluentui-react-charting-2caf6b30-798c-40cb-98ca-64aade9cc329.json b/change/@fluentui-react-charting-2caf6b30-798c-40cb-98ca-64aade9cc329.json new file mode 100644 index 00000000000000..ccf97b9055a44e --- /dev/null +++ b/change/@fluentui-react-charting-2caf6b30-798c-40cb-98ca-64aade9cc329.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Fix Duplicate keys warning", + "packageName": "@fluentui/react-charting", + "email": "74965306+Anush2303@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/packages/charts/react-charting/src/components/VerticalBarChart/VerticalBarChart.base.tsx b/packages/charts/react-charting/src/components/VerticalBarChart/VerticalBarChart.base.tsx index 7b1eeabf68272f..37de4c9281515d 100644 --- a/packages/charts/react-charting/src/components/VerticalBarChart/VerticalBarChart.base.tsx +++ b/packages/charts/react-charting/src/components/VerticalBarChart/VerticalBarChart.base.tsx @@ -786,7 +786,7 @@ export class VerticalBarChartBase const gradientId = getId('VBC_Gradient') + `_${index}_${startColor}`; return ( - + {this.props.enableGradient && ( @@ -892,7 +892,7 @@ export class VerticalBarChartBase return ( {this.props.enableGradient && ( @@ -1005,7 +1005,7 @@ export class VerticalBarChartBase const gradientId = getId('VBC_Gradient') + `_${index}_${startColor}`; return ( - + {this.props.enableGradient && ( From 87d6ba3bd577a8be9756f4d392b048083d8ef16a Mon Sep 17 00:00:00 2001 From: ling1726 Date: Fri, 24 Jan 2025 18:57:40 +0100 Subject: [PATCH 11/13] fix: MenuItem is only focused when mouse cursor is moved (#33725) --- ...i-react-menu-820da09f-c52a-4751-a749-7f8ca4387d65.json | 7 +++++++ .../library/src/components/MenuItem/MenuItem.test.tsx | 4 ++-- .../MenuItem/__snapshots__/MenuItem.test.tsx.snap | 2 +- .../library/src/components/MenuItem/useMenuItem.tsx | 8 +++++--- .../__snapshots__/MenuItemCheckbox.test.tsx.snap | 2 +- .../__snapshots__/MenuItemRadio.test.tsx.snap | 2 +- .../library/src/components/MenuList/MenuList.cy.tsx | 2 +- 7 files changed, 18 insertions(+), 9 deletions(-) create mode 100644 change/@fluentui-react-menu-820da09f-c52a-4751-a749-7f8ca4387d65.json diff --git a/change/@fluentui-react-menu-820da09f-c52a-4751-a749-7f8ca4387d65.json b/change/@fluentui-react-menu-820da09f-c52a-4751-a749-7f8ca4387d65.json new file mode 100644 index 00000000000000..459f066c049d33 --- /dev/null +++ b/change/@fluentui-react-menu-820da09f-c52a-4751-a749-7f8ca4387d65.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "fix: MenuItem is only focused when mouse cursor is moved", + "packageName": "@fluentui/react-menu", + "email": "lingfangao@hotmail.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-menu/library/src/components/MenuItem/MenuItem.test.tsx b/packages/react-components/react-menu/library/src/components/MenuItem/MenuItem.test.tsx index 6095e5869210f5..febb627725a33b 100644 --- a/packages/react-components/react-menu/library/src/components/MenuItem/MenuItem.test.tsx +++ b/packages/react-components/react-menu/library/src/components/MenuItem/MenuItem.test.tsx @@ -40,13 +40,13 @@ describe('MenuItem', () => { expect(tree).toMatchSnapshot(); }); - it('should focus the item on mouseenter', () => { + it('should focus the item on mousemove', () => { // Arrange const { getByRole } = render(Item); // Act const menuitem = getByRole('menuitem'); - fireEvent.mouseEnter(menuitem); + fireEvent.mouseMove(menuitem); // Assert expect(document.activeElement).toBe(menuitem); diff --git a/packages/react-components/react-menu/library/src/components/MenuItem/__snapshots__/MenuItem.test.tsx.snap b/packages/react-components/react-menu/library/src/components/MenuItem/__snapshots__/MenuItem.test.tsx.snap index dc257c5e2d570c..6d744c6c35d055 100644 --- a/packages/react-components/react-menu/library/src/components/MenuItem/__snapshots__/MenuItem.test.tsx.snap +++ b/packages/react-components/react-menu/library/src/components/MenuItem/__snapshots__/MenuItem.test.tsx.snap @@ -6,7 +6,7 @@ exports[`MenuItem renders a default state 1`] = ` onClick={[Function]} onKeyDown={[Function]} onKeyUp={[Function]} - onMouseEnter={[Function]} + onMouseMove={[Function]} role="menuitem" tabIndex={0} > diff --git a/packages/react-components/react-menu/library/src/components/MenuItem/useMenuItem.tsx b/packages/react-components/react-menu/library/src/components/MenuItem/useMenuItem.tsx index 8140489b99816d..750a3deeda900c 100644 --- a/packages/react-components/react-menu/library/src/components/MenuItem/useMenuItem.tsx +++ b/packages/react-components/react-menu/library/src/components/MenuItem/useMenuItem.tsx @@ -74,10 +74,12 @@ export const useMenuItem_unstable = (props: MenuItemProps, ref: React.Ref { - innerRef.current?.focus(); + onMouseMove: useEventCallback(event => { + if (event.currentTarget.ownerDocument.activeElement !== event.currentTarget) { + innerRef.current?.focus(); + } - props.onMouseEnter?.(event); + props.onMouseMove?.(event); }), onClick: useEventCallback(event => { if (!hasSubmenu && !persistOnClick) { diff --git a/packages/react-components/react-menu/library/src/components/MenuItemCheckbox/__snapshots__/MenuItemCheckbox.test.tsx.snap b/packages/react-components/react-menu/library/src/components/MenuItemCheckbox/__snapshots__/MenuItemCheckbox.test.tsx.snap index 47e84002411fd2..a9f89bebad3882 100644 --- a/packages/react-components/react-menu/library/src/components/MenuItemCheckbox/__snapshots__/MenuItemCheckbox.test.tsx.snap +++ b/packages/react-components/react-menu/library/src/components/MenuItemCheckbox/__snapshots__/MenuItemCheckbox.test.tsx.snap @@ -8,7 +8,7 @@ exports[`MenuItemCheckbox conformance renders a default state 1`] = ` onClick={[Function]} onKeyDown={[Function]} onKeyUp={[Function]} - onMouseEnter={[Function]} + onMouseMove={[Function]} role="menuitemcheckbox" tabIndex={0} > diff --git a/packages/react-components/react-menu/library/src/components/MenuItemRadio/__snapshots__/MenuItemRadio.test.tsx.snap b/packages/react-components/react-menu/library/src/components/MenuItemRadio/__snapshots__/MenuItemRadio.test.tsx.snap index 6c1f079c2da6ba..7829b98c6a6c91 100644 --- a/packages/react-components/react-menu/library/src/components/MenuItemRadio/__snapshots__/MenuItemRadio.test.tsx.snap +++ b/packages/react-components/react-menu/library/src/components/MenuItemRadio/__snapshots__/MenuItemRadio.test.tsx.snap @@ -8,7 +8,7 @@ exports[`MenuItemRadio renders a default state 1`] = ` onClick={[Function]} onKeyDown={[Function]} onKeyUp={[Function]} - onMouseEnter={[Function]} + onMouseMove={[Function]} role="menuitemradio" tabIndex={0} > diff --git a/packages/react-components/react-menu/library/src/components/MenuList/MenuList.cy.tsx b/packages/react-components/react-menu/library/src/components/MenuList/MenuList.cy.tsx index bcfe5222076d67..f869c5fb6b6fb7 100644 --- a/packages/react-components/react-menu/library/src/components/MenuList/MenuList.cy.tsx +++ b/packages/react-components/react-menu/library/src/components/MenuList/MenuList.cy.tsx @@ -22,7 +22,7 @@ describe('MenuList', () => {
, ); cy.get(menuItemSelector).each(el => { - cy.wrap(el).trigger('mouseover').should('be.focused'); + cy.wrap(el).trigger('mousemove').should('be.focused'); }); }); From 0230517f104f6d57df264ba19f2a35ed477b61b4 Mon Sep 17 00:00:00 2001 From: Fluent UI Build Date: Mon, 27 Jan 2025 07:20:52 +0000 Subject: [PATCH 12/13] release: applying package updates - react v8 --- ...-2caf6b30-798c-40cb-98ca-64aade9cc329.json | 7 ------- ...-ef56337f-c8bb-48ee-94f5-75abe0aa1d3b.json | 7 ------- packages/charts/react-charting/CHANGELOG.json | 21 +++++++++++++++++++ packages/charts/react-charting/CHANGELOG.md | 12 ++++++++++- packages/charts/react-charting/package.json | 2 +- .../react-docsite-components/CHANGELOG.json | 15 +++++++++++++ .../react-docsite-components/CHANGELOG.md | 11 +++++++++- .../react-docsite-components/package.json | 4 ++-- packages/react-examples/package.json | 4 ++-- packages/react-monaco-editor/CHANGELOG.json | 15 +++++++++++++ packages/react-monaco-editor/CHANGELOG.md | 11 +++++++++- packages/react-monaco-editor/package.json | 4 ++-- 12 files changed, 89 insertions(+), 24 deletions(-) delete mode 100644 change/@fluentui-react-charting-2caf6b30-798c-40cb-98ca-64aade9cc329.json delete mode 100644 change/@fluentui-react-charting-ef56337f-c8bb-48ee-94f5-75abe0aa1d3b.json diff --git a/change/@fluentui-react-charting-2caf6b30-798c-40cb-98ca-64aade9cc329.json b/change/@fluentui-react-charting-2caf6b30-798c-40cb-98ca-64aade9cc329.json deleted file mode 100644 index ccf97b9055a44e..00000000000000 --- a/change/@fluentui-react-charting-2caf6b30-798c-40cb-98ca-64aade9cc329.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "patch", - "comment": "Fix Duplicate keys warning", - "packageName": "@fluentui/react-charting", - "email": "74965306+Anush2303@users.noreply.github.com", - "dependentChangeType": "patch" -} diff --git a/change/@fluentui-react-charting-ef56337f-c8bb-48ee-94f5-75abe0aa1d3b.json b/change/@fluentui-react-charting-ef56337f-c8bb-48ee-94f5-75abe0aa1d3b.json deleted file mode 100644 index e8006f3935cb83..00000000000000 --- a/change/@fluentui-react-charting-ef56337f-c8bb-48ee-94f5-75abe0aa1d3b.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "patch", - "comment": "fix: ensure text elements use the correct font-family in SVG export", - "packageName": "@fluentui/react-charting", - "email": "110246001+krkshitij@users.noreply.github.com", - "dependentChangeType": "patch" -} diff --git a/packages/charts/react-charting/CHANGELOG.json b/packages/charts/react-charting/CHANGELOG.json index 0e35b815417dd6..d82dbb26da72a8 100644 --- a/packages/charts/react-charting/CHANGELOG.json +++ b/packages/charts/react-charting/CHANGELOG.json @@ -1,6 +1,27 @@ { "name": "@fluentui/react-charting", "entries": [ + { + "date": "Mon, 27 Jan 2025 07:20:35 GMT", + "tag": "@fluentui/react-charting_v5.23.47", + "version": "5.23.47", + "comments": { + "patch": [ + { + "author": "74965306+Anush2303@users.noreply.github.com", + "package": "@fluentui/react-charting", + "commit": "ab504b182ef3b6c7594fce9aa91948dac8332dd5", + "comment": "Fix Duplicate keys warning" + }, + { + "author": "110246001+krkshitij@users.noreply.github.com", + "package": "@fluentui/react-charting", + "commit": "57165f4aa96f1417347275e52262f6de755225d5", + "comment": "fix: ensure text elements use the correct font-family in SVG export" + } + ] + } + }, { "date": "Fri, 24 Jan 2025 07:20:37 GMT", "tag": "@fluentui/react-charting_v5.23.46", diff --git a/packages/charts/react-charting/CHANGELOG.md b/packages/charts/react-charting/CHANGELOG.md index b1780055d0cfdd..2946a0169c8ae9 100644 --- a/packages/charts/react-charting/CHANGELOG.md +++ b/packages/charts/react-charting/CHANGELOG.md @@ -1,9 +1,19 @@ # Change Log - @fluentui/react-charting -This log was last generated on Fri, 24 Jan 2025 07:20:37 GMT and should not be manually modified. +This log was last generated on Mon, 27 Jan 2025 07:20:35 GMT and should not be manually modified. +## [5.23.47](https://github.com/microsoft/fluentui/tree/@fluentui/react-charting_v5.23.47) + +Mon, 27 Jan 2025 07:20:35 GMT +[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-charting_v5.23.46..@fluentui/react-charting_v5.23.47) + +### Patches + +- Fix Duplicate keys warning ([PR #33722](https://github.com/microsoft/fluentui/pull/33722) by 74965306+Anush2303@users.noreply.github.com) +- fix: ensure text elements use the correct font-family in SVG export ([PR #33719](https://github.com/microsoft/fluentui/pull/33719) by 110246001+krkshitij@users.noreply.github.com) + ## [5.23.46](https://github.com/microsoft/fluentui/tree/@fluentui/react-charting_v5.23.46) Fri, 24 Jan 2025 07:20:37 GMT diff --git a/packages/charts/react-charting/package.json b/packages/charts/react-charting/package.json index e684171bcf5271..7f8658f49bbdc0 100644 --- a/packages/charts/react-charting/package.json +++ b/packages/charts/react-charting/package.json @@ -1,6 +1,6 @@ { "name": "@fluentui/react-charting", - "version": "5.23.46", + "version": "5.23.47", "description": "React web charting controls for Microsoft fluentui system.", "main": "lib-commonjs/index.js", "module": "lib/index.js", diff --git a/packages/react-docsite-components/CHANGELOG.json b/packages/react-docsite-components/CHANGELOG.json index 7cabe24b98da22..1797d72d6e11be 100644 --- a/packages/react-docsite-components/CHANGELOG.json +++ b/packages/react-docsite-components/CHANGELOG.json @@ -1,6 +1,21 @@ { "name": "@fluentui/react-docsite-components", "entries": [ + { + "date": "Mon, 27 Jan 2025 07:20:35 GMT", + "tag": "@fluentui/react-docsite-components_v8.13.167", + "version": "8.13.167", + "comments": { + "patch": [ + { + "author": "beachball", + "package": "@fluentui/react-docsite-components", + "comment": "Bump @fluentui/react-monaco-editor to v1.7.285", + "commit": "87d6ba3bd577a8be9756f4d392b048083d8ef16a" + } + ] + } + }, { "date": "Fri, 24 Jan 2025 07:20:37 GMT", "tag": "@fluentui/react-docsite-components_v8.13.166", diff --git a/packages/react-docsite-components/CHANGELOG.md b/packages/react-docsite-components/CHANGELOG.md index bb0c0dbf48d91c..f46c670b75e7e9 100644 --- a/packages/react-docsite-components/CHANGELOG.md +++ b/packages/react-docsite-components/CHANGELOG.md @@ -1,9 +1,18 @@ # Change Log - @fluentui/react-docsite-components -This log was last generated on Fri, 24 Jan 2025 07:20:37 GMT and should not be manually modified. +This log was last generated on Mon, 27 Jan 2025 07:20:35 GMT and should not be manually modified. +## [8.13.167](https://github.com/microsoft/fluentui/tree/@fluentui/react-docsite-components_v8.13.167) + +Mon, 27 Jan 2025 07:20:35 GMT +[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-docsite-components_v8.13.166..@fluentui/react-docsite-components_v8.13.167) + +### Patches + +- Bump @fluentui/react-monaco-editor to v1.7.285 ([PR #33725](https://github.com/microsoft/fluentui/pull/33725) by beachball) + ## [8.13.166](https://github.com/microsoft/fluentui/tree/@fluentui/react-docsite-components_v8.13.166) Fri, 24 Jan 2025 07:20:37 GMT diff --git a/packages/react-docsite-components/package.json b/packages/react-docsite-components/package.json index 87b6d92d67f959..89ab9d3a5a5854 100644 --- a/packages/react-docsite-components/package.json +++ b/packages/react-docsite-components/package.json @@ -1,6 +1,6 @@ { "name": "@fluentui/react-docsite-components", - "version": "8.13.166", + "version": "8.13.167", "description": "Fluent UI React components for building documentation sites.", "main": "lib-commonjs/index.js", "module": "lib/index.js", @@ -42,7 +42,7 @@ "@fluentui/public-docsite-setup": "^0.3.34", "@fluentui/react-hooks": "^8.8.16", "@fluentui/set-version": "^8.2.23", - "@fluentui/react-monaco-editor": "^1.7.284", + "@fluentui/react-monaco-editor": "^1.7.285", "color-check": "0.0.2", "markdown-to-jsx": "^7.0.0", "office-ui-fabric-core": "^11.0.0", diff --git a/packages/react-examples/package.json b/packages/react-examples/package.json index 03cb95a9913de4..552ee960803e69 100644 --- a/packages/react-examples/package.json +++ b/packages/react-examples/package.json @@ -36,8 +36,8 @@ "@fluentui/merge-styles": "^8.6.13", "@fluentui/react": "^8.122.8", "@fluentui/react-cards": "^0.205.197", - "@fluentui/react-charting": "^5.23.46", - "@fluentui/react-docsite-components": "^8.13.166", + "@fluentui/react-charting": "^5.23.47", + "@fluentui/react-docsite-components": "^8.13.167", "@fluentui/react-experiments": "^8.14.194", "@fluentui/react-file-type-icons": "^8.12.7", "@fluentui/react-focus": "^8.9.20", diff --git a/packages/react-monaco-editor/CHANGELOG.json b/packages/react-monaco-editor/CHANGELOG.json index 64c72b368b3779..390350b78aa726 100644 --- a/packages/react-monaco-editor/CHANGELOG.json +++ b/packages/react-monaco-editor/CHANGELOG.json @@ -1,6 +1,21 @@ { "name": "@fluentui/react-monaco-editor", "entries": [ + { + "date": "Mon, 27 Jan 2025 07:20:35 GMT", + "tag": "@fluentui/react-monaco-editor_v1.7.285", + "version": "1.7.285", + "comments": { + "patch": [ + { + "author": "beachball", + "package": "@fluentui/react-monaco-editor", + "comment": "Bump @fluentui/react-charting to v5.23.47", + "commit": "87d6ba3bd577a8be9756f4d392b048083d8ef16a" + } + ] + } + }, { "date": "Fri, 24 Jan 2025 07:20:37 GMT", "tag": "@fluentui/react-monaco-editor_v1.7.284", diff --git a/packages/react-monaco-editor/CHANGELOG.md b/packages/react-monaco-editor/CHANGELOG.md index df035313f71848..05e87654c83ab6 100644 --- a/packages/react-monaco-editor/CHANGELOG.md +++ b/packages/react-monaco-editor/CHANGELOG.md @@ -1,9 +1,18 @@ # Change Log - @fluentui/react-monaco-editor -This log was last generated on Fri, 24 Jan 2025 07:20:37 GMT and should not be manually modified. +This log was last generated on Mon, 27 Jan 2025 07:20:35 GMT and should not be manually modified. +## [1.7.285](https://github.com/microsoft/fluentui/tree/@fluentui/react-monaco-editor_v1.7.285) + +Mon, 27 Jan 2025 07:20:35 GMT +[Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-monaco-editor_v1.7.284..@fluentui/react-monaco-editor_v1.7.285) + +### Patches + +- Bump @fluentui/react-charting to v5.23.47 ([PR #33725](https://github.com/microsoft/fluentui/pull/33725) by beachball) + ## [1.7.284](https://github.com/microsoft/fluentui/tree/@fluentui/react-monaco-editor_v1.7.284) Fri, 24 Jan 2025 07:20:37 GMT diff --git a/packages/react-monaco-editor/package.json b/packages/react-monaco-editor/package.json index dce7f2c006e2a0..0e092dd12009c6 100644 --- a/packages/react-monaco-editor/package.json +++ b/packages/react-monaco-editor/package.json @@ -1,6 +1,6 @@ { "name": "@fluentui/react-monaco-editor", - "version": "1.7.284", + "version": "1.7.285", "description": "Live React example editing using monaco", "main": "lib-commonjs/index.js", "module": "lib/index.js", @@ -34,7 +34,7 @@ "@fluentui/example-data": "^8.4.25", "@fluentui/monaco-editor": "^1.3.24", "@fluentui/react-hooks": "^8.8.16", - "@fluentui/react-charting": "^5.23.46", + "@fluentui/react-charting": "^5.23.47", "raw-loader": "4.0.2", "react-syntax-highlighter": "^10.1.3", "tslib": "^2.1.0" From 808cd501d50a317249d3d02f01ea3dd88114b252 Mon Sep 17 00:00:00 2001 From: Oleksandr Fediashov Date: Mon, 27 Jan 2025 14:21:32 +0100 Subject: [PATCH 13/13] feat(react-positioning): allow to configure boundaries with "PositioningRect" (#33724) --- ...=> PositioningMatchTargetSize.stories.tsx} | 0 ...ioningOverflowBoundaryPadding.stories.tsx} | 0 ...ositioningOverflowBoundaryRect.stories.tsx | 118 ++++++++++++++++++ .../Concepts/Positioning/index.stories.tsx | 5 +- .../Positioning/Positioning.stories.tsx | 101 ++++++++++++++- ...-effdfdb6-3257-4413-8137-665d46849a33.json | 7 ++ ...-1b79ae8a-e147-4e34-8d3b-fcaf84702e74.json | 7 ++ .../etc/react-components.api.md | 6 + .../react-components/src/index.ts | 2 + .../etc/react-positioning.api.md | 19 ++- .../react-positioning/src/index.ts | 3 + .../react-positioning/src/types.ts | 22 +++- .../src/utils/getBoundary.ts | 7 +- 13 files changed, 277 insertions(+), 20 deletions(-) rename apps/public-docsite-v9/src/Concepts/Positioning/{MatchTargetSize.stories.tsx => PositioningMatchTargetSize.stories.tsx} (100%) rename apps/public-docsite-v9/src/Concepts/Positioning/{OverflowBoundaryPadding.stories.tsx => PositioningOverflowBoundaryPadding.stories.tsx} (100%) create mode 100644 apps/public-docsite-v9/src/Concepts/Positioning/PositioningOverflowBoundaryRect.stories.tsx create mode 100644 change/@fluentui-react-components-effdfdb6-3257-4413-8137-665d46849a33.json create mode 100644 change/@fluentui-react-positioning-1b79ae8a-e147-4e34-8d3b-fcaf84702e74.json diff --git a/apps/public-docsite-v9/src/Concepts/Positioning/MatchTargetSize.stories.tsx b/apps/public-docsite-v9/src/Concepts/Positioning/PositioningMatchTargetSize.stories.tsx similarity index 100% rename from apps/public-docsite-v9/src/Concepts/Positioning/MatchTargetSize.stories.tsx rename to apps/public-docsite-v9/src/Concepts/Positioning/PositioningMatchTargetSize.stories.tsx diff --git a/apps/public-docsite-v9/src/Concepts/Positioning/OverflowBoundaryPadding.stories.tsx b/apps/public-docsite-v9/src/Concepts/Positioning/PositioningOverflowBoundaryPadding.stories.tsx similarity index 100% rename from apps/public-docsite-v9/src/Concepts/Positioning/OverflowBoundaryPadding.stories.tsx rename to apps/public-docsite-v9/src/Concepts/Positioning/PositioningOverflowBoundaryPadding.stories.tsx diff --git a/apps/public-docsite-v9/src/Concepts/Positioning/PositioningOverflowBoundaryRect.stories.tsx b/apps/public-docsite-v9/src/Concepts/Positioning/PositioningOverflowBoundaryRect.stories.tsx new file mode 100644 index 00000000000000..fa6b2f21fea84d --- /dev/null +++ b/apps/public-docsite-v9/src/Concepts/Positioning/PositioningOverflowBoundaryRect.stories.tsx @@ -0,0 +1,118 @@ +import * as React from 'react'; +import { + Popover, + PopoverTrigger, + PopoverSurface, + Button, + makeStyles, + tokens, + type PositioningRect, + useIsomorphicLayoutEffect, +} from '@fluentui/react-components'; + +const useClasses = makeStyles({ + area: { + border: `2px solid ${tokens.colorStatusDangerBackground3}`, + padding: '60px 20px 20px 20px', + width: '300px', + height: '300px', + + display: 'flex', + flexDirection: 'column', + alignItems: 'end', + justifyContent: 'space-between', + position: 'relative', + + '::before': { + content: '"Container"', + position: 'absolute', + padding: `${tokens.spacingHorizontalMNudge} ${tokens.spacingHorizontalS}`, + + top: 0, + left: 0, + + color: tokens.colorStatusDangerBackground1, + backgroundColor: tokens.colorStatusDangerBackground3, + }, + }, + boundary: { + width: '320px', + height: '320px', + outline: `2px solid ${tokens.colorBrandBackground}`, + + position: 'absolute', + top: '50px', + left: '10px', + pointerEvents: 'none', + + '::before': { + content: '"Boundary"', + position: 'absolute', + padding: `${tokens.spacingHorizontalMNudge} ${tokens.spacingHorizontalS}`, + + top: 0, + left: 0, + + color: tokens.colorNeutralForegroundOnBrand, + backgroundColor: tokens.colorBrandBackground, + }, + }, +}); + +export const OverflowBoundaryRect = () => { + const classes = useClasses(); + + const boundaryRef = React.useRef(null); + const [boundaryRect, setBoundaryRect] = React.useState(null); + + useIsomorphicLayoutEffect(() => { + setBoundaryRect(boundaryRef.current?.getBoundingClientRect() ?? null); + }, []); + + return ( +
+
+ + + + + + Stays within the defined rect + + + + + + + Stays within the defined rect + +
+ ); +}; + +OverflowBoundaryRect.parameters = { + docs: { + description: { + story: [ + 'Boundaries can be also defined as `Rect` objects. ', + 'This is useful when a boundary is not an actual element, but some kind of computed values.', + ].join('\n'), + }, + }, +}; diff --git a/apps/public-docsite-v9/src/Concepts/Positioning/index.stories.tsx b/apps/public-docsite-v9/src/Concepts/Positioning/index.stories.tsx index 526e9b9a576ec2..e4958cfe29e31e 100644 --- a/apps/public-docsite-v9/src/Concepts/Positioning/index.stories.tsx +++ b/apps/public-docsite-v9/src/Concepts/Positioning/index.stories.tsx @@ -11,9 +11,10 @@ export { AnchorToTarget } from './PositioningAnchorToTarget.stories'; export { ImperativeAnchorTarget } from './PositioningImperativeAnchorTarget.stories'; export { ImperativePositionUpdate } from './PositioningImperativePositionUpdate.stories'; export { OverflowBoundary } from './PositioningOverflowBoundary.stories'; -export { OverflowBoundaryPadding } from './OverflowBoundaryPadding.stories'; +export { OverflowBoundaryRect } from './PositioningOverflowBoundaryRect.stories'; +export { OverflowBoundaryPadding } from './PositioningOverflowBoundaryPadding.stories'; export { FlipBoundary } from './PositioningFlipBoundary.stories'; -export { MatchTargetSize } from './MatchTargetSize.stories'; +export { MatchTargetSize } from './PositioningMatchTargetSize.stories'; export { DisableTransform } from './PositioningDisableTransform.stories'; export { ListenToUpdates } from './PositioningListenToUpdates.stories'; export { AutoSizeForSmallViewport } from './PositioningAutoSize.stories'; diff --git a/apps/vr-tests-react-components/src/stories/Positioning/Positioning.stories.tsx b/apps/vr-tests-react-components/src/stories/Positioning/Positioning.stories.tsx index 5421aa2f3c6035..3c4cb2047f0cab 100644 --- a/apps/vr-tests-react-components/src/stories/Positioning/Positioning.stories.tsx +++ b/apps/vr-tests-react-components/src/stories/Positioning/Positioning.stories.tsx @@ -5,8 +5,9 @@ import { PositioningProps, PositioningVirtualElement, PositioningImperativeRef, + type PositioningRect, } from '@fluentui/react-positioning'; -import { useMergedRefs } from '@fluentui/react-utilities'; +import { useMergedRefs, useIsomorphicLayoutEffect } from '@fluentui/react-utilities'; import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts'; import { Steps, StoryWright } from 'storywright'; @@ -814,11 +815,7 @@ const PositioningEndEvent = () => { }; const TargetDisplayNone = () => { - const positioningRef = React.useRef(null); - const { targetRef, containerRef } = usePositioning({ - positioningRef, - }); - + const { targetRef, containerRef } = usePositioning({}); const [visible, setVisible] = React.useState(true); return ( @@ -939,6 +936,95 @@ const ShiftToCoverTargetAsyncContent = () => { ); }; +const BoundaryRect = () => { + const rectHostRef = React.useRef(null); + + const boundaryRect = React.useMemo( + () => ({ + width: 700, + height: 700, + x: 70, + y: 70, + }), + [], + ); + const { targetRef, containerRef } = usePositioning({ + overflowBoundary: boundaryRect, + + position: 'below', + align: 'end', + }); + + useIsomorphicLayoutEffect(() => { + const rectEl = document.createElement('div'); + + Object.assign(rectEl.style, { + position: 'fixed', + border: '4px solid orange', + boxSizing: 'border-box', + + left: `${boundaryRect.x}px`, + top: `${boundaryRect.y}px`, + width: `${boundaryRect.width}px`, + height: `${boundaryRect.height}px`, + + zIndex: 1, + }); + + rectHostRef.current?.append(rectEl); + + return () => { + rectEl.remove(); + }; + }, [boundaryRect]); + + return ( + <> +
+
+
+ Hello world +
+
+
+
    +
  • + SHOULD BE below gray box as it's a target +
  • +
  • + SHOULD BE inside an orange box as it's a overflowBoundary +
  • +
+
+ + ); +}; + export default { title: 'Positioning', @@ -960,6 +1046,9 @@ export default { ], } satisfies Meta<'div'>; +export const _BoundaryRect = () => ; +_BoundaryRect.storyName = 'using boundary rect'; + export const _PositionAndAlignProps = () => ; _PositionAndAlignProps.storyName = 'position and align props'; diff --git a/change/@fluentui-react-components-effdfdb6-3257-4413-8137-665d46849a33.json b/change/@fluentui-react-components-effdfdb6-3257-4413-8137-665d46849a33.json new file mode 100644 index 00000000000000..ad5069ff1d59a6 --- /dev/null +++ b/change/@fluentui-react-components-effdfdb6-3257-4413-8137-665d46849a33.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "feat: export \"PositioningBoundary\" & \"PositioningRect\" types", + "packageName": "@fluentui/react-components", + "email": "olfedias@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-react-positioning-1b79ae8a-e147-4e34-8d3b-fcaf84702e74.json b/change/@fluentui-react-positioning-1b79ae8a-e147-4e34-8d3b-fcaf84702e74.json new file mode 100644 index 00000000000000..346dd8d597acac --- /dev/null +++ b/change/@fluentui-react-positioning-1b79ae8a-e147-4e34-8d3b-fcaf84702e74.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "feat: allow to configure boundaries with \"PositioningRect\"", + "packageName": "@fluentui/react-positioning", + "email": "olfedias@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-components/etc/react-components.api.md b/packages/react-components/react-components/etc/react-components.api.md index 9fa63ed455f95c..b2dd2a9f62bc25 100644 --- a/packages/react-components/react-components/etc/react-components.api.md +++ b/packages/react-components/react-components/etc/react-components.api.md @@ -691,8 +691,10 @@ import { Portal } from '@fluentui/react-portal'; import { PortalMountNodeProvider } from '@fluentui/react-shared-contexts'; import { PortalProps } from '@fluentui/react-portal'; import { PortalState } from '@fluentui/react-portal'; +import { PositioningBoundary } from '@fluentui/react-positioning'; import { PositioningImperativeRef } from '@fluentui/react-positioning'; import { PositioningProps } from '@fluentui/react-positioning'; +import { PositioningRect } from '@fluentui/react-positioning'; import { PositioningShorthand } from '@fluentui/react-positioning'; import { PositioningShorthandValue } from '@fluentui/react-positioning'; import { PositioningVirtualElement } from '@fluentui/react-positioning'; @@ -3201,10 +3203,14 @@ export { PortalProps } export { PortalState } +export { PositioningBoundary } + export { PositioningImperativeRef } export { PositioningProps } +export { PositioningRect } + export { PositioningShorthand } export { PositioningShorthandValue } diff --git a/packages/react-components/react-components/src/index.ts b/packages/react-components/react-components/src/index.ts index 32dd9b20295d32..dc9bec538639a3 100644 --- a/packages/react-components/react-components/src/index.ts +++ b/packages/react-components/react-components/src/index.ts @@ -821,7 +821,9 @@ export type { export { resolvePositioningShorthand } from '@fluentui/react-positioning'; export type { + PositioningBoundary, PositioningProps, + PositioningRect, PositioningShorthand, PositioningShorthandValue, PositioningImperativeRef, diff --git a/packages/react-components/react-positioning/etc/react-positioning.api.md b/packages/react-components/react-positioning/etc/react-positioning.api.md index 3e2adcbf2b93ba..0ed0122986cddd 100644 --- a/packages/react-components/react-positioning/etc/react-positioning.api.md +++ b/packages/react-components/react-positioning/etc/react-positioning.api.md @@ -13,8 +13,8 @@ export type Alignment = 'top' | 'bottom' | 'start' | 'end' | 'center'; // @public (undocumented) export type AutoSize = 'height' | 'height-always' | 'width' | 'width-always' | 'always' | boolean; -// @public (undocumented) -export type Boundary = HTMLElement | Array | 'clippingParents' | 'scrollParent' | 'window'; +// @public @deprecated (undocumented) +export type Boundary = PositioningBoundary; // @internal export function createArrowHeightStyles(arrowHeight: number): GriffelStyle; @@ -47,8 +47,8 @@ export type OffsetFunction = (param: OffsetFunctionParam) => OffsetObject | Offs // @public (undocumented) export type OffsetFunctionParam = { - positionedRect: Rect; - targetRect: Rect; + positionedRect: PositioningRect; + targetRect: PositioningRect; position: Position; alignment?: Alignment; }; @@ -65,6 +65,9 @@ export type OffsetShorthand = number; // @public (undocumented) export type Position = 'above' | 'below' | 'before' | 'after'; +// @public (undocumented) +export type PositioningBoundary = PositioningRect | HTMLElement | Array | 'clippingParents' | 'scrollParent' | 'window'; + // @public (undocumented) export type PositioningImperativeRef = { updatePosition: () => void; @@ -77,6 +80,14 @@ export interface PositioningProps extends Pick | 'clippingParents' | 'scrollParent' | 'window'; +export type PositioningBoundary = + | PositioningRect + | HTMLElement + | Array + | 'clippingParents' + | 'scrollParent' + | 'window'; +/** + * @deprecated use PositioningBoundary instead + */ +export type Boundary = PositioningBoundary; export type PositioningImperativeRef = { /** @@ -91,10 +101,10 @@ export interface PositioningOptions { align?: Alignment; /** The element which will define the boundaries of the positioned element for the flip behavior. */ - flipBoundary?: Boundary | null; + flipBoundary?: PositioningBoundary | null; /** The element which will define the boundaries of the positioned element for the overflow behavior. */ - overflowBoundary?: Boundary | null; + overflowBoundary?: PositioningBoundary | null; /** * Applies a padding to the overflow bounadry, so that overflow is detected earlier before the diff --git a/packages/react-components/react-positioning/src/utils/getBoundary.ts b/packages/react-components/react-positioning/src/utils/getBoundary.ts index 482b29fb41013d..39e0db34f3b51b 100644 --- a/packages/react-components/react-positioning/src/utils/getBoundary.ts +++ b/packages/react-components/react-positioning/src/utils/getBoundary.ts @@ -1,12 +1,15 @@ import type { Boundary as FloatingUIBoundary } from '@floating-ui/dom'; import { getScrollParent } from './getScrollParent'; -import type { Boundary } from '../types'; +import type { PositioningBoundary } from '../types'; /** * Allows to mimic a behavior from V1 of Popper and accept `window` and `scrollParent` as strings. */ -export function getBoundary(element: HTMLElement | null, boundary?: Boundary): FloatingUIBoundary | undefined { +export function getBoundary( + element: HTMLElement | null, + boundary?: PositioningBoundary, +): FloatingUIBoundary | undefined { if (boundary === 'window') { return element?.ownerDocument!.documentElement; }