Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Buttonの内部処理を整理する #5347

Draft
wants to merge 21 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
3bb40d3
chore: decoratorsのデフォルト文字列の持ち方を調整する
AtsushiM Jan 23, 2025
5ef9eda
chore: DecoratorsTypeの設置場所を移動
AtsushiM Jan 23, 2025
0d284e1
chore: useDecoratorsを定義
AtsushiM Jan 23, 2025
139d213
Merge branch 'master' of https://github.com/kufu/smarthr-ui into chor…
AtsushiM Jan 24, 2025
7f05277
chore: useDecoratorsにわたすgenericsを調整
AtsushiM Jan 24, 2025
10baf9d
chore: libs/decorator を hooks/useDecorators に移動
AtsushiM Jan 24, 2025
660292c
chore: fix stories
AtsushiM Jan 24, 2025
74f1c62
Merge branch 'master' of https://github.com/kufu/smarthr-ui into chor…
AtsushiM Jan 28, 2025
a8510c1
chore: Button/DisabledDetailのstyle生成をmemo化
AtsushiM Jan 29, 2025
31a93be
chore: Button/DisabledDetailのTooltipIconを切り出す
AtsushiM Jan 29, 2025
e1dbbb8
chore: ButtonWrapperのdisalbed時のonClick時の処理を定数化する
AtsushiM Jan 29, 2025
f41ab81
chore: ButtonWrapperのtvのslotsにdefaultではなくbuttonでstyleを定義する
AtsushiM Jan 29, 2025
d5128bc
chore: ButtonWrapperのstyleを整理する
AtsushiM Jan 29, 2025
7033ea7
chore: ButtonWrapperとButtonInnerを統合する
AtsushiM Jan 29, 2025
a903172
chore: ButtonWrapperのstyle生成を整理
AtsushiM Jan 29, 2025
b6841c4
chore: Buttonのstyle生成をmemo化
AtsushiM Jan 29, 2025
71a68ef
chore: Buttonの表示内容の条件判定を整理
AtsushiM Jan 29, 2025
8c8187f
Merge branch 'chore-add-use-decorators' into chore-refactoring-Button
AtsushiM Jan 29, 2025
125b965
chore: fix ci
AtsushiM Jan 29, 2025
09d8706
chore: fix ci
AtsushiM Jan 29, 2025
00ba3b5
chore: AncherButtonのrelはmemo化の効率がわるいため解除
AtsushiM Jan 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/smarthr-ui/src/components/Browser/Browser.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { FC, KeyboardEventHandler, useCallback, useMemo } from 'react'
import { tv } from 'tailwind-variants'

import { DecoratorsType } from '../../types'
import { type DecoratorsType } from '../../hooks/useDecorators'
import { Text } from '../Text'

import { BrowserColumn } from './BrowserColumn'
Expand Down
17 changes: 6 additions & 11 deletions packages/smarthr-ui/src/components/Button/AnchorButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { tv } from 'tailwind-variants'

import { ElementRef, ElementRefProps } from '../../types'

import { ButtonInner } from './ButtonInner'
import { ButtonWrapper } from './ButtonWrapper'
import { DisabledDetail } from './DisabledDetail'
import { BaseProps } from './types'
Expand Down Expand Up @@ -50,11 +49,7 @@ const AnchorButton = forwardRef(
}: PropsWithoutRef<Props<T>> & ElementProps<T>,
ref: Ref<ElementRef<T>>,
): ReactElement => {
const styles = useMemo(() => anchorButton({ className }), [className])
const actualRel = useMemo(
() => (rel === undefined && target === '_blank' ? 'noopener noreferrer' : rel),
[rel, target],
)
const style = useMemo(() => anchorButton({ className }), [className])

const button = (
<ButtonWrapper
Expand All @@ -63,16 +58,16 @@ const AnchorButton = forwardRef(
square={square}
wide={wide}
variant={variant}
className={styles}
className={style}
target={target}
rel={actualRel}
rel={rel === undefined && target === '_blank' ? 'noopener noreferrer' : rel}
isAnchor
anchorRef={ref}
elementAs={elementAs}
prefix={prefix}
suffix={suffix}
>
<ButtonInner prefix={prefix} suffix={suffix} size={size}>
{children}
</ButtonInner>
{children}
</ButtonWrapper>
)

Expand Down
78 changes: 49 additions & 29 deletions packages/smarthr-ui/src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
'use client'

import React, { ButtonHTMLAttributes, forwardRef, useMemo } from 'react'
import React, { ButtonHTMLAttributes, PropsWithChildren, forwardRef, useMemo } from 'react'
import { tv } from 'tailwind-variants'

import { type DecoratorsType, useDecorators } from '../../hooks/useDecorators'
import { usePortal } from '../../hooks/usePortal'
import { DecoratorsType } from '../../types'
import { Loader } from '../Loader'
import { VisuallyHiddenText } from '../VisuallyHiddenText'

import { ButtonInner } from './ButtonInner'
import { ButtonWrapper } from './ButtonWrapper'
import { DisabledDetail } from './DisabledDetail'
import { BaseProps } from './types'
Expand Down Expand Up @@ -39,10 +38,13 @@ const buttonStyle = tv({
})

export type Props = {
decorators?: DecoratorsType<'loading'>
decorators?: DecoratorsType<DecoratorKeyTypes>
}

const LOADING_TEXT = '処理中'
const DECORATOR_DEFAULT_TEXTS = {
loading: '処理中',
} as const
type DecoratorKeyTypes = keyof typeof DECORATOR_DEFAULT_TEXTS

export const Button = forwardRef<HTMLButtonElement, BaseProps & ElementProps & Props>(
(
Expand All @@ -64,24 +66,34 @@ export const Button = forwardRef<HTMLButtonElement, BaseProps & ElementProps & P
},
ref,
) => {
const { wrapper, loader: loaderSlot } = buttonStyle()
const wrapperStyle = useMemo(() => wrapper({ className }), [className, wrapper])
const loaderStyle = useMemo(
() => loaderSlot({ isSecondary: variant === 'secondary' }),
[loaderSlot, variant],
)
const { createPortal } = usePortal()
const styles = useMemo(() => {
const { wrapper, loader } = buttonStyle()

return {
wrapper: wrapper({ className }),
loader: loader({ isSecondary: variant === 'secondary' }),
}
}, [variant, className])

let actualPrefix = prefix
let actualSuffix = suffix
let disabledOnLoading = disabled
let actualChildren = children

const loader = <Loader size="s" className={loaderStyle} role="presentation" />
const actualPrefix = !loading && prefix
const actualSuffix = loading && !square ? loader : suffix
const disabledOnLoading = loading || disabled
const actualChildren = loading && square ? loader : children
if (loading) {
actualPrefix = undefined
disabledOnLoading = true

const loader = <Loader size="s" className={styles.loader} role="presentation" />

if (square) {
actualChildren = loader
} else {
actualSuffix = loader
}
}

const statusText = useMemo(() => {
const loadingText = decorators?.loading?.(LOADING_TEXT) ?? LOADING_TEXT
return loading ? loadingText : ''
}, [decorators, loading])
const decorated = useDecorators<DecoratorKeyTypes>(DECORATOR_DEFAULT_TEXTS, decorators)

const button = (
<ButtonWrapper
Expand All @@ -91,18 +103,15 @@ export const Button = forwardRef<HTMLButtonElement, BaseProps & ElementProps & P
square={square}
wide={wide}
variant={variant}
className={wrapperStyle}
className={styles.wrapper}
buttonRef={ref}
disabled={disabledOnLoading}
$loading={loading}
prefix={actualPrefix}
suffix={actualSuffix}
>
{
// `button` 要素内で live region を使うことはできないので、`role="status"` を持つ要素を外側に配置している。 https://github.com/kufu/smarthr-ui/pull/4558
createPortal(<VisuallyHiddenText role="status">{statusText}</VisuallyHiddenText>)
}
<ButtonInner prefix={actualPrefix} suffix={actualSuffix} size={size}>
{actualChildren}
</ButtonInner>
<LoadingStatus loading={loading}>{decorated.loading}</LoadingStatus>
{actualChildren}
</ButtonWrapper>
)

Expand All @@ -115,3 +124,14 @@ export const Button = forwardRef<HTMLButtonElement, BaseProps & ElementProps & P
)
// BottomFixedArea での判定に用いるために displayName を明示的に設定する
Button.displayName = 'Button'

const LoadingStatus = React.memo<PropsWithChildren<{ loading: boolean }>>(
({ loading, children }) => {
const { createPortal } = usePortal()

// `button` 要素内で live region を使うことはできないので、`role="status"` を持つ要素を外側に配置している。 https://github.com/kufu/smarthr-ui/pull/4558
return createPortal(
<VisuallyHiddenText role="status">{loading && children}</VisuallyHiddenText>,
)
},
)
35 changes: 0 additions & 35 deletions packages/smarthr-ui/src/components/Button/ButtonInner.tsx

This file was deleted.

Loading