Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { type ComponentPropsWithoutRef, type ReactNode, memo, useMemo } from 'react'
import { tv } from 'tailwind-variants'

// Shared className generator for AppHeader button styling
// Used to maintain consistent styling across dropdown menus and navigation items
export const commonButtonClassNameGenerator = tv({
base: [
'[&&]:shr-box-border [&&]:shr-flex [&&]:shr-w-full [&&]:shr-cursor-pointer [&&]:shr-items-center [&&]:shr-border-none [&&]:shr-bg-transparent [&&]:shr-px-1 [&&]:shr-py-0.5 [&&]:shr-text-base [&&]:shr-leading-normal [&&]:shr-text-black [&&]:shr-no-underline',
Expand Down Expand Up @@ -34,47 +35,3 @@ export const commonButtonClassNameGenerator = tv({
rounded: true,
},
})

type AnchorProps = Omit<ComponentPropsWithoutRef<'a'>, 'prefix'>
type ButtonProps = Omit<ComponentPropsWithoutRef<'button'>, 'prefix'>

type Props = (({ elementAs: 'a' } & AnchorProps) | ({ elementAs: 'button' } & ButtonProps)) & {
prefix?: ReactNode
current?: boolean
boldWhenCurrent?: boolean
}

export const CommonButton = memo<Props>(
({ elementAs, prefix, current, boldWhenCurrent, className, children, ...rest }) => {
const actualClassName = useMemo(
() =>
commonButtonClassNameGenerator({
prefix: !!prefix,
current,
boldWhenCurrent,
className,
}),
[current, prefix, boldWhenCurrent, className],
)

switch (elementAs) {
case 'a':
return (
<a {...(rest as AnchorProps)} className={actualClassName}>
{prefix}
{children}
</a>
)
case 'button':
return (
// eslint-disable-next-line smarthr/best-practice-for-button-element
<button {...(rest as ButtonProps)} className={actualClassName}>
{prefix}
{children}
</button>
)
}

throw new Error(elementAs satisfies never)
},
)
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { FaCaretDownIcon, FaGearIcon, FaUserIcon } from '../../../Icon'
import { Cluster, Stack } from '../../../Layout'
import { Text } from '../../../Text'
import { buildDisplayName } from '../../utils'
import { CommonButton } from '../common/CommonButton'
import { commonButtonClassNameGenerator } from '../common/CommonButton'
import { Translate } from '../common/Translate'

import type { HeaderProps, UserInfoProps } from '../../types'
Expand Down Expand Up @@ -300,17 +300,20 @@ const DisplayNameDropdownTrigger = memo<PropsWithChildren<{ className: string }>
),
)

const AccountLink = memo<PropsWithChildren<{ href?: string | null }>>(
({ href, children }) =>
const AccountLink = memo<PropsWithChildren<{ href?: string | null }>>(({ href, children }) => {
const buttonClassName = useMemo(() => commonButtonClassNameGenerator(), [])

return (
href && (
<CommonButton
elementAs="a"
<AnchorButton
href={href}
target="_blank"
rel="noopener noreferrer"
prefix={<FaGearIcon />}
className={buttonClassName}
>
<Translate>{children}</Translate>
</CommonButton>
),
)
</AnchorButton>
)
)
})
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { type FC, memo, useMemo } from 'react'

import { useIntl } from '../../../../intl'
import { Button } from '../../../Button'
import { AnchorButton, Button } from '../../../Button'
import { Dropdown, DropdownContent, DropdownTrigger } from '../../../Dropdown'
import { FaCircleQuestionIcon, FaGraduationCapIcon } from '../../../Icon'
import { CommonButton } from '../common/CommonButton'
import { commonButtonClassNameGenerator } from '../common/CommonButton'
import { Translate } from '../common/Translate'

type Props = {
Expand Down Expand Up @@ -53,29 +53,31 @@ const ContentBody = memo<Props>(({ helpPageUrl, schoolUrl }) => {
[localize],
)

const buttonClassName = useMemo(() => commonButtonClassNameGenerator(), [])

return (
<div className="shr-p-0.5">
{helpPageUrl && (
<CommonButton
elementAs="a"
<AnchorButton
href={helpPageUrl}
target="_blank"
rel="noopener noreferrer"
prefix={<FaCircleQuestionIcon />}
className={buttonClassName}
>
<Translate>{translated.help}</Translate>
</CommonButton>
</AnchorButton>
)}
{schoolUrl && (
<CommonButton
elementAs="a"
<AnchorButton
href={schoolUrl}
target="_blank"
rel="noopener noreferrer"
prefix={<FaGraduationCapIcon />}
className={buttonClassName}
>
<Translate>{translated.school}</Translate>
</CommonButton>
</AnchorButton>
)}
</div>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Button } from '../../../Button'
import { Heading } from '../../../Heading'
import { FaCheckIcon, FaXmarkIcon } from '../../../Icon'
import { Section } from '../../../SectioningContent'
import { CommonButton } from '../common/CommonButton'
import { commonButtonClassNameGenerator } from '../common/CommonButton'

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

Expand Down Expand Up @@ -96,15 +96,21 @@ const LocaleButton = memo<{
className: string
children: string
onClick: (e: MouseEvent<HTMLButtonElement>) => void
}>(({ value, selected, className, children, onClick }) => (
<CommonButton
elementAs="button"
type="button"
value={value}
onClick={onClick}
prefix={selected && <FaCheckIcon color="MAIN" />}
className={className}
>
{children}
</CommonButton>
))
}>(({ value, selected, className, children, onClick }) => {
const buttonClassName = useMemo(
() => commonButtonClassNameGenerator({ className }),
[className],
)

return (
<Button
type="button"
value={value}
onClick={onClick}
prefix={selected ? <FaCheckIcon color="MAIN" /> : undefined}
className={buttonClassName}
>
{children}
</Button>
)
})
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
import { type PropsWithChildren, memo } from 'react'
import { type PropsWithChildren, memo, useMemo } from 'react'

import { Button } from '../../../Button'
import { FaAngleRightIcon } from '../../../Icon'
import { CommonButton } from '../common/CommonButton'
import { commonButtonClassNameGenerator } from '../common/CommonButton'
import { Translate } from '../common/Translate'

type Props = PropsWithChildren<{
onClick: () => void
isCurrent?: boolean
}>

export const MenuButton = memo<Props>(({ children, onClick, isCurrent }) => (
<CommonButton
elementAs="button"
type="button"
onClick={onClick}
current={isCurrent}
boldWhenCurrent
className="[&&]:shr-justify-between [&&]:shr-px-0.5"
>
<Translate>{children}</Translate>
<FaAngleRightIcon color="TEXT_BLACK" />
</CommonButton>
))
export const MenuButton = memo<Props>(({ children, onClick, isCurrent }) => {
const buttonClassName = useMemo(
() =>
commonButtonClassNameGenerator({
current: isCurrent,
boldWhenCurrent: true,
className: '[&&]:shr-justify-between [&&]:shr-px-0.5',
}),
[isCurrent],
)

return (
<Button type="button" onClick={onClick} className={buttonClassName}>
<Translate>{children}</Translate>
<FaAngleRightIcon color="TEXT_BLACK" />
</Button>
)
})
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { type FC, type MouseEvent, memo, useCallback, useContext, useMemo } from 'react'
import { tv } from 'tailwind-variants'

import { AnchorButton, Button } from '../../../Button'
import { isChildNavigation } from '../../utils'
import { CommonButton, commonButtonClassNameGenerator } from '../common/CommonButton'
import { commonButtonClassNameGenerator } from '../common/CommonButton'
import { Translate } from '../common/Translate'

import { MenuButton } from './MenuButton'
import { NavigationContext } from './NavigationContext'

import type {
Navigation,
NavigationButton,
NavigationButton as NavigationButtonType,
NavigationCustomTag,
NavigationGroup,
NavigationLink,
NavigationLink as NavigationLinkType,
} from '../../types'

const classNameGenerator = tv({
Expand Down Expand Up @@ -81,16 +82,23 @@ const NavigationCustomTag = memo<
},
)

const NavigationLink = memo<NavigationLink & { className: string }>(
({ href, current, children, className }) => (
<CommonButton elementAs="a" href={href} current={current} boldWhenCurrent className={className}>
<Translate>{children}</Translate>
</CommonButton>
),
const NavigationLink = memo<NavigationLinkType & { className: string }>(
({ href, current, children, className }) => {
const buttonClassName = useMemo(
() => commonButtonClassNameGenerator({ current, boldWhenCurrent: true, className }),
[current, className],
)

return (
<AnchorButton href={href} className={buttonClassName}>
<Translate>{children}</Translate>
</AnchorButton>
)
},
)

const NavigationButton: FC<
Pick<Props, 'onClickNavigation'> & { navigation: NavigationButton; className: string }
Pick<Props, 'onClickNavigation'> & { navigation: NavigationButtonType; className: string }
> = ({ navigation, onClickNavigation, className }) => {
const onClick = useCallback(
(e: MouseEvent<HTMLButtonElement>) => {
Expand All @@ -100,17 +108,15 @@ const NavigationButton: FC<
[navigation, onClickNavigation],
)

const buttonClassName = useMemo(
() => commonButtonClassNameGenerator({ current: navigation.current, boldWhenCurrent: true, className }),
[navigation.current, className],
)

return (
<CommonButton
elementAs="button"
type="button"
onClick={onClick}
current={navigation.current}
boldWhenCurrent
className={className}
>
<Button type="button" onClick={onClick} className={buttonClassName}>
<Translate>{navigation.children}</Translate>
</CommonButton>
</Button>
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import {
} from 'react'
import { tv } from 'tailwind-variants'

import { Button } from '../../../Button'
import { Dropdown, DropdownContent, DropdownTrigger } from '../../../Dropdown'
import { FaCaretDownIcon } from '../../../Icon'
import { Text } from '../../../Text'
import { CommonButton } from '../common/CommonButton'
import { commonButtonClassNameGenerator } from '../common/CommonButton'

import type { Header } from '../../../Header'

Expand Down Expand Up @@ -90,18 +91,21 @@ const TenantDropdown: FC<
<div className="shr-p-0.5">
{tenants.map((tenant) => {
const isCurrent = tenant.id === currentTenantId
const buttonClassName = useMemo(
() => commonButtonClassNameGenerator({ current: isCurrent }),
[isCurrent],
)

return (
<CommonButton
<Button
key={tenant.id}
elementAs="button"
type="button"
value={tenant.id}
current={isCurrent}
onClick={isCurrent ? undefined : onClickTenantName}
className={buttonClassName}
>
{tenant.name}
</CommonButton>
</Button>
)
})}
</div>
Expand Down
Loading
Loading