Skip to content

Commit 07f3fb8

Browse files
committed
migrate DialogV1 to css modules
1 parent 307e706 commit 07f3fb8

File tree

3 files changed

+175
-51
lines changed

3 files changed

+175
-51
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
.Overlay {
2+
&:before {
3+
position: fixed;
4+
top: 0;
5+
right: 0;
6+
bottom: 0;
7+
left: 0;
8+
display: block;
9+
cursor: default;
10+
content: ' ';
11+
z-index: 99;
12+
background: var(--overlay-backdrop-bgColor);
13+
}
14+
}
15+
16+
.CloseIcon {
17+
position: absolute;
18+
top: var(--base-size-8);
19+
right: var(--base-size-16);
20+
}
21+
22+
.Dialog {
23+
box-shadow: var(--shadow-floating-large);
24+
border-radius: var(--borderRadius-medium);
25+
position: fixed;
26+
top: 0;
27+
left: 50%;
28+
transform: translateX(-50%);
29+
max-height: 80vh;
30+
z-index: 999;
31+
margin: 10vh auto;
32+
background-color: var(--bgColor-default);
33+
width: 440px;
34+
outline: none;
35+
36+
@media screen and (--viewportRange-narrow) {
37+
width: 320px;
38+
}
39+
40+
@media screen and (--viewportRange-wide) {
41+
width: 640px;
42+
}
43+
44+
@media screen and (max-width: 750px) {
45+
width: 100dvw;
46+
margin: 0;
47+
border-radius: 0;
48+
height: 100dvh;
49+
}
50+
}
51+
52+
.Header {
53+
border-radius: var(--borderRadius-medium) var(--borderRadius-medium) 0 0;
54+
border-bottom: var(--borderWidth-thin) solid var(--borderColor-default);
55+
display: flex;
56+
padding: var(--base-size-16);
57+
background: var(--bgColor-muted);
58+
59+
@media screen and (max-width: 750px) {
60+
border-radius: 0px;
61+
}
62+
}

packages/react/src/DialogV1/Dialog.test.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {Dialog} from '../DialogV1'
44
import {render as HTMLRender, fireEvent} from '@testing-library/react'
55
import axe from 'axe-core'
66
import {behavesAsComponent} from '../utils/testing'
7+
import {FeatureFlags} from '../FeatureFlags'
78

89
/* Dialog Version 1*/
910

@@ -113,6 +114,25 @@ describe('Dialog', () => {
113114
behavesAsComponent({Component: Dialog.Header})
114115
})
115116

117+
it('should support `className` on the Dialog element', () => {
118+
const Element = () => <Dialog isOpen className={'test-class-name'} />
119+
const FeatureFlagElement = () => {
120+
return (
121+
<FeatureFlags
122+
flags={{
123+
primer_react_css_modules_team: true,
124+
primer_react_css_modules_staff: true,
125+
primer_react_css_modules_ga: true,
126+
}}
127+
>
128+
<Element />
129+
</FeatureFlags>
130+
)
131+
}
132+
expect(HTMLRender(<Element />).container.children[1]).toHaveClass('test-class-name')
133+
expect(HTMLRender(<FeatureFlagElement />).container.children[1]).toHaveClass('test-class-name')
134+
})
135+
116136
it('should have no axe violations', async () => {
117137
const spy = jest.spyOn(console, 'warn').mockImplementation()
118138
const {container} = HTMLRender(comp)

packages/react/src/DialogV1/Dialog.tsx

Lines changed: 93 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ import Text from '../Text'
1010
import type {ComponentProps} from '../utils/types'
1111
import {useRefObjectAsForwardedRef} from '../hooks/useRefObjectAsForwardedRef'
1212
import {XIcon} from '@primer/octicons-react'
13+
import {toggleStyledComponent} from '../internal/utils/toggleStyledComponent'
14+
import {useFeatureFlag} from '../FeatureFlags'
15+
import {clsx} from 'clsx'
16+
import classes from './Dialog.module.css'
17+
18+
const CSS_MODULES_FEATURE_FLAG = 'primer_react_css_modules_team'
1319

1420
// Dialog v1
1521
const noop = () => null
@@ -19,41 +25,50 @@ type StyledDialogBaseProps = {
1925
wide?: boolean
2026
} & SxProp
2127

22-
const DialogBase = styled.div<StyledDialogBaseProps>`
23-
box-shadow: ${get('shadows.shadow.large')};
24-
border-radius: ${get('radii.2')};
25-
position: fixed;
26-
top: 0;
27-
left: 50%;
28-
transform: translateX(-50%);
29-
max-height: 80vh;
30-
z-index: 999;
31-
margin: 10vh auto;
32-
background-color: ${get('colors.canvas.default')};
33-
width: ${props => (props.narrow ? '320px' : props.wide ? '640px' : '440px')};
34-
outline: none;
35-
36-
@media screen and (max-width: 750px) {
37-
width: 100dvw;
38-
margin: 0;
39-
border-radius: 0;
40-
height: 100dvh;
41-
}
28+
const DialogBase = toggleStyledComponent(
29+
CSS_MODULES_FEATURE_FLAG,
30+
'div',
31+
styled.div<StyledDialogBaseProps>`
32+
box-shadow: ${get('shadows.shadow.large')};
33+
border-radius: ${get('radii.2')};
34+
position: fixed;
35+
top: 0;
36+
left: 50%;
37+
transform: translateX(-50%);
38+
max-height: 80vh;
39+
z-index: 999;
40+
margin: 10vh auto;
41+
background-color: ${get('colors.canvas.default')};
42+
width: ${props => (props.narrow ? '320px' : props.wide ? '640px' : '440px')};
43+
outline: none;
44+
45+
@media screen and (max-width: 750px) {
46+
width: 100dvw;
47+
margin: 0;
48+
border-radius: 0;
49+
height: 100dvh;
50+
}
4251
43-
${sx};
44-
`
52+
${sx};
53+
`,
54+
)
4555

46-
const DialogHeaderBase = styled(Box)<SxProp>`
47-
border-radius: ${get('radii.2')} ${get('radii.2')} 0px 0px;
48-
border-bottom: 1px solid ${get('colors.border.default')};
49-
display: flex;
56+
const DialogHeaderBase = toggleStyledComponent(
57+
CSS_MODULES_FEATURE_FLAG,
58+
'div',
59+
styled(Box)<SxProp>`
60+
border-radius: ${get('radii.2')} ${get('radii.2')} 0px 0px;
61+
border-bottom: 1px solid ${get('colors.border.default')};
62+
display: flex;
5063
51-
@media screen and (max-width: 750px) {
52-
border-radius: 0px;
53-
}
64+
@media screen and (max-width: 750px) {
65+
border-radius: 0px;
66+
}
67+
68+
${sx};
69+
`,
70+
)
5471

55-
${sx};
56-
`
5772
export type DialogHeaderProps = ComponentProps<typeof DialogHeaderBase>
5873

5974
function DialogHeader({theme, children, backgroundColor = 'canvas.subtle', ...rest}: DialogHeaderProps) {
@@ -65,28 +80,40 @@ function DialogHeader({theme, children, backgroundColor = 'canvas.subtle', ...re
6580
)
6681
}
6782

83+
const enabled = useFeatureFlag(CSS_MODULES_FEATURE_FLAG)
84+
6885
return (
69-
<DialogHeaderBase theme={theme} p={3} backgroundColor={backgroundColor} {...rest}>
86+
<DialogHeaderBase
87+
theme={theme}
88+
p={3}
89+
backgroundColor={backgroundColor}
90+
{...rest}
91+
className={enabled ? classes.Header : undefined}
92+
>
7093
{children}
7194
</DialogHeaderBase>
7295
)
7396
}
7497

75-
const Overlay = styled.span`
76-
&:before {
77-
position: fixed;
78-
top: 0;
79-
right: 0;
80-
bottom: 0;
81-
left: 0;
82-
display: block;
83-
cursor: default;
84-
content: ' ';
85-
background: transparent;
86-
z-index: 99;
87-
background: ${get('colors.primer.canvas.backdrop')};
88-
}
89-
`
98+
const Overlay = toggleStyledComponent(
99+
CSS_MODULES_FEATURE_FLAG,
100+
'span',
101+
styled.span`
102+
&:before {
103+
position: fixed;
104+
top: 0;
105+
right: 0;
106+
bottom: 0;
107+
left: 0;
108+
display: block;
109+
cursor: default;
110+
content: ' ';
111+
background: transparent;
112+
z-index: 99;
113+
background: ${get('colors.primer.canvas.backdrop')};
114+
}
115+
`,
116+
)
90117

91118
type InternalDialogProps = {
92119
isOpen?: boolean
@@ -96,7 +123,7 @@ type InternalDialogProps = {
96123
} & ComponentProps<typeof DialogBase>
97124

98125
const Dialog = forwardRef<HTMLDivElement, InternalDialogProps>(
99-
({children, onDismiss = noop, isOpen, initialFocusRef, returnFocusRef, ...props}, forwardedRef) => {
126+
({children, onDismiss = noop, isOpen, initialFocusRef, returnFocusRef, className, ...props}, forwardedRef) => {
100127
const overlayRef = useRef(null)
101128
const modalRef = useRef<HTMLDivElement>(null)
102129
useRefObjectAsForwardedRef(forwardedRef, modalRef)
@@ -118,17 +145,32 @@ const Dialog = forwardRef<HTMLDivElement, InternalDialogProps>(
118145
returnFocusRef,
119146
overlayRef,
120147
})
148+
149+
const enabled = useFeatureFlag(CSS_MODULES_FEATURE_FLAG)
150+
151+
const iconStyles = enabled
152+
? {className: classes.CloseIcon}
153+
: {sx: {position: 'absolute', top: '8px', right: '16px'}}
154+
121155
return isOpen ? (
122156
<>
123-
<Overlay ref={overlayRef} />
124-
<DialogBase tabIndex={-1} ref={modalRef} role="dialog" aria-modal="true" {...props} {...getDialogProps()}>
157+
<Overlay className={enabled ? classes.Overlay : undefined} ref={overlayRef} />
158+
<DialogBase
159+
tabIndex={-1}
160+
ref={modalRef}
161+
role="dialog"
162+
aria-modal="true"
163+
{...props}
164+
{...getDialogProps()}
165+
className={clsx({[classes.Dialog]: enabled}, className)}
166+
>
125167
<IconButton
126168
icon={XIcon}
127169
ref={closeButtonRef}
128170
onClick={onCloseClick}
129-
sx={{position: 'absolute', top: '8px', right: '16px'}}
130171
aria-label="Close"
131172
variant="invisible"
173+
{...iconStyles}
132174
/>
133175
{children}
134176
</DialogBase>

0 commit comments

Comments
 (0)