Skip to content

feat(dialog): improves behaviour of dialogs and provides more option #277

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .storybook/preview-head.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<style>
#docs-root {
isolation: isolate;
}
</style>
22 changes: 18 additions & 4 deletions src/components/Backdrop/Backdrop.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Content, Overlay, Root } from '@radix-ui/react-dialog'
import React, { FC } from 'react'
import { Content, Overlay, Portal, Root } from '@radix-ui/react-dialog'
import React, { ComponentProps, FC } from 'react'
import { CSS, styled } from '../../stitches.config'
import { ConditionalWrapper } from '../../utils'
import { overlayAnimationStyles, overlayStyles } from '../Overlay'

const StyledOverlay = styled(Overlay, overlayStyles, overlayAnimationStyles, {
Expand Down Expand Up @@ -33,6 +34,10 @@ type BackdropProps = React.ComponentProps<typeof Root> & {
overlayCss?: CSS
/** Modify the default styling of the content wrapper */
contentCss?: CSS
/** By default, portals your overlay and content parts into the body, set false to add at dom location. */
portalled?: boolean
/** Specify a container element to portal the content into. */
container?: ComponentProps<typeof Portal>['container']
}

/**
Expand All @@ -45,13 +50,22 @@ type BackdropProps = React.ComponentProps<typeof Root> & {
export const Backdrop: FC<BackdropProps> = ({
overlayCss,
contentCss,
container,
portalled = true,
children,
...props
}) => {
return (
<Root {...props}>
<StyledOverlay css={overlayCss} />
<StyledContent css={contentCss}>{children}</StyledContent>
<ConditionalWrapper
condition={portalled}
wrapper={(child) => <Portal container={container}>{child}</Portal>}
>
<>
<StyledOverlay css={overlayCss} />
<StyledContent css={contentCss}>{children}</StyledContent>
</>
</ConditionalWrapper>
</Root>
)
}
25 changes: 22 additions & 3 deletions src/components/ComponentsProvider/ComponentsProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { FC, PropsWithChildren } from 'react'
import { CSSProps, styled } from '../../stitches.config'
import { ConditionalWrapper } from '../../utils'
import { ThemeProvider, ThemeProviderProps } from '../ThemeProvider'
import { ToastProvider, ToastViewport } from '../Toast'
Expand Down Expand Up @@ -40,7 +41,15 @@ export type ComponentsProviderProps = {
* Toast viewport configuration options
*/
viewport?: false | ToastViewportPropsWithoutChildren
}
/**
* By default the childre are put into their own stacking context to better separate the content from the portalled dialog elements. Set false to turn this off and controll it yourself.
*/
isolated?: boolean
} & CSSProps

const Isolate = styled('div', {
variants: { isolated: { false: {}, true: { isolation: 'isolate' } } },
})

/**
* The `ComponentsProvider` should wrap you application.
Expand All @@ -53,7 +62,15 @@ export type ComponentsProviderProps = {
*/
export const ComponentsProvider: FC<
PropsWithChildren<ComponentsProviderProps>
> = ({ theme = {}, tooltip = {}, toast = {}, viewport = {}, children }) => (
> = ({
theme = {},
tooltip = {},
toast = {},
viewport = {},
css,
isolated = true,
children,
}) => (
<ConditionalWrapper
condition={toast}
wrapper={(wrappedChildren) => (
Expand All @@ -73,7 +90,9 @@ export const ComponentsProvider: FC<
)}
>
<>
{children}
<Isolate css={css as any} isolated={isolated}>
{children}
</Isolate>
{viewport && <ToastViewport {...viewport} />}
</>
</ConditionalWrapper>
Expand Down
65 changes: 39 additions & 26 deletions src/components/ConfirmDialog/ConfirmDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import {
Content,
Description,
Overlay,
Portal,
Root,
Title,
Trigger,
} from '@radix-ui/react-alert-dialog'
import React, { ComponentProps, ElementRef, FC, forwardRef } from 'react'
import type { CSSProps } from '../../stitches.config'
import { CSS, styled } from '../../stitches.config'
import { ConditionalWrapper } from '../../utils'
import { Button } from '../Button'
import { Heading } from '../Heading'
import { overlayAnimationStyles, overlayStyles } from '../Overlay'
Expand Down Expand Up @@ -56,11 +58,6 @@ export const StyledContent = styled(
overlayAnimationStyles
)

type ConfirmDialogProps = ComponentProps<typeof Root> & {
/** Modify the default styling of the overlay */
overlayCss?: CSS
}

/**
* The `ConfirmDialog` component can be used get confirmation of an action from the user.
* This is done by isolating the user from the main window by overlaying
Expand All @@ -80,39 +77,55 @@ type ConfirmDialogProps = ComponentProps<typeof Root> & {
*
* Based on [Radix Alert Dialog](https://radix-ui.com/primitives/docs/components/alert-dialog).
*/
export const ConfirmDialog: FC<ConfirmDialogProps> = ({
children,
overlayCss,
...props
}) => {
return (
<Root {...props}>
<StyledOverlay css={overlayCss} />
{children}
</Root>
)
}
export const ConfirmDialog = Root

type ConfirmDialogContentProps = ComponentProps<typeof StyledContent> &
CSSProps & {
/** Add a title to the content. */
title?: string
/** Add a description to the content. */
description?: string
/** Modify the default styling of the overlay */
overlayCss?: CSS
/** By default, portals your overlay and content parts into the body, set false to add at dom location. */
portalled?: boolean
/** Specify a container element to portal the content into. */
container?: ComponentProps<typeof Portal>['container']
}

export const ConfirmDialogContent = forwardRef<
ElementRef<typeof StyledContent>,
ConfirmDialogContentProps
>(({ title, description, children, ...props }, forwardedRef) => (
<StyledContent {...props} ref={forwardedRef}>
{title && <ConfirmDialogTitle>{title}</ConfirmDialogTitle>}
{description && (
<ConfirmDialogDescription>{description}</ConfirmDialogDescription>
)}
{children}
</StyledContent>
))
>(
(
{
title,
description,
overlayCss,
container,
portalled = true,
children,
...props
},
forwardedRef
) => (
<ConditionalWrapper
condition={portalled}
wrapper={(child) => <Portal container={container}>{child}</Portal>}
>
<>
<StyledOverlay css={overlayCss} />
<StyledContent {...props} ref={forwardedRef}>
{title && <ConfirmDialogTitle>{title}</ConfirmDialogTitle>}
{description && (
<ConfirmDialogDescription>{description}</ConfirmDialogDescription>
)}
{children}
</StyledContent>
</>
</ConditionalWrapper>
)
)
ConfirmDialogContent.toString = () => `.${StyledContent.className}`

export const ConfirmDialogTrigger = forwardRef<
Expand Down
Loading