From 9133927daab8a5315bb6b5dfe09ae3c9b9b3f8cf Mon Sep 17 00:00:00 2001 From: zhixzhan Date: Mon, 10 May 2021 14:54:28 +0800 Subject: [PATCH 1/8] fix breadcrumb & show code button collision --- .../src/pages/design/VisualPanelHeader.tsx | 24 ++++++++++--------- .../client/src/pages/design/styles.ts | 16 ++++++++++++- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/Composer/packages/client/src/pages/design/VisualPanelHeader.tsx b/Composer/packages/client/src/pages/design/VisualPanelHeader.tsx index 8cb60601e4..0786c8eddc 100644 --- a/Composer/packages/client/src/pages/design/VisualPanelHeader.tsx +++ b/Composer/packages/client/src/pages/design/VisualPanelHeader.tsx @@ -18,7 +18,7 @@ import { decodeDesignerPathToArrayPath } from '../../utils/convertUtils/designer import { getFocusPath } from '../../utils/navigation'; import { TreeLink } from '../../components/ProjectTree/types'; -import { breadcrumbClass } from './styles'; +import * as pageStyles from './styles'; type BreadcrumbItem = { key: string; @@ -171,16 +171,18 @@ const VisualPanelHeader: React.FC = React.memo((props) = const items = breadcrumbs.map(createBreadcrumbItem); return ( -
- undefined} - /> -
+
+
+ undefined} + /> +
+
{showCode ? formatMessage('Hide code') : formatMessage('Show code')} diff --git a/Composer/packages/client/src/pages/design/styles.ts b/Composer/packages/client/src/pages/design/styles.ts index 9d0e9a70be..782b0f1e21 100644 --- a/Composer/packages/client/src/pages/design/styles.ts +++ b/Composer/packages/client/src/pages/design/styles.ts @@ -103,9 +103,23 @@ export const formEditor = css` min-width: 300px; `; +export const visualPanelHeaderContainer = css` + height: 65px; +`; + +export const visualPanelHeaderLeft = css` + overflow: hidden; + float: left; + width: calc(100% - 100px); +`; + +export const visualPanelHeaderRight = css` + float: right; + line-height: 65px; +`; + export const breadcrumbClass = mergeStyleSets({ root: { - width: '500px', margin: '0', padding: '10px', }, From ac5fd26ce8598adf8d5a2db1fbb37b0d1c70e57b Mon Sep 17 00:00:00 2001 From: zhixzhan Date: Tue, 11 May 2021 09:33:53 +0800 Subject: [PATCH 2/8] use flex --- .../src/pages/design/VisualPanelHeader.tsx | 20 +++++++++---------- .../client/src/pages/design/styles.ts | 11 +++------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/Composer/packages/client/src/pages/design/VisualPanelHeader.tsx b/Composer/packages/client/src/pages/design/VisualPanelHeader.tsx index 0786c8eddc..477ec71642 100644 --- a/Composer/packages/client/src/pages/design/VisualPanelHeader.tsx +++ b/Composer/packages/client/src/pages/design/VisualPanelHeader.tsx @@ -172,17 +172,15 @@ const VisualPanelHeader: React.FC = React.memo((props) = return (
-
- undefined} - /> -
-
+ undefined} + /> +
{showCode ? formatMessage('Hide code') : formatMessage('Show code')} diff --git a/Composer/packages/client/src/pages/design/styles.ts b/Composer/packages/client/src/pages/design/styles.ts index 782b0f1e21..730b1426f9 100644 --- a/Composer/packages/client/src/pages/design/styles.ts +++ b/Composer/packages/client/src/pages/design/styles.ts @@ -104,17 +104,12 @@ export const formEditor = css` `; export const visualPanelHeaderContainer = css` + display: flex; + justify-content: space-between; height: 65px; `; -export const visualPanelHeaderLeft = css` - overflow: hidden; - float: left; - width: calc(100% - 100px); -`; - -export const visualPanelHeaderRight = css` - float: right; +export const visualPanelHeaderShowCodeButton = css` line-height: 65px; `; From 4c5f336d13042c82272ef1b6c25fcc19faf732eb Mon Sep 17 00:00:00 2001 From: zhixzhan Date: Tue, 11 May 2021 15:42:16 +0800 Subject: [PATCH 3/8] update styles --- Composer/packages/client/src/pages/design/styles.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Composer/packages/client/src/pages/design/styles.ts b/Composer/packages/client/src/pages/design/styles.ts index 730b1426f9..b139cc38fc 100644 --- a/Composer/packages/client/src/pages/design/styles.ts +++ b/Composer/packages/client/src/pages/design/styles.ts @@ -110,7 +110,8 @@ export const visualPanelHeaderContainer = css` `; export const visualPanelHeaderShowCodeButton = css` - line-height: 65px; + align-items: center; + display: flex; `; export const breadcrumbClass = mergeStyleSets({ From 0cfa598616ff80465eab1a49720023cb0afdea7e Mon Sep 17 00:00:00 2001 From: zhixzhan Date: Thu, 13 May 2021 09:21:49 +0800 Subject: [PATCH 4/8] observe button width, auto layout ... breadcrumb --- .../src/pages/design/VisualPanelHeader.tsx | 56 +++++++++++++++---- .../client/src/pages/design/styles.ts | 6 +- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/Composer/packages/client/src/pages/design/VisualPanelHeader.tsx b/Composer/packages/client/src/pages/design/VisualPanelHeader.tsx index 477ec71642..18b8b5a7e5 100644 --- a/Composer/packages/client/src/pages/design/VisualPanelHeader.tsx +++ b/Composer/packages/client/src/pages/design/VisualPanelHeader.tsx @@ -155,11 +155,43 @@ const useBreadcrumbs = (projectId: string, pluginConfig?: PluginConfig) => { }, [currentDialog?.content, initialBreadcrumbArray]); return breadcrumbArray; }; - +const defaultToggleButtonWidth = 100; +const spaceBetweenContainers = 6; const VisualPanelHeader: React.FC = React.memo((props) => { const { showCode, projectId, onShowCodeClick, pluginConfig } = props; const breadcrumbs = useBreadcrumbs(projectId, pluginConfig); - + const toggleButtonContainerRef = React.useRef(null); + const containerRef = React.useRef(null); + const [toggleButtonWidth, setToggleButtonWidth] = React.useState(defaultToggleButtonWidth); + const [breadcrumbContainerWidth, setBreadcrumbContainerWidth] = React.useState( + `calc(100% - ${toggleButtonWidth}px)` + ); + // Resize observer callback to update the width of the breadcrumb container + const resizeObserverRef = React.useRef( + new ResizeObserver((entries) => { + if (entries.length) { + const { width } = entries[0].contentRect; + setBreadcrumbContainerWidth(width - toggleButtonWidth - spaceBetweenContainers); + } + }) + ); + // Set the width of the toggle button based on its text (locale) + React.useEffect(() => { + if (toggleButtonContainerRef.current) { + const toggleButton = toggleButtonContainerRef.current.querySelector('button'); + if (toggleButton) { + const { width } = toggleButton?.getBoundingClientRect(); + setToggleButtonWidth(width); + } + } + }, []); + // Observe width changes of the container to re-set the available width for breadcrumb container + React.useEffect(() => { + if (containerRef.current) { + resizeObserverRef.current.observe(containerRef.current); + } + return () => resizeObserverRef.current.disconnect(); + }, []); const createBreadcrumbItem: (breadcrumb: BreadcrumbItem) => IBreadcrumbItem = (breadcrumb: BreadcrumbItem) => { return { key: breadcrumb.key, @@ -171,16 +203,16 @@ const VisualPanelHeader: React.FC = React.memo((props) = const items = breadcrumbs.map(createBreadcrumbItem); return ( -
- undefined} - /> -
+
+
+ +
+
{showCode ? formatMessage('Hide code') : formatMessage('Show code')} diff --git a/Composer/packages/client/src/pages/design/styles.ts b/Composer/packages/client/src/pages/design/styles.ts index b139cc38fc..cfe8679dee 100644 --- a/Composer/packages/client/src/pages/design/styles.ts +++ b/Composer/packages/client/src/pages/design/styles.ts @@ -105,13 +105,13 @@ export const formEditor = css` export const visualPanelHeaderContainer = css` display: flex; - justify-content: space-between; + align-items: center; height: 65px; `; export const visualPanelHeaderShowCodeButton = css` - align-items: center; - display: flex; + padding: 10px; + width: fit-content; `; export const breadcrumbClass = mergeStyleSets({ From a9c3d6c956f251c65b127a36cf15f7f6c0b80760 Mon Sep 17 00:00:00 2001 From: zhixzhan Date: Thu, 13 May 2021 09:48:53 +0800 Subject: [PATCH 5/8] ignore typescript ResizeObserver declarations missing --- Composer/packages/client/src/pages/design/VisualPanelHeader.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/Composer/packages/client/src/pages/design/VisualPanelHeader.tsx b/Composer/packages/client/src/pages/design/VisualPanelHeader.tsx index 18b8b5a7e5..18bbf686fb 100644 --- a/Composer/packages/client/src/pages/design/VisualPanelHeader.tsx +++ b/Composer/packages/client/src/pages/design/VisualPanelHeader.tsx @@ -168,6 +168,7 @@ const VisualPanelHeader: React.FC = React.memo((props) = ); // Resize observer callback to update the width of the breadcrumb container const resizeObserverRef = React.useRef( + // @ts-ignore new ResizeObserver((entries) => { if (entries.length) { const { width } = entries[0].contentRect; From a788889d4ce3255ed3f4c3fa8aad447f166e1b7c Mon Sep 17 00:00:00 2001 From: zhixzhan Date: Thu, 13 May 2021 11:26:48 +0800 Subject: [PATCH 6/8] fix type in test --- .../packages/client/__tests__/mocks/ResizeObserver.ts | 11 +++++++++++ .../client/__tests__/pages/design/Design.test.tsx | 3 +++ 2 files changed, 14 insertions(+) create mode 100644 Composer/packages/client/__tests__/mocks/ResizeObserver.ts diff --git a/Composer/packages/client/__tests__/mocks/ResizeObserver.ts b/Composer/packages/client/__tests__/mocks/ResizeObserver.ts new file mode 100644 index 0000000000..78db7dfd0d --- /dev/null +++ b/Composer/packages/client/__tests__/mocks/ResizeObserver.ts @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +export default class ResizeObserver { + observe() { + // do nothing + } + disconnect() { + // do nothing + } +} diff --git a/Composer/packages/client/__tests__/pages/design/Design.test.tsx b/Composer/packages/client/__tests__/pages/design/Design.test.tsx index d3b12856af..507ca29aa9 100644 --- a/Composer/packages/client/__tests__/pages/design/Design.test.tsx +++ b/Composer/packages/client/__tests__/pages/design/Design.test.tsx @@ -16,6 +16,9 @@ import { undoFunctionState } from '../../../src/recoilModel/undo/history'; import mockProjectResponse from '../../../src/recoilModel/dispatchers/__tests__/mocks/mockProjectResponse.json'; import DesignPage from '../../../src/pages/design/DesignPage'; import { SAMPLE_DIALOG } from '../../mocks/sampleDialog'; +import ResizeObserver from '../../mocks/ResizeObserver'; + +(global as any).ResizeObserver = ResizeObserver; const projectId = '12345.6789'; const dialogId = SAMPLE_DIALOG.id; From d00d02882aaad52fb6efdea437a387b57e4835b6 Mon Sep 17 00:00:00 2001 From: Soroush Date: Thu, 13 May 2021 10:25:25 -0700 Subject: [PATCH 7/8] useResizeObserver --- .../client/src/hooks/useResizeObserver.ts | 39 +++++++++++++++++++ .../src/pages/design/VisualPanelHeader.tsx | 27 ++++++------- 2 files changed, 51 insertions(+), 15 deletions(-) create mode 100644 Composer/packages/client/src/hooks/useResizeObserver.ts diff --git a/Composer/packages/client/src/hooks/useResizeObserver.ts b/Composer/packages/client/src/hooks/useResizeObserver.ts new file mode 100644 index 0000000000..6357cdebd8 --- /dev/null +++ b/Composer/packages/client/src/hooks/useResizeObserver.ts @@ -0,0 +1,39 @@ +/* eslint-disable @typescript-eslint/ban-ts-ignore */ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import React from 'react'; + +/* + * TODO: remove ts-ignore after updating typescript to v4. + * current typescript version does not have definitions for ResizeObserver. + */ + +/** + * Observes size changes of a given element and runs the provided callback. + * @param element Element to observe size changes. + * @param resizeCallback Callback to call when resize happens. + * @param options Optional options for resize observer. + */ +export const useResizeObserver = ( + element: T | null, + // @ts-ignore + resizeCallback: (entries: ResizeObserverEntry[]) => void, + // @ts-ignore + options?: ResizeObserverOptions +) => { + // @ts-ignore + const resizeObserver = React.useRef(new ResizeObserver(resizeCallback)); + + React.useEffect(() => { + if (element) { + resizeObserver.current.observe(element, options); + } + + return () => { + if (element) { + resizeObserver.current.unobserve(element); + } + }; + }, [element]); +}; diff --git a/Composer/packages/client/src/pages/design/VisualPanelHeader.tsx b/Composer/packages/client/src/pages/design/VisualPanelHeader.tsx index 18bbf686fb..951ae1f1b2 100644 --- a/Composer/packages/client/src/pages/design/VisualPanelHeader.tsx +++ b/Composer/packages/client/src/pages/design/VisualPanelHeader.tsx @@ -17,6 +17,7 @@ import { getDialogData } from '../../utils/dialogUtil'; import { decodeDesignerPathToArrayPath } from '../../utils/convertUtils/designerPathEncoder'; import { getFocusPath } from '../../utils/navigation'; import { TreeLink } from '../../components/ProjectTree/types'; +import { useResizeObserver } from '../../hooks/useResizeObserver'; import * as pageStyles from './styles'; @@ -159,23 +160,17 @@ const defaultToggleButtonWidth = 100; const spaceBetweenContainers = 6; const VisualPanelHeader: React.FC = React.memo((props) => { const { showCode, projectId, onShowCodeClick, pluginConfig } = props; + const breadcrumbs = useBreadcrumbs(projectId, pluginConfig); + const toggleButtonContainerRef = React.useRef(null); const containerRef = React.useRef(null); + const [toggleButtonWidth, setToggleButtonWidth] = React.useState(defaultToggleButtonWidth); const [breadcrumbContainerWidth, setBreadcrumbContainerWidth] = React.useState( `calc(100% - ${toggleButtonWidth}px)` ); - // Resize observer callback to update the width of the breadcrumb container - const resizeObserverRef = React.useRef( - // @ts-ignore - new ResizeObserver((entries) => { - if (entries.length) { - const { width } = entries[0].contentRect; - setBreadcrumbContainerWidth(width - toggleButtonWidth - spaceBetweenContainers); - } - }) - ); + // Set the width of the toggle button based on its text (locale) React.useEffect(() => { if (toggleButtonContainerRef.current) { @@ -186,13 +181,15 @@ const VisualPanelHeader: React.FC = React.memo((props) = } } }, []); + // Observe width changes of the container to re-set the available width for breadcrumb container - React.useEffect(() => { - if (containerRef.current) { - resizeObserverRef.current.observe(containerRef.current); + useResizeObserver(containerRef.current, (entries) => { + if (entries.length) { + const { width } = entries[0].contentRect; + setBreadcrumbContainerWidth(width - toggleButtonWidth - spaceBetweenContainers); } - return () => resizeObserverRef.current.disconnect(); - }, []); + }); + const createBreadcrumbItem: (breadcrumb: BreadcrumbItem) => IBreadcrumbItem = (breadcrumb: BreadcrumbItem) => { return { key: breadcrumb.key, From e536b7664ed66d3f3af4bcd7eab5d9eeff16d3da Mon Sep 17 00:00:00 2001 From: Soroush Date: Thu, 13 May 2021 10:59:41 -0700 Subject: [PATCH 8/8] fix mock --- Composer/packages/client/__tests__/mocks/ResizeObserver.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Composer/packages/client/__tests__/mocks/ResizeObserver.ts b/Composer/packages/client/__tests__/mocks/ResizeObserver.ts index 78db7dfd0d..81607f4b4a 100644 --- a/Composer/packages/client/__tests__/mocks/ResizeObserver.ts +++ b/Composer/packages/client/__tests__/mocks/ResizeObserver.ts @@ -5,6 +5,9 @@ export default class ResizeObserver { observe() { // do nothing } + unobserve() { + // do nothing + } disconnect() { // do nothing }