diff --git a/.changeset/sweet-results-smell.md b/.changeset/sweet-results-smell.md new file mode 100644 index 00000000000..63155480051 --- /dev/null +++ b/.changeset/sweet-results-smell.md @@ -0,0 +1,5 @@ +--- +'@primer/react': major +--- + +Remove support for `sx` from the Dialog component and sub-components diff --git a/e2e/components/Dialog.test.ts b/e2e/components/Dialog.test.ts index 84365d50f31..f622e770b35 100644 --- a/e2e/components/Dialog.test.ts +++ b/e2e/components/Dialog.test.ts @@ -27,18 +27,6 @@ const stories = [ title: 'Position sidesheet', id: 'components-dialog-features--side-sheet', }, - { - title: 'Dev: With Css', - id: 'components-dialog-dev--with-css', - }, - { - title: 'Dev: With Sx', - id: 'components-dialog-dev--with-sx', - }, - { - title: 'Dev: With Sx And Css', - id: 'components-dialog-dev--with-sx-and-css', - }, ] as const test.describe('Dialog', () => { diff --git a/packages/react/src/Dialog/Dialog.dev.stories.tsx b/packages/react/src/Dialog/Dialog.dev.stories.tsx index abf3f391772..2cb2a5134e1 100644 --- a/packages/react/src/Dialog/Dialog.dev.stories.tsx +++ b/packages/react/src/Dialog/Dialog.dev.stories.tsx @@ -87,113 +87,6 @@ export const WithCss = ({width, height, subtitle}: DialogStoryProps) => { ) } -function SxHeader({title, subtitle, dialogLabelId}: React.PropsWithChildren) { - if (typeof title === 'string' && typeof subtitle === 'string') { - return ( - -

{title.toUpperCase()}

-
- ) - } - return null -} -function SxBody({children}: React.PropsWithChildren) { - return {children} -} -function SxFooter({footerButtons}: React.PropsWithChildren) { - return ( - - {footerButtons ? : null} - - ) -} -export const WithSx = ({width, height, subtitle}: DialogStoryProps) => { - const [isOpen, setIsOpen] = useState(true) - const onDialogClose = useCallback(() => setIsOpen(false), []) - return ( - <> - - {isOpen && ( - - {lipsum} - - )} - - ) -} - -function SxAndCssHeader({ - title, - subtitle, - dialogLabelId, -}: React.PropsWithChildren) { - if (typeof title === 'string' && typeof subtitle === 'string') { - return ( - -

{title.toUpperCase()}

-
- ) - } - return null -} -function SxAndCssBody({children}: React.PropsWithChildren) { - return ( - - {children} - - ) -} -function SxAndCssFooter({footerButtons}: React.PropsWithChildren) { - return ( - - {footerButtons ? : null} - - ) -} -export const WithSxAndCss = ({width, height, subtitle}: DialogStoryProps) => { - const [isOpen, setIsOpen] = useState(true) - const onDialogClose = useCallback(() => setIsOpen(false), []) - return ( - <> - - {isOpen && ( - - {lipsum} - - )} - - ) -} - export const WithScrollBody = () => { const [isOpen, setIsOpen] = useState(false) const buttonRef = useRef(null) diff --git a/packages/react/src/Dialog/Dialog.features.stories.tsx b/packages/react/src/Dialog/Dialog.features.stories.tsx index 01a38d8e1f2..5f67b70948d 100644 --- a/packages/react/src/Dialog/Dialog.features.stories.tsx +++ b/packages/react/src/Dialog/Dialog.features.stories.tsx @@ -79,11 +79,11 @@ function CustomHeader({ return null } function CustomBody({children}: React.PropsWithChildren) { - return {children} + return {children} } function CustomFooter({footerButtons}: React.PropsWithChildren) { return ( - + {footerButtons ? : null} ) diff --git a/packages/react/src/Dialog/Dialog.module.css b/packages/react/src/Dialog/Dialog.module.css index fb773a6b1b4..d750854c158 100644 --- a/packages/react/src/Dialog/Dialog.module.css +++ b/packages/react/src/Dialog/Dialog.module.css @@ -270,6 +270,18 @@ Add a border between the body and footer if: flex-shrink: 0; } +.HeaderInner { + display: flex; +} + +.HeaderContent { + display: flex; + padding-inline: var(--base-size-8); + padding-block: var(--base-size-6); + flex-direction: column; + flex-grow: 1; +} + .Title { margin: 0; /* override default margin */ font-size: var(--text-body-size-medium); diff --git a/packages/react/src/Dialog/Dialog.tsx b/packages/react/src/Dialog/Dialog.tsx index 14f6151ede9..9bfacac1238 100644 --- a/packages/react/src/Dialog/Dialog.tsx +++ b/packages/react/src/Dialog/Dialog.tsx @@ -1,10 +1,8 @@ import React, {useCallback, useEffect, useRef, useState, type SyntheticEvent} from 'react' import type {ButtonProps} from '../Button' import {Button, IconButton} from '../Button' -import Box from '../Box' import {useOnEscapePress, useProvidedRefOrCreate} from '../hooks' import {useFocusTrap} from '../hooks/useFocusTrap' -import type {SxProp} from '../sx' import {XIcon} from '@primer/octicons-react' import {useFocusZone} from '../hooks/useFocusZone' import {FocusKeys} from '@primer/behaviors' @@ -17,7 +15,6 @@ import type {ForwardRefComponent as PolymorphicForwardRefComponent} from '../uti import classes from './Dialog.module.css' import {clsx} from 'clsx' -import {BoxWithFallback} from '../internal/components/BoxWithFallback' /* Dialog Version 2 */ @@ -52,7 +49,7 @@ export type DialogButtonProps = Omit & { /** * Props to customize the rendering of the Dialog. */ -export interface DialogProps extends SxProp { +export interface DialogProps { /** * Title of the Dialog. Also serves as the aria-label for this Dialog. */ @@ -198,13 +195,13 @@ const DefaultHeader: React.FC> = ({ }, [onClose]) return ( - - +
+
{title ?? 'Dialog'} {subtitle && {subtitle}} - +
- +
) } @@ -245,7 +242,6 @@ const _Dialog = React.forwardRef - - {header} @@ -339,50 +332,50 @@ const _Dialog = React.forwardRef {footer} - - + + ) }) _Dialog.displayName = 'Dialog' -type StyledHeaderProps = React.ComponentProps<'div'> & SxProp +type StyledHeaderProps = React.ComponentProps<'div'> -const Header = React.forwardRef(function Header({className, ...rest}, forwardRef) { - return +const Header = React.forwardRef(function Header({className, ...rest}, forwardRef) { + return
}) Header.displayName = 'Dialog.Header' -type StyledTitleProps = React.ComponentProps<'h1'> & SxProp +type StyledTitleProps = React.ComponentProps<'h1'> -const Title = React.forwardRef(function Title({className, ...rest}, forwardRef) { - return +const Title = React.forwardRef(function Title({className, ...rest}, forwardRef) { + return

}) Title.displayName = 'Dialog.Title' -type StyledSubtitleProps = React.ComponentProps<'h2'> & SxProp +type StyledSubtitleProps = React.ComponentProps<'h2'> -const Subtitle = React.forwardRef(function Subtitle( +const Subtitle = React.forwardRef(function Subtitle( {className, ...rest}, forwardRef, ) { - return + return

}) Subtitle.displayName = 'Dialog.Subtitle' -type StyledBodyProps = React.ComponentProps<'div'> & SxProp +type StyledBodyProps = React.ComponentProps<'div'> -const Body = React.forwardRef(function Body({className, ...rest}, forwardRef) { - return +const Body = React.forwardRef(function Body({className, ...rest}, forwardRef) { + return
}) as PolymorphicForwardRefComponent<'div', StyledBodyProps> Body.displayName = 'Dialog.Body' -type StyledFooterProps = React.ComponentProps<'div'> & SxProp +type StyledFooterProps = React.ComponentProps<'div'> -const Footer = React.forwardRef(function Footer({className, ...rest}, forwardRef) { - return +const Footer = React.forwardRef(function Footer({className, ...rest}, forwardRef) { + return
}) Footer.displayName = 'Dialog.Footer' diff --git a/packages/styled-react/src/__tests__/primer-react.browser.test.tsx b/packages/styled-react/src/__tests__/primer-react.browser.test.tsx index 89eeeb65764..f86970ef32f 100644 --- a/packages/styled-react/src/__tests__/primer-react.browser.test.tsx +++ b/packages/styled-react/src/__tests__/primer-react.browser.test.tsx @@ -155,6 +155,33 @@ describe('@primer/react', () => { expect(window.getComputedStyle(screen.getByRole('dialog')).backgroundColor).toBe('rgb(255, 0, 0)') }) + test('Dialog.Header supports `sx` prop', () => { + render( + {}} + renderHeader={() => } + />, + ) + expect(window.getComputedStyle(screen.getByTestId('component')).backgroundColor).toBe('rgb(255, 0, 0)') + }) + + test('Dialog.Body supports `sx` prop', () => { + render( + {}} renderBody={() => } />, + ) + expect(window.getComputedStyle(screen.getByTestId('component')).backgroundColor).toBe('rgb(255, 0, 0)') + }) + + test('Dialog.Footer supports `sx` prop', () => { + render( + {}} + renderFooter={() => } + />, + ) + expect(window.getComputedStyle(screen.getByTestId('component')).backgroundColor).toBe('rgb(255, 0, 0)') + }) + test('Flash supports `sx` prop', () => { render() expect(window.getComputedStyle(screen.getByTestId('component')).backgroundColor).toBe('rgb(255, 0, 0)') diff --git a/packages/styled-react/src/components/Dialog.tsx b/packages/styled-react/src/components/Dialog.tsx new file mode 100644 index 00000000000..827be448318 --- /dev/null +++ b/packages/styled-react/src/components/Dialog.tsx @@ -0,0 +1,41 @@ +import {Dialog as PrimerDialog} from '@primer/react' +import type {DialogProps as PrimerDialogProps} from '@primer/react' +import {Box} from './Box' +import type {SxProp} from '../sx' +import {forwardRef, type ComponentPropsWithoutRef, type PropsWithChildren} from 'react' + +type DialogProps = PropsWithChildren & SxProp + +const DialogImpl = forwardRef(function Dialog(props, ref) { + // @ts-expect-error - PrimerDialog is not recognized as a valid component type + return +}) + +type DialogHeaderProps = ComponentPropsWithoutRef<'div'> & SxProp + +const DialogHeader = forwardRef(function DialogHeader(props, ref) { + return +}) + +type StyledBodyProps = React.ComponentProps<'div'> & SxProp + +const DialogBody = forwardRef(function DialogBody(props, ref) { + // @ts-expect-error - PrimerDialog.Body is not recognized as a valid component type + return +}) + +type StyledFooterProps = React.ComponentProps<'div'> & SxProp + +const DialogFooter = forwardRef(function DialogFooter(props, ref) { + return +}) + +const Dialog = Object.assign(DialogImpl, { + Buttons: PrimerDialog.Buttons, + Header: DialogHeader, + Body: DialogBody, + Footer: DialogFooter, +}) + +export {Dialog} +export type {DialogProps} diff --git a/packages/styled-react/src/experimental.tsx b/packages/styled-react/src/experimental.tsx index 7b1764bbcb9..84f0becab80 100644 --- a/packages/styled-react/src/experimental.tsx +++ b/packages/styled-react/src/experimental.tsx @@ -1,7 +1,8 @@ +export {Dialog, type DialogProps} from './components/Dialog' export { PageHeader, type PageHeaderProps, type PageHeaderActionsProps, type PageHeaderTitleProps, } from './components/PageHeader' -export {Dialog, Table, Tooltip, UnderlinePanels} from '@primer/react/experimental' +export {Table, Tooltip, UnderlinePanels} from '@primer/react/experimental' diff --git a/packages/styled-react/src/index.tsx b/packages/styled-react/src/index.tsx index 8be52072298..13a6dcbddae 100644 --- a/packages/styled-react/src/index.tsx +++ b/packages/styled-react/src/index.tsx @@ -8,7 +8,6 @@ export {Button} from '@primer/react' export {CheckboxGroup} from '@primer/react' export {CircleBadge} from '@primer/react' export {Details} from '@primer/react' -export {Dialog} from '@primer/react' export {FormControl} from '@primer/react' export {Heading} from '@primer/react' export {IconButton} from '@primer/react' @@ -37,6 +36,7 @@ export {useTheme} from '@primer/react' export {Checkbox, type CheckboxProps} from './components/Checkbox' export {CounterLabel, type CounterLabelProps} from './components/CounterLabel' +export {Dialog, type DialogProps} from './components/Dialog' export {Flash} from './components/Flash' export {Header, type HeaderProps} from './components/Header' export {LinkButton, type LinkButtonProps} from './components/LinkButton'