diff --git a/docs/migration.md b/docs/migration.md index 1cfbe981c78..f4ad5866b59 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -47,7 +47,9 @@ consider additional positioning prop support on a case-by-case basis. #### @zendeskgarden/react-chrome - Removed `PRODUCT` type export. Use `IHeaderItemProps['product']` instead. +- Removed `hasFooter` prop for `Body` (no replacement needed) - The following React component types have changed: + - Removed `IBodyProps` type export. - Renamed `ICollapsibleSubNavItemProps` type export to `ISubNavCollapsibleItemProps`. - `Header.ItemIcon`: `HTMLAttributes` -> `SVGAttributes` - `Nav.ItemIcon`: `HTMLAttributes` -> `SVGAttributes` diff --git a/packages/chrome/demo/stories/ChromeStory.tsx b/packages/chrome/demo/stories/ChromeStory.tsx index 17d9af6be0e..b6462deff97 100644 --- a/packages/chrome/demo/stories/ChromeStory.tsx +++ b/packages/chrome/demo/stories/ChromeStory.tsx @@ -195,7 +195,7 @@ export const ChromeStory: Story = ({ )} )} - + {hasHeader && (
{hasLogo && ( diff --git a/packages/chrome/src/elements/body/Body.tsx b/packages/chrome/src/elements/body/Body.tsx index f45524ae1b9..24c18514ec7 100644 --- a/packages/chrome/src/elements/body/Body.tsx +++ b/packages/chrome/src/elements/body/Body.tsx @@ -5,27 +5,27 @@ * found at http://www.apache.org/licenses/LICENSE-2.0. */ -import React, { useMemo } from 'react'; -import PropTypes from 'prop-types'; -import { IBodyProps } from '../../types'; +import React, { HTMLAttributes, useMemo, useState } from 'react'; import { StyledBody } from '../../styled'; import { BodyContext } from '../../utils/useBodyContext'; /** * @extends HTMLAttributes */ -export const Body = React.forwardRef(({ hasFooter, ...props }, ref) => { - const bodyContextValue = useMemo(() => ({ hasFooter: !!hasFooter }), [hasFooter]); +export const Body = React.forwardRef>( + (props, ref) => { + const [hasFooter, setHasFooter] = useState(false); + const bodyContextValue = useMemo( + () => ({ hasFooter, setHasFooter }), + [hasFooter, setHasFooter] + ); - return ( - - - - ); -}); + return ( + + + + ); + } +); Body.displayName = 'Body'; - -Body.propTypes = { - hasFooter: PropTypes.bool -}; diff --git a/packages/chrome/src/elements/body/Content.spec.tsx b/packages/chrome/src/elements/body/Content.spec.tsx index a37546d94ce..655a5d6fdf0 100644 --- a/packages/chrome/src/elements/body/Content.spec.tsx +++ b/packages/chrome/src/elements/body/Content.spec.tsx @@ -8,12 +8,17 @@ import React from 'react'; import { render } from 'garden-test-utils'; import { Content } from './Content'; +import { Body } from './Body'; describe('Content', () => { it('passes ref to underlying DOM element', () => { const ref = React.createRef(); - const { container } = render(); + const { queryByTestId } = render( + + + + ); - expect(container.firstChild).toBe(ref.current); + expect(queryByTestId('content')).toBe(ref.current); }); }); diff --git a/packages/chrome/src/elements/body/Content.tsx b/packages/chrome/src/elements/body/Content.tsx index 1c6a2a592ce..92ca5d150b2 100644 --- a/packages/chrome/src/elements/body/Content.tsx +++ b/packages/chrome/src/elements/body/Content.tsx @@ -14,7 +14,7 @@ import { useBodyContext } from '../../utils/useBodyContext'; */ export const Content = React.forwardRef>( (props, ref) => { - const { hasFooter } = useBodyContext(); + const { hasFooter } = useBodyContext() || {}; return ; } diff --git a/packages/chrome/src/elements/footer/Footer.tsx b/packages/chrome/src/elements/footer/Footer.tsx index 87c13745748..9c9e7d1d048 100644 --- a/packages/chrome/src/elements/footer/Footer.tsx +++ b/packages/chrome/src/elements/footer/Footer.tsx @@ -5,15 +5,32 @@ * found at http://www.apache.org/licenses/LICENSE-2.0. */ -import React, { HTMLAttributes } from 'react'; +import React, { HTMLAttributes, useEffect } from 'react'; import { StyledFooter } from '../../styled'; +import { useBodyContext } from '../../utils/useBodyContext'; import { FooterItem } from './FooterItem'; /** * @extends HTMLAttributes */ export const FooterComponent = React.forwardRef>( - (props, ref) => + (props, ref) => { + const { hasFooter, setHasFooter } = useBodyContext() || {}; + + useEffect(() => { + if (!hasFooter && setHasFooter) { + setHasFooter(true); + } + + return () => { + if (hasFooter && setHasFooter) { + setHasFooter(false); + } + }; + }, [hasFooter, setHasFooter]); + + return ; + } ); FooterComponent.displayName = 'Footer'; diff --git a/packages/chrome/src/index.ts b/packages/chrome/src/index.ts index c4c63806219..6b9a73b4687 100644 --- a/packages/chrome/src/index.ts +++ b/packages/chrome/src/index.ts @@ -33,7 +33,6 @@ export { PRODUCTS, type IChromeProps, type ISkipNavProps, - type IBodyProps, type IHeaderProps, type IHeaderItemProps, type IHeaderItemTextProps, diff --git a/packages/chrome/src/types/index.ts b/packages/chrome/src/types/index.ts index 462a0c89525..e3b19a0c713 100644 --- a/packages/chrome/src/types/index.ts +++ b/packages/chrome/src/types/index.ts @@ -35,11 +35,6 @@ export interface ISkipNavProps extends AnchorHTMLAttributes { zIndex?: number; } -export interface IBodyProps extends HTMLAttributes { - /** Adjusts the body content height to allow space for a footer component */ - hasFooter?: boolean; -} - export interface IHeaderProps extends HTMLAttributes { /** Displays logo for standlone usage */ isStandalone?: boolean; diff --git a/packages/chrome/src/utils/useBodyContext.ts b/packages/chrome/src/utils/useBodyContext.ts index e18d5f1aa64..7da467981a4 100644 --- a/packages/chrome/src/utils/useBodyContext.ts +++ b/packages/chrome/src/utils/useBodyContext.ts @@ -9,11 +9,10 @@ import React, { useContext } from 'react'; interface IBodyContext { hasFooter: boolean; + setHasFooter: (footerPresent: boolean) => void; } -export const BodyContext = React.createContext({ - hasFooter: true -}); +export const BodyContext = React.createContext(undefined); export const useBodyContext = () => { return useContext(BodyContext);