Skip to content

Commit f7a6cfc

Browse files
author
Luke Bowerman
authored
Dialog clean-up Phase III (#1108)
* Deprecate Drawer * Rename Modal* to Dialog* (externally visible) * Rename ModalPortal to just Portal * Cleaning up some more
1 parent f38023e commit f7a6cfc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+776
-1173
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717

1818
### Changed
1919

20+
- Deprecate use of `Modal` term throughout code base
2021
- `ModalPortal` is now `Portal`
2122
- `Modal*` has moved to `Dialog*`
2223
- `ModalContext` is now `DialogContext`
@@ -51,6 +52,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5152

5253
### Removed
5354

55+
- `ModalHeader` no longer supports `headerIcon`
5456
- `Drawer` no longer available
5557
- `ComboboxMultiOption` prop `hideCheckMark` (instead use `indicator={false}`)
5658
- `CustomizableAttributes` are no longer supported

packages/components/src/Dialog/ModalBackdrop.tsx renamed to packages/components/src/Dialog/Backdrop.tsx

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,10 @@
2525
*/
2626

2727
import { CompatibleHTMLProps, reset } from '@looker/design-tokens'
28-
import {
29-
OpacityProps,
30-
// opacity,
31-
BackgroundColorProps,
32-
// backgroundColor,
33-
color,
34-
} from 'styled-system'
28+
import { OpacityProps, BackgroundColorProps, color } from 'styled-system'
3529
import styled, { CSSObject } from 'styled-components'
3630

37-
export interface ModalBackdropProps
31+
export interface BackdropProps
3832
extends CompatibleHTMLProps<HTMLDivElement>,
3933
BackgroundColorProps,
4034
OpacityProps {
@@ -44,9 +38,9 @@ export interface ModalBackdropProps
4438

4539
// Backdrop styles are applied here (rather than using the inline `style={...}` prop) to ensure that
4640
// transitions will still apply to backdrop
47-
export const ModalBackdrop = styled.div.attrs((props: ModalBackdropProps) => ({
41+
export const Backdrop = styled.div.attrs((props: BackdropProps) => ({
4842
backgroundColor: props.visible ? props.backgroundColor : 'transparent',
49-
}))<ModalBackdropProps>`
43+
}))<BackdropProps>`
5044
${reset}
5145
${color}
5246
@@ -67,7 +61,7 @@ export const ModalBackdrop = styled.div.attrs((props: ModalBackdropProps) => ({
6761
}
6862
`
6963

70-
ModalBackdrop.defaultProps = {
64+
Backdrop.defaultProps = {
7165
backgroundColor: 'ui2',
7266
opacity: 0.6,
7367
visible: true,

packages/components/src/Dialog/Confirm/ConfirmLayout.tsx

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
*/
2626
import React, { FC, ReactElement } from 'react'
2727
import { ButtonProps } from '../../Button'
28-
import { IconProps } from '../../Icon'
2928
import { Paragraph } from '../../Text'
3029
import { DialogContent, DialogFooter, DialogHeader } from '../Layout'
3130

@@ -34,12 +33,9 @@ interface ConfirmLayoutProps {
3433
* Header content
3534
*/
3635
title: string
36+
3737
/**
38-
* Optional icon to display next to the title
39-
*/
40-
titleIcon?: ReactElement<IconProps>
41-
/**
42-
* Primary modal content
38+
* Primary dialog content
4339
*/
4440
message: ReactElement | string
4541
/**
@@ -57,13 +53,10 @@ export const ConfirmLayout: FC<ConfirmLayoutProps> = ({
5753
primaryButton,
5854
message,
5955
title,
60-
titleIcon = undefined,
6156
}) => {
6257
return (
6358
<>
64-
<DialogHeader hideClose headerIcon={titleIcon}>
65-
{title}
66-
</DialogHeader>
59+
<DialogHeader hideClose>{title}</DialogHeader>
6760
<DialogContent innerProps={{ py: 'none' }}>
6861
{typeof message === 'string' ? (
6962
<Paragraph breakword>{message}</Paragraph>

packages/components/src/Dialog/Confirm/ConfirmationDialog.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,12 @@
2727
import React, { FC, useCallback, ReactElement } from 'react'
2828
import { StatefulColor } from '@looker/design-tokens'
2929
import { Button, ButtonTransparent } from '../../Button'
30-
import { ManagedModalProps } from '../Modal'
31-
import { Dialog } from '../Dialog'
30+
import { Dialog, DialogProps } from '../Dialog'
3231
import { ConfirmLayout } from './ConfirmLayout'
3332

3433
export type ConfirmationCallback = (close: () => void) => void
3534

36-
export interface ConfirmationProps extends ManagedModalProps {
35+
export interface ConfirmationProps extends DialogProps {
3736
/**
3837
* Cancel button text
3938
* @default 'Cancel'
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
3+
MIT License
4+
5+
Copyright (c) 2020 Looker Data Sciences, Inc.
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy
8+
of this software and associated documentation files (the "Software"), to deal
9+
in the Software without restriction, including without limitation the rights
10+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
copies of the Software, and to permit persons to whom the Software is
12+
furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included in all
15+
copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
SOFTWARE.
24+
25+
*/
26+
27+
import 'jest-styled-components'
28+
import React from 'react'
29+
import {
30+
assertSnapshotShallow,
31+
mountWithTheme,
32+
} from '@looker/components-test-utils'
33+
import { Portal } from '../Portal'
34+
import { Backdrop } from './Backdrop'
35+
import { Dialog } from './Dialog'
36+
import { DialogManager } from './DialogManager'
37+
38+
const simpleContent = (
39+
<div>
40+
simple content
41+
<button>Done</button>
42+
</div>
43+
)
44+
45+
describe('Dialog', () => {
46+
test('Active', () => {
47+
assertSnapshotShallow(<Dialog isOpen>{simpleContent}</Dialog>)
48+
})
49+
50+
test('Verify initial state', () => {
51+
const dialog = mountWithTheme(<Dialog>{simpleContent}</Dialog>)
52+
53+
expect(dialog.find(Portal).exists()).toEqual(false)
54+
expect(dialog.contains(simpleContent)).toBeFalsy()
55+
})
56+
57+
test('Verify "open" prop', () => {
58+
const dialog = mountWithTheme(<Dialog isOpen>{simpleContent}</Dialog>)
59+
60+
expect(dialog.find(Portal).exists()).toEqual(true)
61+
expect(dialog.contains(simpleContent)).toBeTruthy()
62+
})
63+
64+
describe('Dialog styled', () => {
65+
const dialog = mountWithTheme(
66+
<Dialog
67+
isOpen
68+
backdrop={{ backgroundColor: 'pink' }}
69+
surfaceStyles={{ backgroundColor: 'purple' }}
70+
>
71+
{simpleContent}
72+
</Dialog>
73+
)
74+
75+
test('Dialog applies the backdrop styles', () => {
76+
const backdrop = dialog.find(Backdrop)
77+
78+
expect(backdrop.exists()).toBeTruthy()
79+
80+
expect(backdrop.props().style).toEqual({ backgroundColor: 'pink' })
81+
})
82+
})
83+
})
84+
85+
describe('DialogManager - click events', () => {
86+
test('Trigger.click renders a backdrop, clicking backdrop closes it', () => {
87+
const dialog = mountWithTheme(
88+
<DialogManager content={simpleContent}>
89+
{({ onClick }) => <a onClick={onClick}>Open Dialog</a>}
90+
</DialogManager>
91+
)
92+
93+
// Dialog closed
94+
expect(dialog.find(Portal).exists()).toBeFalsy()
95+
96+
const button = dialog.find('a')
97+
expect(button.exists()).toBeTruthy()
98+
button.simulate('click') // Click to open
99+
100+
// Dialog open
101+
expect(dialog.find(Portal).exists()).toBeTruthy()
102+
103+
const backdrop = dialog.find(Backdrop)
104+
expect(backdrop.exists()).toBeTruthy()
105+
window.document.body.click()
106+
})
107+
})
108+
109+
test('contains the content passed to it', () => {
110+
const dialog = mountWithTheme(
111+
<DialogManager content={simpleContent}>
112+
<a>Open Dialog</a>
113+
</DialogManager>
114+
)
115+
116+
const button = dialog.find('a')
117+
expect(button.exists()).toBeTruthy()
118+
button.simulate('click') // Click to open
119+
expect(dialog.contains(simpleContent)).toBeTruthy()
120+
window.document.body.click()
121+
})
Lines changed: 35 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,28 @@
2424
2525
*/
2626

27-
import React, { CSSProperties } from 'react'
27+
import React, { CSSProperties, FC } from 'react'
2828
import { CSSTransition } from 'react-transition-group'
29-
import { CSSObject, FlattenSimpleInterpolation } from 'styled-components'
29+
import { CSSObject } from 'styled-components'
3030
import { ResponsiveValue } from 'styled-system'
3131
import { Portal } from '../Portal'
3232
import { useFocusTrap, useScrollLock } from '../utils'
33-
import { ModalBackdrop } from './ModalBackdrop'
33+
import { Backdrop } from './Backdrop'
3434
import { DialogContext } from './DialogContext'
35+
import { Surface } from './Surface'
3536

36-
export interface ModalSurfaceStyleProps {
37-
animation?: FlattenSimpleInterpolation
38-
backgroundColor: string
39-
border: string
40-
borderColor: string
41-
borderRadius: string
42-
boxShadow: string
43-
color: string
44-
}
37+
export interface DialogProps {
38+
/**
39+
* When true, renders the Backdrop, Surface and it's contained content.
40+
* @default false
41+
*/
42+
isOpen?: boolean
43+
44+
/**
45+
* Specify a callback to be called each time this Dialog is closed
46+
*/
47+
onClose?: () => void
4548

46-
export interface ManagedModalProps {
4749
/**
4850
* Optional backdrop styles to merge with the Backdrop implementation. These
4951
* must be a CSSProperty compatible key / value paired object. For example
@@ -66,33 +68,15 @@ export interface ManagedModalProps {
6668
maxWidth?: ResponsiveValue<string>
6769
}
6870

69-
export interface ModalProps extends ManagedModalProps {
70-
/**
71-
* When true, renders the Backdrop, Surface and it's contained content.
72-
* @default false
73-
*/
74-
isOpen?: boolean
75-
/**
76-
* Specify a callback to be called each time this Modal is closed
77-
*/
78-
onClose?: () => void
79-
}
80-
81-
export interface ModalInternalProps extends ModalProps {
82-
/**
83-
* To implement Modal the Surface is supplied as a function so it can consume the animationState of the Modal.
84-
* animationState will be null, 'exited', 'entering' or 'exiting' and can be used to set CSS class on Surface
85-
* element to provide CSS transitions. (See DialogSurface for implementation examples)
86-
*/
87-
render: (animationState: string) => JSX.Element
88-
}
89-
90-
export function Modal({
71+
export const Dialog: FC<DialogProps> = ({
9172
backdrop,
73+
children,
9274
isOpen,
9375
onClose,
94-
render,
95-
}: ModalInternalProps) {
76+
maxWidth,
77+
surfaceStyles,
78+
width,
79+
}) => {
9680
const {
9781
callbackRef: focusRef,
9882
disable: disableFocusTrap,
@@ -107,10 +91,14 @@ export function Modal({
10791
isEnabled: scrollLockEnabled,
10892
} = useScrollLock(isOpen, false)
10993

94+
const handleClose = () => {
95+
onClose && onClose()
96+
}
97+
11098
return (
11199
<DialogContext.Provider
112100
value={{
113-
closeModal: onClose,
101+
closeModal: handleClose,
114102
disableFocusTrap,
115103
disableScrollLock,
116104
enableFocusTrap,
@@ -134,7 +122,7 @@ export function Modal({
134122
scrollRef(node)
135123
}}
136124
>
137-
<ModalBackdrop
125+
<Backdrop
138126
className={state}
139127
onClick={onClose}
140128
visible={backdrop === undefined ? true : !!backdrop}
@@ -144,7 +132,14 @@ export function Modal({
144132
: undefined
145133
}
146134
/>
147-
{render(state)}
135+
<Surface
136+
style={surfaceStyles}
137+
className={state}
138+
width={width}
139+
maxWidth={maxWidth}
140+
>
141+
{children}
142+
</Surface>
148143
</Portal>
149144
)}
150145
</CSSTransition>

0 commit comments

Comments
 (0)