From a907d620fa771fc4a4c8f71e4adabdb2839a3446 Mon Sep 17 00:00:00 2001 From: Eric Peterson Date: Fri, 20 May 2022 17:28:14 +0200 Subject: [PATCH] Provide a deprecation path for affected sidebar contexts. Signed-off-by: Eric Peterson --- packages/core-components/api-report.md | 6 +++ .../layout/Sidebar/SidebarContext.test.tsx | 41 +++++++++++++---- .../src/layout/Sidebar/SidebarContext.tsx | 34 +++++++++----- .../Sidebar/SidebarPinStateContext.test.tsx | 45 ++++++++++++++----- .../layout/Sidebar/SidebarPinStateContext.tsx | 35 ++++++++++----- .../src/layout/Sidebar/index.ts | 7 ++- 6 files changed, 128 insertions(+), 40 deletions(-) diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index d162e7a714..33db173fcf 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -902,6 +902,9 @@ export const sidebarConfig: { mobileSidebarHeight: number; }; +// @public @deprecated +export const SidebarContext: React_2.Context; + // @public export const SidebarContextProvider: ({ children, @@ -1005,6 +1008,9 @@ export type SidebarPageProps = { children?: React_2.ReactNode; }; +// @public @deprecated +export const SidebarPinStateContext: React_2.Context; + // @public export const SidebarPinStateContextProvider: ({ children, diff --git a/packages/core-components/src/layout/Sidebar/SidebarContext.test.tsx b/packages/core-components/src/layout/Sidebar/SidebarContext.test.tsx index d14e035433..43a18851d7 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarContext.test.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarContext.test.tsx @@ -13,21 +13,45 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, { ReactNode } from 'react'; -import { renderInTestApp } from '@backstage/test-utils'; -import { screen, waitFor } from '@testing-library/react'; +import React, { ReactNode, useContext } from 'react'; +import { renderWithEffects } from '@backstage/test-utils'; +import { waitFor } from '@testing-library/react'; import { renderHook, act } from '@testing-library/react-hooks'; -import { SidebarContextProvider, useSidebar } from './SidebarContext'; +import { + LegacySidebarContext, + SidebarContextProvider, + useSidebar, +} from './SidebarContext'; describe('SidebarContext', () => { describe('SidebarContextProvider', () => { it('should render children', async () => { - await renderInTestApp( + const { findByText } = await renderWithEffects( {} }}> Child , ); - expect(await screen.findByText('Child')).toBeInTheDocument(); + expect(await findByText('Child')).toBeInTheDocument(); + }); + + it('should provide the legacy context as well, for now', async () => { + const LegacyContextSpy = () => { + const { isOpen } = useContext(LegacySidebarContext); + return <>{String(isOpen)}; + }; + + const { findByText } = await renderWithEffects( + {}, + }} + > + + , + ); + + expect(await findByText('true')).toBeInTheDocument(); }); }); @@ -52,15 +76,16 @@ describe('SidebarContext', () => { {children} ); - const { result } = renderHook(() => useSidebar(), { wrapper }); + const { result, rerender } = renderHook(() => useSidebar(), { wrapper }); expect(result.current.isOpen).toBe(true); act(() => { result.current.setOpen(false); + rerender(); }); - waitFor(() => { + await waitFor(() => { expect(result.current.isOpen).toBe(false); }); }); diff --git a/packages/core-components/src/layout/Sidebar/SidebarContext.tsx b/packages/core-components/src/layout/Sidebar/SidebarContext.tsx index c91be85928..4e47b6040a 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarContext.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarContext.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import React, { ReactNode, useContext } from 'react'; +import React, { createContext, ReactNode, useContext } from 'react'; import { createVersionedContext, createVersionedValueMap, @@ -30,6 +30,21 @@ export type SidebarContextType = { setOpen: (open: boolean) => void; }; +const defaultSidebarContext = { + isOpen: false, + setOpen: () => {}, +}; + +/** + * Context whether the `Sidebar` is open + * + * @public @deprecated + * Use `` + `useSidebar()` instead. + */ +export const LegacySidebarContext = createContext( + defaultSidebarContext, +); + const VersionedSidebarContext = createVersionedContext<{ 1: SidebarContextType; }>('sidebar-context'); @@ -46,11 +61,13 @@ export const SidebarContextProvider = ({ children: ReactNode; value: SidebarContextType; }) => ( - - {children} - + + + {children} + + ); /** @@ -63,10 +80,7 @@ export const useSidebar = (): SidebarContextType => { // Invoked from outside a SidbarContextProvider, return a default value. if (versionedSidebarContext === undefined) { - return { - isOpen: false, - setOpen: () => {}, - }; + return defaultSidebarContext; } const sidebarContext = versionedSidebarContext.atVersion(1); diff --git a/packages/core-components/src/layout/Sidebar/SidebarPinStateContext.test.tsx b/packages/core-components/src/layout/Sidebar/SidebarPinStateContext.test.tsx index cc83a846e3..d8bc054e4a 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarPinStateContext.test.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarPinStateContext.test.tsx @@ -13,19 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, { ReactNode } from 'react'; -import { renderInTestApp } from '@backstage/test-utils'; -import { screen, waitFor } from '@testing-library/react'; +import React, { ReactNode, useContext } from 'react'; +import { renderWithEffects } from '@backstage/test-utils'; +import { waitFor } from '@testing-library/react'; import { renderHook, act } from '@testing-library/react-hooks'; import { + LegacySidebarPinStateContext, SidebarPinStateContextProvider, useSidebarPinState, } from './SidebarPinStateContext'; -describe('SidebarContext', () => { - describe('SidebarContextProvider', () => { +describe('SidebarPinStateContext', () => { + describe('SidebarPinStateContextProvider', () => { it('should render children', async () => { - await renderInTestApp( + const { findByText } = await renderWithEffects( { Child , ); - expect(await screen.findByText('Child')).toBeInTheDocument(); + expect(await findByText('Child')).toBeInTheDocument(); + }); + + it('should provide the legacy context as well, for now', async () => { + const LegacyContextSpy = () => { + const { isMobile } = useContext(LegacySidebarPinStateContext); + return <>{String(isMobile)}; + }; + + const { findByText } = await renderWithEffects( + {}, + }} + > + + , + ); + + expect(await findByText('true')).toBeInTheDocument(); }); }); - describe('useSidebar', () => { + describe('useSidebarPinState', () => { it('does not need to be invoked within provider', () => { const { result } = renderHook(() => useSidebarPinState()); expect(result.current.isPinned).toBe(true); @@ -63,15 +85,18 @@ describe('SidebarContext', () => { {children} ); - const { result } = renderHook(() => useSidebarPinState(), { wrapper }); + const { result, rerender } = renderHook(() => useSidebarPinState(), { + wrapper, + }); expect(result.current.isPinned).toBe(true); act(() => { result.current.toggleSidebarPinState(); + rerender(); }); - waitFor(() => { + await waitFor(() => { expect(result.current.isPinned).toBe(false); }); }); diff --git a/packages/core-components/src/layout/Sidebar/SidebarPinStateContext.tsx b/packages/core-components/src/layout/Sidebar/SidebarPinStateContext.tsx index 709973e064..ec38884890 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarPinStateContext.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarPinStateContext.tsx @@ -17,7 +17,7 @@ import { createVersionedContext, createVersionedValueMap, } from '@backstage/version-bridge'; -import React, { ReactNode, useContext } from 'react'; +import React, { createContext, ReactNode, useContext } from 'react'; /** * Type of `SidebarPinStateContext` @@ -30,6 +30,21 @@ export type SidebarPinStateContextType = { isMobile?: boolean; }; +const defaultSidebarPinStateContext = { + isPinned: true, + toggleSidebarPinState: () => {}, + isMobile: false, +}; + +/** + * Contains the state on how the `Sidebar` is rendered + * + * @public @deprecated + * Use `` + `useSidebarPinState()` instead. + */ +export const LegacySidebarPinStateContext = + createContext(defaultSidebarPinStateContext); + const VersionedSidebarPinStateContext = createVersionedContext<{ 1: SidebarPinStateContextType; }>('sidebar-pin-state-context'); @@ -46,11 +61,13 @@ export const SidebarPinStateContextProvider = ({ children: ReactNode; value: SidebarPinStateContextType; }) => ( - - {children} - + + + {children} + + ); /** @@ -63,11 +80,7 @@ export const useSidebarPinState = (): SidebarPinStateContextType => { // Invoked from outside a SidebarPinStateContextProvider: default value. if (versionedSidebarContext === undefined) { - return { - isPinned: true, - toggleSidebarPinState: () => {}, - isMobile: false, - }; + return defaultSidebarPinStateContext; } const sidebarContext = versionedSidebarContext.atVersion(1); diff --git a/packages/core-components/src/layout/Sidebar/index.ts b/packages/core-components/src/layout/Sidebar/index.ts index e041ecc730..06681ded52 100644 --- a/packages/core-components/src/layout/Sidebar/index.ts +++ b/packages/core-components/src/layout/Sidebar/index.ts @@ -48,9 +48,14 @@ export { IntroCard, SidebarIntro } from './Intro'; export type { SidebarIntroClassKey } from './Intro'; export { SIDEBAR_INTRO_LOCAL_STORAGE, sidebarConfig } from './config'; export type { SidebarOptions, SubmenuOptions } from './config'; -export { SidebarContextProvider, useSidebar } from './SidebarContext'; +export { + LegacySidebarContext as SidebarContext, + SidebarContextProvider, + useSidebar, +} from './SidebarContext'; export type { SidebarContextType } from './SidebarContext'; export { + LegacySidebarPinStateContext as SidebarPinStateContext, SidebarPinStateContextProvider, useSidebarPinState, } from './SidebarPinStateContext';