Skip to content

Commit

Permalink
Merge branch 'refs/heads/master' into HEAD
Browse files Browse the repository at this point in the history
  • Loading branch information
github-actions[bot] committed Apr 16, 2024
2 parents 4808fdc + 376e2b0 commit a698fd6
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 152 deletions.
6 changes: 2 additions & 4 deletions src/components/FlashMessage/FlashMessage.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import styled from 'styled-components'

import { Button } from '../Button'

import { FlashMessage, Props, animationTypes, messageTypes } from './FlashMessage'
import { FlashMessage, Props, messageTypes } from './FlashMessage'

import { FlashMessageListProvider, useFlashMessageList } from '.'

Expand Down Expand Up @@ -61,8 +61,6 @@ const Template: StoryFn = (arg) => (
)
export const Bounce = Template.bind({})
Bounce.args = { animation: 'bounce' }
export const Fade = Template.bind({})
Fade.args = { animation: 'fade' }
export const None = Template.bind({})
None.args = { animation: 'none' }

Expand Down Expand Up @@ -135,7 +133,7 @@ export const Demo: StoryFn = () => {
<hr />
<fieldset>
<legend>animation</legend>
{animationTypes.map((animationType) => (
{['bounce', 'none'].map((animationType) => (
<label key={animationType}>
<input
name="animationType"
Expand Down
2 changes: 1 addition & 1 deletion src/components/FlashMessage/FlashMessage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ describe('FlashMessage', () => {
<FlashMessage type="success" text="flash!!" onClose={spy} visible={true} />,
)
})
document.querySelector<HTMLButtonElement>('button.close')!.click()
document.querySelector<HTMLButtonElement>('button.smarthr-ui-FlashMessage-button')!.click()

expect(spy).toHaveBeenCalled()
})
Expand Down
176 changes: 47 additions & 129 deletions src/components/FlashMessage/FlashMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import React, { FC, HTMLAttributes, ReactNode, useEffect } from 'react'
import styled, { css, keyframes } from 'styled-components'
import React, { ComponentPropsWithoutRef, FC, ReactNode, useEffect, useMemo } from 'react'
import { VariantProps, tv } from 'tailwind-variants'

import { Theme, useTheme } from '../../hooks/useTheme'
import { Button } from '../Button'
import { FaTimesIcon } from '../Icon'
import { FaXmarkIcon } from '../Icon'
import { ResponseMessage } from '../ResponseMessage'

import { useClassNames } from './useClassNames'

export const messageTypes = ['success', 'info', 'warning', 'error'] as const
export const animationTypes = ['bounce', 'fade', 'none'] as const
export const roles = ['alert', 'status'] as const

export type Props = {
Expand All @@ -19,22 +15,43 @@ export type Props = {
type: (typeof messageTypes)[number]
/** メッセージの内容 */
text: ReactNode
/** アニメーションのタイプ */
animation?: (typeof animationTypes)[number]
/** コンポーネントに適用する role 属性 */
role?: (typeof roles)[number]
/** コンポーネントに適用するクラス名 */
className?: string
/** 閉じるボタンを押下、または表示してから8秒後に発火するコールバック関数 */
onClose: () => void
/** FlashMessage が表示されてから一定時間後に自動で閉じるかどうか */
autoClose?: boolean
}
} & VariantProps<typeof flashMessage>

type ElementProps = Omit<HTMLAttributes<HTMLDivElement>, keyof Props>
type ElementProps = Omit<ComponentPropsWithoutRef<'div'>, keyof Props>

const REMOVE_DELAY = 8000

const flashMessage = tv({
slots: {
wrapper: [
'smarthr-ui-FlashMessage',
'shr-border-shorthand shr-fixed shr-bottom-0.5 shr-left-0.5 shr-z-flash-message shr-flex shr-items-center shr-gap-0.5 shr-rounded-m shr-bg-white shr-p-1 shr-shadow-layer-4',
'[&_.smarthr-ui-Icon-withText]:-shr-my-0.25 [&_.smarthr-ui-Icon-withText]:shr-grow',
/* Icon + margin + 8文字 + margin + Button(border + padding + fontSize) */
'shr-min-w-[calc(1em+theme(spacing[0.5])+8em+theme(spacing[0.5])+(theme(borderWidth.DEFAULT)*2)+(theme(spacing[0.5])*2)+theme(fontSize.sm))]',
],
responseMessage: ['smarthr-ui-FlashMessage-icon', ''],
closeButton: ['smarthr-ui-FlashMessage-button', '-shr-my-0.5 -shr-mr-0.5'],
},
variants: {
animation: {
bounce: {
wrapper: [
'shr-animate-[flash-message-bounce_1s_0s_both]',
'motion-reduce:shr-animate-none',
],
},
none: {},
},
},
})

/**
* @deprecated `FlashMessage` は気づきにくいため、安易な使用はお勧めしません。`NotificationBar` や `Dialog` の使用を検討してください。
*/
Expand All @@ -44,14 +61,11 @@ export const FlashMessage: FC<Props & ElementProps> = ({
text,
animation = 'bounce',
role = 'alert',
className = '',
className,
onClose,
autoClose = true,
...props
...rest
}) => {
const theme = useTheme()
const classNames = useClassNames()

useEffect(() => {
if (!visible || !autoClose) {
return
Expand All @@ -63,121 +77,25 @@ export const FlashMessage: FC<Props & ElementProps> = ({
}
}, [autoClose, onClose, visible])

const { wrapperStyle, responseMessageStyle, closeButtonStyle } = useMemo(() => {
const { wrapper, responseMessage, closeButton } = flashMessage()
return {
wrapperStyle: wrapper({ animation, className }),
responseMessageStyle: responseMessage(),
closeButtonStyle: closeButton(),
}
}, [animation, className])

if (!visible) return null

return (
<Wrapper
{...props}
className={`${type} ${classNames.wrapper} ${className}`}
themes={theme}
animation={animation}
role={role}
>
<ResponseMessage type={type} iconGap={0.5} className={classNames.icon}>
<div {...rest} className={wrapperStyle} role={role}>
<ResponseMessage type={type} iconGap={0.5} className={responseMessageStyle}>
{text}
</ResponseMessage>
<CloseButton
themes={theme}
className={`close ${classNames.button}`}
onClick={onClose}
size="s"
square
>
<FaTimesIcon alt="閉じる" />
</CloseButton>
</Wrapper>
<Button className={closeButtonStyle} onClick={onClose} size="s" square>
<FaXmarkIcon alt="閉じる" />
</Button>
</div>
)
}

const bounceAnimation = keyframes`
from,
20%,
53%,
80%,
to {
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
transform: translate3d(0, 0, 0);
}
40%,
43% {
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
transform: translate3d(0, -30px, 0);
}
70% {
animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
transform: translate3d(0, -15px, 0);
}
90% {
transform: translate3d(0, -4px, 0);
}
`

const fadeAnimation = keyframes`
from {
opacity: 0;
}
to {
opacity: 1;
}
`

const Wrapper = styled.div<{ themes: Theme; animation: Props['animation'] }>`
${({ themes, animation }) => {
const { border, fontSize, space, radius, color, zIndex, shadow } = themes
let keyframe = bounceAnimation
switch (animation) {
case 'bounce':
keyframe = bounceAnimation
break
case 'fade':
keyframe = fadeAnimation
break
case 'none':
keyframe = fadeAnimation
break
}
return css`
z-index: ${zIndex.FLASH_MESSAGE};
position: fixed;
bottom: ${space(0.5)};
left: ${space(0.5)};
display: flex;
align-items: center;
gap: ${space(0.5)};
box-shadow: ${shadow.LAYER4};
border: ${border.shorthand};
border-radius: ${radius.m};
background-color: ${color.WHITE};
padding: ${space(1)};
/* Icon + margin + 8文字 + margin + Button(border + padding + fontSize) */
min-width: calc(
1em + ${space(0.5)} + 8em + ${space(0.5)} + (${border.lineWidth} * 2) + (${space(0.5)} * 2) +
${fontSize.S}
);
animation: ${keyframe} ${animation === 'none' ? '0.01s' : '1s'} 0s both;
@media (prefers-reduced-motion) {
animation-duration: 0.01s;
}
.smarthr-ui-Icon-withText {
flex-grow: 1;
margin-block: ${space(-0.25)};
}
`
}}
`

const CloseButton = styled(Button)<{ themes: Theme }>(
({ themes: { space } }) => css`
margin-block: ${space(-0.5)};
margin-inline-end: ${space(-0.5)};
`,
)
18 changes: 0 additions & 18 deletions src/components/FlashMessage/useClassNames.ts

This file was deleted.

2 changes: 2 additions & 0 deletions src/components/Icon/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ import {
FaSortUp,
FaSquarePlus,
FaSquarePollVertical,
FaStar,
FaSuitcaseMedical,
FaTable,
FaTableList,
Expand Down Expand Up @@ -296,6 +297,7 @@ export const FaSortIcon = /*#__PURE__*/ createIcon(FaSort)
export const FaSortUpIcon = /*#__PURE__*/ createIcon(FaSortUp)
export const FaSquarePlusIcon = /*#__PURE__*/ createIcon(FaSquarePlus)
export const FaSquarePollVerticalIcon = /*#__PURE__*/ createIcon(FaSquarePollVertical)
export const FaStarIcon = /*#__PURE__*/ createIcon(FaStar)
export const FaSuitcaseMedicalIcon = /*#__PURE__*/ createIcon(FaSuitcaseMedical)
export const FaTableIcon = /*#__PURE__*/ createIcon(FaTable)
export const FaTableListIcon = /*#__PURE__*/ createIcon(FaTableList)
Expand Down
17 changes: 17 additions & 0 deletions src/smarthr-ui-preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,23 @@ export default {
transform: 'translateY(0)',
},
},
'flash-message-bounce': {
'from, 20%, 53%, 80%, to': {
'animation-timing-function': 'cubic-bezier(0.215, 0.61, 0.355, 1)',
transform: 'translate3d(0, 0, 0)',
},
'40%, 43%': {
'animation-timing-function': 'cubic-bezier(0.755, 0.05, 0.855, 0.06)',
transform: 'translate3d(0, -30px, 0)',
},
'70%': {
'animation-timing-function': 'cubic-bezier(0.755, 0.05, 0.855, 0.06)',
transform: 'translate3d(0, -15px, 0)',
},
'90%': {
transform: 'translate3d(0, -4px, 0)',
},
},
}),
},
},
Expand Down

0 comments on commit a698fd6

Please sign in to comment.