Skip to content

Commit

Permalink
Merge pull request #405 from pixiv/toshusai/fix-modal-focus
Browse files Browse the repository at this point in the history
fix: 自動的にmodal内にフォーカスが移動しない問題を修正 + etc
  • Loading branch information
toshusai authored Oct 26, 2023
2 parents 4ceb37c + 9fd9891 commit e250c83
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 113 deletions.
64 changes: 32 additions & 32 deletions docs/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -162,38 +162,38 @@ __metadata:
linkType: hard

"@charcoal-ui/foundation@file:../packages/foundation::locator=charcoal-web-docs%40workspace%3A.":
version: 3.3.0-beta.0
resolution: "@charcoal-ui/foundation@file:../packages/foundation#../packages/foundation::hash=20ac71&locator=charcoal-web-docs%40workspace%3A."
checksum: caa7cd8dd3d0da231bd4f2f4bd572e85271d929e4cc87178e4de94b788d960e2e99979090c0f1e781f9145e9ef898d67c75d618f860f076edd1c51cb050ff25f
version: 3.3.0
resolution: "@charcoal-ui/foundation@file:../packages/foundation#../packages/foundation::hash=f171f8&locator=charcoal-web-docs%40workspace%3A."
checksum: c870992f52889299bf7f6822aea364ab5fda2eaa45aba8215ba84c3c26951cf153dd6b02bcc4ff2d7a70807ac962bbfd73f43cec707b7ed788e0b12b79ca7267
languageName: node
linkType: hard

"@charcoal-ui/icon-files@file:../packages/icon-files::locator=charcoal-web-docs%40workspace%3A.":
version: 3.3.0-beta.0
resolution: "@charcoal-ui/icon-files@file:../packages/icon-files#../packages/icon-files::hash=d8f2a0&locator=charcoal-web-docs%40workspace%3A."
checksum: d5c66986fbf41ba3f1c2f2e34439ca5f081cca2c3d03a2d6682a132bcbe0264f85eb139a24cce28a849dca5b0488e1fe1ee3ebe64821f45adf7d5b295871f912
version: 3.3.0
resolution: "@charcoal-ui/icon-files@file:../packages/icon-files#../packages/icon-files::hash=238a46&locator=charcoal-web-docs%40workspace%3A."
checksum: e952e88fe1b29b068e768572119c4528647e1a192e53430dba9b775085b1dda0bcb98c36ed9d34638ffc01ebc28d24e36d251c88202ec7904a75f6039b5976e0
languageName: node
linkType: hard

"@charcoal-ui/icons@file:../packages/icons::locator=charcoal-web-docs%40workspace%3A.":
version: 3.3.0-beta.0
resolution: "@charcoal-ui/icons@file:../packages/icons#../packages/icons::hash=2135a7&locator=charcoal-web-docs%40workspace%3A."
version: 3.3.0
resolution: "@charcoal-ui/icons@file:../packages/icons#../packages/icons::hash=155702&locator=charcoal-web-docs%40workspace%3A."
dependencies:
"@charcoal-ui/icon-files": ^3.3.0-beta.0
"@charcoal-ui/icon-files": ^3.3.0
dompurify: ^2.3.6
warning: ^4.0.3
checksum: adfcc7b8da8ddf01a046583b7043dce8587c53f06170b3178500c33b9693dcaf5b5681289a57ae04e1b695b9de50119160ce774a4f3a1256c228761569fee3f5
checksum: d04cb39342a02d5db3ef356f2d3858d77d7ff4bb4192dfe05c2a4cf1e263ba50d658534593b5fadd980cd752006d980065d9fec25f6acfb75083e330dbedd103
languageName: node
linkType: hard

"@charcoal-ui/react@file:../packages/react::locator=charcoal-web-docs%40workspace%3A.":
version: 3.3.0-beta.0
resolution: "@charcoal-ui/react@file:../packages/react#../packages/react::hash=2f6a35&locator=charcoal-web-docs%40workspace%3A."
version: 3.3.0
resolution: "@charcoal-ui/react@file:../packages/react#../packages/react::hash=23a0de&locator=charcoal-web-docs%40workspace%3A."
dependencies:
"@charcoal-ui/icons": ^3.3.0-beta.0
"@charcoal-ui/styled": ^3.3.0-beta.0
"@charcoal-ui/theme": ^3.3.0-beta.0
"@charcoal-ui/utils": ^3.3.0-beta.0
"@charcoal-ui/icons": ^3.3.0
"@charcoal-ui/styled": ^3.3.0
"@charcoal-ui/theme": ^3.3.0
"@charcoal-ui/utils": ^3.3.0
"@react-aria/button": ^3.7.0
"@react-aria/checkbox": ^3.8.0
"@react-aria/dialog": ^3.5.0
Expand All @@ -215,43 +215,43 @@ __metadata:
peerDependencies:
react: ">=17.0.0"
styled-components: ">=5.1.1"
checksum: b04426a89e9825f5e8866ba79cfe844088fe6a94395eec3ed14d97e3f85fb3999464cab02235c1852b1d8a2d04f6c7135650def865fe76e30930b2bfaa1bc9ad
checksum: f7f12c16106c14b1f0c03a4211c5dd3b8028dd4c507437aa02459d23a692c30839741b09425b0677055a2bd5afe8963f7a2e3dd474901e11a02c215524f6e95a
languageName: node
linkType: hard

"@charcoal-ui/styled@file:../packages/styled::locator=charcoal-web-docs%40workspace%3A.":
version: 3.3.0-beta.0
resolution: "@charcoal-ui/styled@file:../packages/styled#../packages/styled::hash=051221&locator=charcoal-web-docs%40workspace%3A."
version: 3.3.0
resolution: "@charcoal-ui/styled@file:../packages/styled#../packages/styled::hash=d4801e&locator=charcoal-web-docs%40workspace%3A."
dependencies:
"@charcoal-ui/foundation": ^3.3.0-beta.0
"@charcoal-ui/theme": ^3.3.0-beta.0
"@charcoal-ui/utils": ^3.3.0-beta.0
"@charcoal-ui/foundation": ^3.3.0
"@charcoal-ui/theme": ^3.3.0
"@charcoal-ui/utils": ^3.3.0
warning: ^4.0.3
peerDependencies:
react: ">=17.0.0"
styled-components: ">=5.1.1"
checksum: f16403e1e3230ad8ab71969746a6509697d65745fc3d7e9dda328cc3fc86df247fc37e882a50bd59f85cfa4b2e3fe05c2486da9aa722bc1a5401fb927d8fefd9
checksum: cdd2c78b97c17f6542a0d01554e8591514a424bfd4ad3ea5866361c3b727e6c30281f205b7ed42fcb971ca6fde8cc188979b4839488d2416bb88d5ed8b990870
languageName: node
linkType: hard

"@charcoal-ui/theme@file:../packages/theme::locator=charcoal-web-docs%40workspace%3A.":
version: 3.3.0-beta.0
resolution: "@charcoal-ui/theme@file:../packages/theme#../packages/theme::hash=209188&locator=charcoal-web-docs%40workspace%3A."
version: 3.3.0
resolution: "@charcoal-ui/theme@file:../packages/theme#../packages/theme::hash=d3e7d3&locator=charcoal-web-docs%40workspace%3A."
dependencies:
"@charcoal-ui/foundation": ^3.3.0-beta.0
"@charcoal-ui/utils": ^3.3.0-beta.0
"@charcoal-ui/foundation": ^3.3.0
"@charcoal-ui/utils": ^3.3.0
polished: ^4.1.4
checksum: eb6373c38a1d5ebe66bf3c1a1017152ced38b3bd76681c545f5ec75927a8aede90428114eedb82a0b75fe5b0c542fe40a0ee96e82f569e9233af2be608401c9f
checksum: 647656c05f4b1edaa70f558f65c0757c9cbfd03cbf677ecb7b1f0d523ac4be0f86017249c984e56ac7db9a0966c93a5651d0f36e67a313be6700bdec36a78d28
languageName: node
linkType: hard

"@charcoal-ui/utils@file:../packages/utils::locator=charcoal-web-docs%40workspace%3A.":
version: 3.3.0-beta.0
resolution: "@charcoal-ui/utils@file:../packages/utils#../packages/utils::hash=fe489f&locator=charcoal-web-docs%40workspace%3A."
version: 3.3.0
resolution: "@charcoal-ui/utils@file:../packages/utils#../packages/utils::hash=bd0f39&locator=charcoal-web-docs%40workspace%3A."
dependencies:
"@charcoal-ui/foundation": ^3.3.0-beta.0
"@charcoal-ui/foundation": ^3.3.0
polished: ^4.1.4
checksum: 01eb2b8969afe3487dfe2be3140650141398d32e01ce115ea06ff2a564d614b3b4ea7649a698dd4b4a58a3be19f6359c4e040a6f4367daf041be346f1fd831e8
checksum: 91fc0cdfcd4c6a0907c5d788c02ca94504876be29697af36592347d91d448fa1ca4d2b27da400701330df6cfbd84a63a42cd76a77089d86c93b46d5748ef361c
languageName: node
linkType: hard

Expand Down
16 changes: 16 additions & 0 deletions packages/react/src/_lib/useForwardedRef.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as React from 'react'

export function useForwardedRef<T>(ref: React.ForwardedRef<T>) {
const innerRef = React.useRef<T>(null)

React.useEffect(() => {
if (!ref) return
if (typeof ref === 'function') {
ref(innerRef.current)
} else {
ref.current = innerRef.current
}
})

return innerRef
}
82 changes: 82 additions & 0 deletions packages/react/src/components/Modal/Dialog/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { forwardRef } from 'react'
import * as React from 'react'
import styled, { css } from 'styled-components'
import { useDialog } from '@react-aria/dialog'
import { columnSystem, COLUMN_UNIT, GUTTER_UNIT } from '@charcoal-ui/foundation'
import { unreachable } from '../../../_lib'
import { maxWidth } from '@charcoal-ui/utils'
import { animated } from 'react-spring'
import { useForwardedRef } from '../../../_lib/useForwardedRef'
import { Size, BottomSheet } from '..'

export const Dialog = forwardRef<
HTMLDivElement,
React.ComponentProps<typeof AnimatedStyledDialogDiv>
>(function Dialog(props, forwardRef) {
const ref = useForwardedRef(forwardRef)
const { dialogProps } = useDialog(
{
role: 'dialog',
},
ref
)

return (
<AnimatedStyledDialogDiv
{...props}
role={dialogProps.role}
tabIndex={dialogProps.tabIndex}
aria-labelledby={dialogProps['aria-labelledby']}
onBlur={dialogProps.onBlur}
ref={ref}
/>
)
})

const AnimatedStyledDialogDiv = animated(styled.div<{
size: Size
bottomSheet: BottomSheet
}>`
margin: auto;
position: relative;
height: fit-content;
width: ${(p) => {
switch (p.size) {
case 'S': {
return columnSystem(3, COLUMN_UNIT, GUTTER_UNIT) + GUTTER_UNIT * 2
}
case 'M': {
return columnSystem(4, COLUMN_UNIT, GUTTER_UNIT) + GUTTER_UNIT * 2
}
case 'L': {
return columnSystem(6, COLUMN_UNIT, GUTTER_UNIT) + GUTTER_UNIT * 2
}
default: {
return unreachable(p.size)
}
}
}}px;
background-color: ${({ theme }) => theme.color.background1};
border-radius: 24px;
@media ${({ theme }) => maxWidth(theme.breakpoint.screen1)} {
max-width: 440px;
width: calc(100% - 48px);
${(p) =>
p.bottomSheet !== false &&
css`
max-width: unset;
width: 100%;
border-radius: 0;
margin: auto 0 0 0;
${p.bottomSheet === 'full' &&
css`
min-height: 100%;
`}
`}
}
:focus {
outline: none;
}
`)
1 change: 1 addition & 0 deletions packages/react/src/components/Modal/index.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ const M = (props: ModalProps) => {
</ModalAlign>
<ModalAlign>
<TextField
autoFocus
showLabel
label="Country"
placeholder="Tokyo"
Expand Down
103 changes: 22 additions & 81 deletions packages/react/src/components/Modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,18 @@ import {
} from '@react-aria/overlays'
import styled, { css, useTheme } from 'styled-components'
import { theme } from '../../styled'
import { useDialog } from '@react-aria/dialog'
import { AriaDialogProps } from '@react-types/dialog'
import { columnSystem, COLUMN_UNIT, GUTTER_UNIT } from '@charcoal-ui/foundation'
import { unreachable } from '../../_lib'
import { maxWidth } from '@charcoal-ui/utils'
import { useMedia } from '@charcoal-ui/styled'
import { animated, useTransition, easings } from 'react-spring'
import Button, { ButtonProps } from '../Button'
import IconButton from '../IconButton'
import { useObjectRef } from '@react-aria/utils'
import { Dialog } from './Dialog'
import { ModalBackgroundContext } from './ModalBackgroundContext'

export type BottomSheet = boolean | 'full'
type Size = 'S' | 'M' | 'L'
export type Size = 'S' | 'M' | 'L'

export type ModalProps = AriaModalOverlayProps &
AriaDialogProps & {
Expand Down Expand Up @@ -146,35 +144,33 @@ const Modal = forwardRef<HTMLDivElement, ModalProps>(function ModalInner(
$bottomSheet={bottomSheet}
>
<ModalBackgroundContext.Provider value={bgRef.current}>
<ModalDialog
<Dialog
ref={ref}
{...modalProps}
style={transitionEnabled ? { transform } : {}}
size={size}
bottomSheet={bottomSheet}
className={className}
>
<Dialog>
<ModalContext.Provider
value={{
titleProps: {},
title,
close: onClose,
showDismiss,
bottomSheet,
}}
>
{children}
{isDismissable === true && (
<ModalCrossButton
size="S"
icon="24/Close"
onClick={onClose}
/>
)}
</ModalContext.Provider>
</Dialog>
</ModalDialog>
<ModalContext.Provider
value={{
titleProps: {},
title,
close: onClose,
showDismiss,
bottomSheet,
}}
>
{children}
{isDismissable === true && (
<ModalCrossButton
size="S"
icon="24/Close"
onClick={onClose}
/>
)}
</ModalContext.Provider>
</Dialog>
</ModalBackgroundContext.Provider>
</ModalBackground>
</Overlay>
Expand All @@ -184,17 +180,6 @@ const Modal = forwardRef<HTMLDivElement, ModalProps>(function ModalInner(

export default memo(Modal)

function Dialog({ children }: { children: React.ReactNode }) {
const r = React.useRef(null)
const { dialogProps } = useDialog(
{
role: 'dialog',
},
r
)
return <div {...dialogProps}>{children}</div>
}

export const ModalContext = React.createContext<{
/**
* @deprecated
Expand Down Expand Up @@ -240,50 +225,6 @@ const ModalBackground = animated(styled.div<{
}
`)

const ModalDialog = animated(styled.div<{
size: Size
bottomSheet: BottomSheet
}>`
margin: auto;
position: relative;
height: fit-content;
width: ${(p) => {
switch (p.size) {
case 'S': {
return columnSystem(3, COLUMN_UNIT, GUTTER_UNIT) + GUTTER_UNIT * 2
}
case 'M': {
return columnSystem(4, COLUMN_UNIT, GUTTER_UNIT) + GUTTER_UNIT * 2
}
case 'L': {
return columnSystem(6, COLUMN_UNIT, GUTTER_UNIT) + GUTTER_UNIT * 2
}
default: {
return unreachable(p.size)
}
}
}}px;
background-color: ${({ theme }) => theme.color.background1};
border-radius: 24px;
@media ${({ theme }) => maxWidth(theme.breakpoint.screen1)} {
max-width: 440px;
width: calc(100% - 48px);
${(p) =>
p.bottomSheet !== false &&
css`
width: 100%;
border-radius: 0;
margin: auto 0 0 0;
${p.bottomSheet === 'full' &&
css`
min-height: 100%;
`}
`}
}
`)

const ModalCrossButton = styled(IconButton)`
position: absolute;
top: 8px;
Expand Down

0 comments on commit e250c83

Please sign in to comment.