Skip to content

Commit

Permalink
feat!: Dialog の位置指定を消し、スタイリングを見直し (#4848)
Browse files Browse the repository at this point in the history
Co-authored-by: oti <[email protected]>
Co-authored-by: shingo.sasaki <[email protected]>
  • Loading branch information
3 people authored Sep 10, 2024
1 parent 5aaf6f5 commit 25d83ec
Show file tree
Hide file tree
Showing 13 changed files with 276 additions and 629 deletions.
Original file line number Diff line number Diff line change
@@ -1,61 +1,40 @@
import React, { FC, PropsWithChildren, ReactNode, useCallback } from 'react'
import React, { type FC, type PropsWithChildren, type ReactNode, useCallback } from 'react'

import { Button } from '../../Button'
import { Heading, HeadingTagTypes } from '../../Heading'
import { Cluster, Stack } from '../../Layout'
import { ResponseMessage } from '../../ResponseMessage'
import { Section } from '../../SectioningContent'
import { Text } from '../../Text'
import { useOffsetHeight } from '../dialogHelper'
import { type ContentBodyProps, useDialoginnerStyle } from '../useDialogInnerStyle'
import { DialogBody, type Props as DialogBodyProps } from '../DialogBody'
import { DialogHeader, type Props as DialogHeaderProps } from '../DialogHeader'
import { dialogContentInner } from '../dialogInnerStyle'

import type { DecoratorsType, ResponseMessageType } from '../../../types'

export type BaseProps = PropsWithChildren<{
/**
* ダイアログのタイトル
*/
title: ReactNode
/**
* ダイアログのサブタイトル
*/
subtitle?: ReactNode
/**
* @deprecated SectioningContent(Article, Aside, Nav, Section)でDialog全体をラップして、ダイアログタイトルのHeadingレベルを設定してください
*/
titleTag?: HeadingTagTypes
/**
* アクションボタンのラベル
*/
actionText: ReactNode
/**
* アクションボタンのスタイル
*/
actionTheme?: 'primary' | 'secondary' | 'danger'
/**
* アクションボタンをクリックした時に発火するコールバック関数
* @param closeDialog - ダイアログを閉じる関数
*/
onClickAction: (closeDialog: () => void) => void
/**
* アクションボタンを無効にするかどうか
*/
actionDisabled?: boolean
/**
* 閉じるボタンを無効にするかどうか
*/
closeDisabled?: boolean
/** ダイアログフッターの左端操作領域 */
subActionArea?: ReactNode
/** コンポーネント内の文言を変更するための関数を設定 */
decorators?: DecoratorsType<'closeButtonLabel'>
}> &
ContentBodyProps
export type BaseProps = PropsWithChildren<
DialogHeaderProps &
DialogBodyProps & {
/** アクションボタンのラベル */
actionText: ReactNode
/** アクションボタンのスタイル */
actionTheme?: 'primary' | 'secondary' | 'danger'
/**
* アクションボタンをクリックした時に発火するコールバック関数
* @param closeDialog - ダイアログを閉じる関数
*/
onClickAction: (closeDialog: () => void) => void
/** アクションボタンを無効にするかどうか */
actionDisabled?: boolean
/** 閉じるボタンを無効にするかどうか */
closeDisabled?: boolean
/** ダイアログフッターの左端操作領域 */
subActionArea?: ReactNode
/** コンポーネント内の文言を変更するための関数を設定 */
decorators?: DecoratorsType<'closeButtonLabel'>
}
>

export type ActionDialogContentInnerProps = BaseProps & {
onClickClose: () => void
responseMessage?: ResponseMessageType
titleId: string
}

const CLOSE_BUTTON_LABEL = 'キャンセル'
Expand All @@ -80,33 +59,21 @@ export const ActionDialogContentInner: FC<ActionDialogContentInnerProps> = ({
const handleClickAction = useCallback(() => {
onClickAction(onClickClose)
}, [onClickAction, onClickClose])
const { offsetHeight, titleRef, bottomRef } = useOffsetHeight()

const isRequestProcessing = responseMessage && responseMessage.status === 'processing'

const { titleAreaStyle, bodyStyleProps, actionAreaStyle, buttonAreaStyle, messageStyle } =
useDialoginnerStyle(offsetHeight, contentBgColor, contentPadding)
const { wrapper, actionArea, buttonArea, message } = dialogContentInner()

return (
<Section>
{/* eslint-disable-next-line smarthr/a11y-heading-in-sectioning-content */}
<Heading tag={titleTag}>
<Stack gap={0.25} as="span" ref={titleRef} className={titleAreaStyle}>
{subtitle && (
<Text size="S" leading="TIGHT" color="TEXT_GREY" className="smarthr-ui-Dialog-subtitle">
{subtitle}
</Text>
)}
<Text id={titleId} size="L" leading="TIGHT" className="smarthr-ui-Dialog-title">
{title}
</Text>
</Stack>
</Heading>
<div {...bodyStyleProps}>{children}</div>
<Stack gap={0.5} ref={bottomRef} className={actionAreaStyle}>
// eslint-disable-next-line smarthr/best-practice-for-layouts, smarthr/a11y-heading-in-sectioning-content
<Stack gap={0} as="section" className={wrapper()}>
<DialogHeader title={title} subtitle={subtitle} titleTag={titleTag} titleId={titleId} />
<DialogBody contentPadding={contentPadding} contentBgColor={contentBgColor}>
{children}
</DialogBody>
<Stack gap={0.5} className={actionArea()}>
<Cluster justify="space-between">
{subActionArea}
<Cluster gap={{ row: 0.5, column: 1 }} className={buttonAreaStyle}>
<Cluster gap={{ row: 0.5, column: 1 }} className={buttonArea()}>
<Button
onClick={onClickClose}
disabled={closeDisabled || isRequestProcessing}
Expand All @@ -126,13 +93,13 @@ export const ActionDialogContentInner: FC<ActionDialogContentInnerProps> = ({
</Cluster>
</Cluster>
{(responseMessage?.status === 'success' || responseMessage?.status === 'error') && (
<div className={messageStyle}>
<div className={message()}>
<ResponseMessage type={responseMessage.status} role="alert">
{responseMessage.text}
</ResponseMessage>
</div>
)}
</Stack>
</Section>
</Stack>
)
}
30 changes: 0 additions & 30 deletions packages/smarthr-ui/src/components/Dialog/Dialog.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -459,30 +459,6 @@ export const WidthAndPosition: StoryFn = () => (
</DialogContent>
</DialogWrapper>
</li>
<li>
<DialogWrapper>
<DialogTrigger>
<Button aria-haspopup="dialog" aria-controls="dialog-position-1">
top-left
</Button>
</DialogTrigger>
<DialogContent top={50} left={200} id="dialog-position-1">
<p>This Dialog is set to `top: 50px, left: 200px`.</p>
</DialogContent>
</DialogWrapper>
</li>
<li>
<DialogWrapper>
<DialogTrigger>
<Button aria-haspopup="dialog" aria-controls="dialog-position-2">
bottom-right
</Button>
</DialogTrigger>
<DialogContent right={50} bottom={100} id="dialog-position-2">
<p>This Dialog is set to `right: 50px, bottom: 100px`.</p>
</DialogContent>
</DialogWrapper>
</li>
</TriggerList>
)
WidthAndPosition.parameters = {
Expand Down Expand Up @@ -551,12 +527,6 @@ export const RegDialogOpenedDialogWidth: StoryFn = () => (
</Dialog>
)

export const RegDialogOpenedDialogPosition: StoryFn = () => (
<Dialog isOpen top={20} right={40} bottom={60} left={80}>
<p>{dummyText}</p>
</Dialog>
)

export const RegOpenedForm: StoryFn = () => (
<FormDialog
isOpen={true}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import { useMemo } from 'react'
import { type VariantProps, tv } from 'tailwind-variants'
import React, { type PropsWithChildren } from 'react'
import { VariantProps, tv } from 'tailwind-variants'

import { type Gap } from '../../types'
import type { Gap } from '../../types'

export type Props = PropsWithChildren<
Pick<VariantProps<typeof dialogBody>, 'contentBgColor'> & {
contentPadding?: Gap | { block?: Gap; inline?: Gap }
className?: string | undefined
}
>

const dialogContentInner = tv({
slots: {
titleArea: ['smarthr-ui-Dialog-titleArea', 'shr-border-b-shorthand shr-px-1.5 shr-py-1'],
actionArea: ['smarthr-ui-Dialog-actionArea', 'shr-border-t-shorthand shr-px-1.5 shr-py-1'],
buttonArea: ['smarthr-ui-Dialog-buttonArea', 'shr-ms-auto'],
message: 'shr-text-right',
},
})
const dialogBody = tv({
base: ['smarthr-ui-Dialog-body', 'shr-overflow-auto'],
base: ['smarthr-ui-Dialog-body', 'shr-overflow-auto shr-flex-auto'],
variants: {
contentPaddingBlock: {
paddingBlock: {
0: 'shr-py-0',
0.25: 'shr-py-0.25',
0.5: 'shr-py-0.5',
Expand All @@ -38,7 +37,7 @@ const dialogBody = tv({
XXL: 'shr-py-3.5',
X3L: 'shr-py-4',
} as { [key in Gap]: string },
contentPaddingInline: {
paddingInline: {
0: 'shr-px-0',
0.25: 'shr-px-0.25',
0.5: 'shr-px-0.5',
Expand Down Expand Up @@ -80,34 +79,15 @@ const dialogBody = tv({
},
})

export type ContentBodyProps = Pick<VariantProps<typeof dialogBody>, 'contentBgColor'> & {
contentPadding?: Gap | { block?: Gap; inline?: Gap }
}

export const useDialoginnerStyle = (
offsetHeight: number,
bgColor: ContentBodyProps['contentBgColor'],
padding: ContentBodyProps['contentPadding'] = 1.5,
) =>
useMemo(() => {
const { titleArea, actionArea, buttonArea, message } = dialogContentInner()
const paddingBlock = padding instanceof Object ? padding.block : padding
const paddingInline = padding instanceof Object ? padding.inline : padding
export const DialogBody: React.FC<Props> = ({
contentBgColor,
contentPadding = 1.5,
className,
...rest
}) => {
const paddingBlock = contentPadding instanceof Object ? contentPadding.block : contentPadding
const paddingInline = contentPadding instanceof Object ? contentPadding.inline : contentPadding

return {
titleAreaStyle: titleArea(),
bodyStyleProps: {
className: dialogBody({
contentBgColor: bgColor,
contentPaddingBlock: paddingBlock,
contentPaddingInline: paddingInline,
}),
style: {
maxHeight: `calc(100svh - ${offsetHeight}px)`,
},
},
actionAreaStyle: actionArea(),
buttonAreaStyle: buttonArea(),
messageStyle: message(),
}
}, [bgColor, offsetHeight, padding])
const style = dialogBody({ contentBgColor, paddingBlock, paddingInline, className })
return <div {...rest} className={style} />
}
Loading

0 comments on commit 25d83ec

Please sign in to comment.