Skip to content

Commit

Permalink
feat(modal): use Button to reconstrust Modal.Action (#332)
Browse files Browse the repository at this point in the history
* feat(modal): use Button to reconstrust Modal.Action

* docs(modal): add example for action loading

* test: update snapshots
  • Loading branch information
unix committed Jul 15, 2020
1 parent 98f701e commit 194a70a
Show file tree
Hide file tree
Showing 5 changed files with 261 additions and 123 deletions.
168 changes: 122 additions & 46 deletions components/modal/__tests__/__snapshots__/index.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -103,53 +103,129 @@ exports[`Modal should render correctly 1`] = `
.content > :global(*:last-child) {
margin-bottom: 0;
}
</style><div></div><footer><button class=\\"\\">Cancel</button><style>
button {
font-size: 0.75rem;
text-transform: uppercase;
display: flex;
-webkit-box-align: center;
align-items: center;
-webkit-box-pack: center;
justify-content: center;
outline: none;
text-decoration: none;
transition: all 200ms ease-in-out 0s;
border: none;
color: #666;
background-color: #fff;
cursor: pointer;
flex: 1;
}
</style><div></div><footer><button type=\\"button\\" class=\\"btn mock \\"><div class=\\"text\\">Cancel</div><style>
.btn {
box-sizing: border-box;
display: inline-block;
padding: 0 1.375rem;
height: 2.5rem;
line-height: 2.5rem;
min-width: 12.5rem;
width: auto;
border-radius: 5px;
font-weight: 400;
font-size: .875rem;
user-select: none;
outline: none;
text-transform: capitalize;
justify-content: center;
text-align: center;
white-space: nowrap;
transition: background-color 200ms ease 0ms, box-shadow 200ms ease 0ms,
border 200ms ease 0ms, color 200ms ease 0ms;
position: relative;
overflow: hidden;
color: #666;
background-color: #fff;
border: 1px solid #eaeaea;
cursor: pointer;
pointer-events: auto;
box-shadow: none;
--zeit-ui-button-padding: 1.375rem;
--zeit-ui-button-height: 2.5rem;
--zeit-ui-button-color: #666;
--zeit-ui-button-bg: #fff;
}
button:hover {
color: #000;
background-color: #fafafa;
}
</style><button class=\\"\\">Submit</button><style>
button {
font-size: 0.75rem;
text-transform: uppercase;
display: flex;
-webkit-box-align: center;
align-items: center;
-webkit-box-pack: center;
justify-content: center;
outline: none;
text-decoration: none;
transition: all 200ms ease-in-out 0s;
border: none;
color: #000;
background-color: #fff;
cursor: pointer;
flex: 1;
}
.btn:hover {
color: #000;
--zeit-ui-button-color: #000;
background-color: #fff;
border-color: #000;
cursor: pointer;
pointer-events: auto;
box-shadow: none;
transform: translate3d(0px, 0px, 0px);
}
button:hover {
color: #000;
background-color: #fafafa;
}
</style></footer><style>
.btn :global(.text) {
position: relative;
z-index: 1;
display: inline-flex;
justify-content: center;
align-items: center;
text-align: center;
line-height: inherit;
top: -1px;
}
.btn :global(.text p),
.btn :global(.text pre),
.btn :global(.text div) {
margin: 0;
}
</style></button><button type=\\"button\\" class=\\"btn mock \\"><div class=\\"text\\">Submit</div><style>
.btn {
box-sizing: border-box;
display: inline-block;
padding: 0 1.375rem;
height: 2.5rem;
line-height: 2.5rem;
min-width: 12.5rem;
width: auto;
border-radius: 5px;
font-weight: 400;
font-size: .875rem;
user-select: none;
outline: none;
text-transform: capitalize;
justify-content: center;
text-align: center;
white-space: nowrap;
transition: background-color 200ms ease 0ms, box-shadow 200ms ease 0ms,
border 200ms ease 0ms, color 200ms ease 0ms;
position: relative;
overflow: hidden;
color: #666;
background-color: #fff;
border: 1px solid #eaeaea;
cursor: pointer;
pointer-events: auto;
box-shadow: none;
--zeit-ui-button-padding: 1.375rem;
--zeit-ui-button-height: 2.5rem;
--zeit-ui-button-color: #666;
--zeit-ui-button-bg: #fff;
}
.btn:hover {
color: #000;
--zeit-ui-button-color: #000;
background-color: #fff;
border-color: #000;
cursor: pointer;
pointer-events: auto;
box-shadow: none;
transform: translate3d(0px, 0px, 0px);
}
.btn :global(.text) {
position: relative;
z-index: 1;
display: inline-flex;
justify-content: center;
align-items: center;
text-align: center;
line-height: inherit;
top: -1px;
}
.btn :global(.text p),
.btn :global(.text pre),
.btn :global(.text div) {
margin: 0;
}
</style></button></footer><style>
footer {
display: flex;
overflow: hidden;
Expand All @@ -164,7 +240,7 @@ exports[`Modal should render correctly 1`] = `
border-bottom-right-radius: 5px;
}
footer > :global(button + button) {
footer > :global(button.btn + button.btn) {
border-left: 1px solid #eaeaea;
}
Expand Down
140 changes: 82 additions & 58 deletions components/modal/modal-action.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import React, { MouseEvent, useMemo } from 'react'
import withDefaults from '../utils/with-defaults'
import React, {
MouseEvent,
PropsWithoutRef,
RefAttributes,
useImperativeHandle,
useMemo,
useRef,
} from 'react'
import css from 'styled-jsx/css'
import useTheme from '../styles/use-theme'
import { useModalContext } from './modal-context'
import Button, { ButtonProps } from '../button/button'

type ModalActionEvent = MouseEvent<HTMLButtonElement> & {
close: () => void
Expand All @@ -20,66 +28,82 @@ const defaultProps = {
disabled: false,
}

type NativeAttrs = Omit<React.ButtonHTMLAttributes<any>, keyof Props>
export type ModalActionProps = Props & typeof defaultProps & NativeAttrs
export type ModalActionProps = Props & typeof defaultProps & Omit<ButtonProps, keyof Props>

const ModalAction: React.FC<ModalActionProps> = ({
className,
children,
onClick,
passive,
disabled,
...props
}) => {
const theme = useTheme()
const { close } = useModalContext()
const clickHandler = (event: MouseEvent<HTMLButtonElement>) => {
if (disabled) return
const actionEvent = Object.assign({}, event, {
close: () => close && close(),
})
onClick && onClick(actionEvent)
}
const ModalAction = React.forwardRef<HTMLButtonElement, React.PropsWithChildren<ModalActionProps>>(
(
{ className, children, onClick, passive, disabled, ...props },
ref: React.Ref<HTMLButtonElement | null>,
) => {
const theme = useTheme()
const btnRef = useRef<HTMLButtonElement>(null)
const { close } = useModalContext()
useImperativeHandle(ref, () => btnRef.current)

const color = useMemo(() => {
return passive || disabled ? theme.palette.accents_5 : theme.palette.foreground
}, [theme.palette, passive, disabled])
const clickHandler = (event: MouseEvent<HTMLButtonElement>) => {
if (disabled) return
const actionEvent = Object.assign({}, event, {
close: () => close && close(),
})
onClick && onClick(actionEvent)
}

const bgColor = useMemo(() => {
return disabled ? theme.palette.accents_1 : theme.palette.background
}, [theme.palette, disabled])
const color = useMemo(() => {
return passive ? theme.palette.accents_5 : theme.palette.foreground
}, [theme.palette, passive, disabled])

return (
<>
<button className={className} onClick={clickHandler} {...props}>
const bgColor = useMemo(() => {
return disabled ? theme.palette.accents_1 : theme.palette.background
}, [theme.palette, disabled])

const { className: resolveClassName, styles } = css.resolve`
button.btn {
font-size: 0.75rem;
border: none;
color: ${color};
background-color: ${theme.palette.background};
display: flex;
-webkit-box-align: center;
align-items: center;
-webkit-box-pack: center;
justify-content: center;
flex: 1;
height: 100%;
border-radius: 0;
}
button.btn:hover {
color: ${disabled ? color : theme.palette.foreground};
background-color: ${disabled ? bgColor : theme.palette.accents_1};
}
`

const overrideProps = {
...props,
effect: false,
ref: btnRef,
}

return (
<Button
className={`${resolveClassName} ${className}`}
onClick={clickHandler}
disabled={disabled}
{...overrideProps}>
{children}
</button>
<style jsx>{`
button {
font-size: 0.75rem;
text-transform: uppercase;
display: flex;
-webkit-box-align: center;
align-items: center;
-webkit-box-pack: center;
justify-content: center;
outline: none;
text-decoration: none;
transition: all 200ms ease-in-out 0s;
border: none;
color: ${color};
background-color: ${bgColor};
cursor: ${disabled ? 'not-allowed' : 'pointer'};
flex: 1;
}
{styles}
</Button>
)
},
)

button:hover {
color: ${disabled ? color : theme.palette.foreground};
background-color: ${disabled ? bgColor : theme.palette.accents_1};
}
`}</style>
</>
)
}
type ModalActionComponent<T, P = {}> = React.ForwardRefExoticComponent<
PropsWithoutRef<P> & RefAttributes<T>
>

type ComponentProps = Partial<typeof defaultProps> &
Omit<Props, keyof typeof defaultProps> &
Partial<Omit<ButtonProps, keyof Props>>

ModalAction.defaultProps = defaultProps

export default withDefaults(ModalAction, defaultProps)
export default ModalAction as ModalActionComponent<ComponentProps>
2 changes: 1 addition & 1 deletion components/modal/modal-actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const ModalActions: React.FC<React.PropsWithChildren<{}>> = ({ children, ...prop
border-bottom-right-radius: ${theme.layout.radius};
}
footer > :global(button + button) {
footer > :global(button.btn + button.btn) {
border-left: 1px solid ${theme.palette.border};
}
Expand Down
Loading

0 comments on commit 194a70a

Please sign in to comment.