Update Link for react-router v6 isActive function in style/clasName props

pull/2249/head
Jérémy Rialland 2022-07-21 17:37:05 +02:00 committed by Jérémy Rialland
parent 289a9e91e5
commit 6d0edba3b1
8 changed files with 87 additions and 29 deletions

View File

@ -2,7 +2,7 @@ import { hideNotification } from '@/actions/actions'
import { useEngine, useInversionFail } from '@/components/utils/EngineContext'
import { Message } from '@/design-system'
import { Button } from '@/design-system/buttons'
import { GenericButtonOrLinkProps } from '@/design-system/typography/link'
import { GenericButtonOrNavLinkProps } from '@/design-system/typography/link'
import { RootState } from '@/reducers/rootReducer'
import { DottedName } from 'modele-social'
import Engine, { RuleNode } from 'publicodes'
@ -95,7 +95,7 @@ export default function Notifications() {
)
}
const HideButton = styled(Button)<GenericButtonOrLinkProps>`
const HideButton = styled(Button)<GenericButtonOrNavLinkProps>`
&& {
display: flex;
align-items: center;

View File

@ -2,7 +2,6 @@ import { Link } from '@/design-system/typography/link'
import { DottedName } from 'modele-social'
import { RuleLink as EngineRuleLink } from 'publicodes-react'
import React, { useContext } from 'react'
import { NavLink } from 'react-router-dom'
import { EngineContext } from './utils/EngineContext'
import { SitePathsContext } from './utils/SitePathsContext'

View File

@ -1,5 +1,5 @@
import { Button } from '@/design-system/buttons'
import { GenericButtonOrLinkProps } from '@/design-system/typography/link'
import { GenericButtonOrNavLinkProps } from '@/design-system/typography/link'
import styled from 'styled-components'
export const Banner = styled.div`
@ -23,7 +23,7 @@ export const InnerBanner = styled.div`
border-radius: 0.375rem;
`
export const HideButton = styled(Button)<GenericButtonOrLinkProps>`
export const HideButton = styled(Button)<GenericButtonOrNavLinkProps>`
display: flex;
align-items: center;
justify-content: center;

View File

@ -1,6 +1,6 @@
import { FocusStyle } from '@/design-system/global-style'
import {
GenericButtonOrLinkProps,
GenericButtonOrNavLinkProps,
useButtonOrLink,
} from '@/design-system/typography/link'
import { wrapperDebounceEvents } from '@/utils'
@ -10,7 +10,7 @@ import styled, { css } from 'styled-components'
type Size = 'XL' | 'MD' | 'XS' | 'XXS'
type Color = 'primary' | 'secondary' | 'tertiary'
type ButtonProps = GenericButtonOrLinkProps & {
type ButtonProps = GenericButtonOrNavLinkProps & {
color?: Color
children: React.ReactNode
size?: Size
@ -22,7 +22,6 @@ export const Button = forwardRef(function Button(
size = 'MD',
light = false,
color = 'primary' as const,
className,
isDisabled,
...ariaButtonProps
}: ButtonProps,
@ -36,7 +35,6 @@ export const Button = forwardRef(function Button(
return (
<StyledButton
{...buttonOrLinkProps}
className={className}
$size={size}
$light={light}
$color={color}

View File

@ -2,15 +2,24 @@ import { StyledButton } from '@/design-system/buttons/Button'
import { FocusStyle } from '@/design-system/global-style'
import { H3, H4, HeadingUnderline } from '@/design-system/typography/heading'
import {
GenericButtonOrLinkProps,
NewWindowLinkIcon,
useButtonOrLink,
useExternalLinkProps,
} from '@/design-system/typography/link'
import { Body } from '@/design-system/typography/paragraphs'
import React, { ReactHTML, useRef } from 'react'
import { AriaButtonProps } from '@react-types/button'
import React, { ComponentPropsWithRef, ReactHTML, useRef } from 'react'
import { Link as BaseLink } from 'react-router-dom'
import styled, { css, ThemeProvider } from 'styled-components'
type GenericButtonOrLinkProps = (
| AriaButtonProps<'a'>
| (AriaButtonProps<typeof BaseLink> & ComponentPropsWithRef<typeof BaseLink>)
| AriaButtonProps<'button'>
) & {
openInSameWindow?: true
}
export type GenericCardProps = {
title?: React.ReactNode
children?: React.ReactNode

View File

@ -2,8 +2,8 @@ import { FocusStyle } from '@/design-system/global-style'
import { useButton } from '@react-aria/button'
import { AriaButtonProps } from '@react-types/button'
import React, {
ComponentProps,
ComponentPropsWithRef,
CSSProperties,
ForwardedRef,
useCallback,
useRef,
@ -59,7 +59,7 @@ export const StyledLink = styled.a<{ $isDisabled?: boolean }>`
export const Link = React.forwardRef<
HTMLAnchorElement | HTMLButtonElement,
GenericButtonOrLinkProps & {
GenericButtonOrNavLinkProps & {
children: React.ReactNode
isDisabled?: boolean
}
@ -111,22 +111,56 @@ export function useExternalLinkProps({
}
}
export type GenericButtonOrLinkProps = (
const CustomNavLink = React.forwardRef(function CustomNavLink(
props: ComponentProps<typeof NavLink> & {
_style?: ComponentProps<typeof NavLink>['style']
_className?: ComponentProps<typeof NavLink>['className']
},
forwardedRef: ForwardedRef<HTMLAnchorElement | null>
) {
const navLinkProps = { ...props }
delete navLinkProps._style
delete navLinkProps._className
return (
<NavLink
{...navLinkProps}
style={(...p) => ({
...props.style,
...(typeof props._style === 'function' && props._style(...p)),
})}
className={(...p) => {
const styledClass =
(typeof props.className === 'function'
? props.className(...p)
: props.className) ?? ''
const originalClass =
(typeof props._className === 'function'
? props._className(...p)
: props._className) ?? ''
return styledClass + ' ' + originalClass
}}
ref={forwardedRef}
/>
)
})
export type GenericButtonOrNavLinkProps = (
| AriaButtonProps<'a'>
| (AriaButtonProps<typeof NavLink> & ComponentPropsWithRef<typeof NavLink>)
| AriaButtonProps<'button'>
) & {
openInSameWindow?: true
className?: string
style?: CSSProperties
}
export function useButtonOrLink(
props: GenericButtonOrLinkProps,
props: GenericButtonOrNavLinkProps,
forwardedRef: ForwardedRef<HTMLAnchorElement | HTMLButtonElement | null>
) {
const elementType: 'a' | 'button' | typeof NavLink =
'href' in props ? 'a' : 'to' in props ? NavLink : 'button'
const elementType: 'a' | 'button' | typeof CustomNavLink =
'href' in props ? 'a' : 'to' in props ? CustomNavLink : 'button'
const defaultRef = useRef<HTMLAnchorElement | HTMLButtonElement | null>(null)
const { buttonProps } = useButton({ elementType, ...props }, defaultRef)
@ -157,10 +191,24 @@ export function useButtonOrLink(
)
)
// resolve conflict between styled-component and NavLink style props
const styleProps =
'to' in props && typeof props.style === 'function'
? { _style: props.style, style: undefined }
: {}
// resolve conflict between styled-component and NavLink classname props
const classNameProps =
'to' in props && typeof props.className === 'function'
? { _className: props.className, className: undefined }
: {}
const buttonOrLinkProps = {
...initialProps,
...buttonProps,
...useExternalLinkProps(props),
...classNameProps,
...styleProps,
as: elementType,
ref,
}

View File

@ -8,7 +8,10 @@ import { SitePathsContext } from '@/components/utils/SitePathsContext'
import { Item, Select } from '@/design-system/field/Select'
import { Container, Grid } from '@/design-system/layout'
import { H1 } from '@/design-system/typography/heading'
import { GenericButtonOrLinkProps, Link } from '@/design-system/typography/link'
import {
GenericButtonOrNavLinkProps,
Link,
} from '@/design-system/typography/link'
import { Body } from '@/design-system/typography/paragraphs'
import { useFetchData } from '@/hooks/useFetchData'
import { useContext, useMemo } from 'react'
@ -156,7 +159,7 @@ const DesktopGridItem = styled(Grid).attrs({ item: true, lg: 3 })`
}
`
const SidebarLink = styled(Link)<GenericButtonOrLinkProps>`
const SidebarLink = styled(Link)<GenericButtonOrNavLinkProps>`
display: block;
border-radius: 0;
padding: 0.5rem 1rem;

View File

@ -1,6 +1,7 @@
import { useIsEmbedded } from '@/components/utils/embeddedContext'
import { SitePathsContext } from '@/components/utils/SitePathsContext'
import { Link } from '@/design-system/typography/link'
import { useRelativeSitePaths } from '@/sitePaths'
import { useContext } from 'react'
import { Trans } from 'react-i18next'
import { Route, Routes } from 'react-router-dom'
@ -12,19 +13,21 @@ import { StoreProvider } from './StoreContext'
import VotreSituation from './VotreSituation'
export default function ÉconomieCollaborative() {
const relativeSitePaths = useRelativeSitePaths()
const { économieCollaborative } = useContext(SitePathsContext).simulateurs
const iframePath =
useSimulatorsData()['économie-collaborative'].iframePath ?? ''
const indexPath = useIsEmbedded()
? '/iframes/' + iframePath
? `/iframes/${iframePath}`
: économieCollaborative.index
return (
<TrackChapter chapter1="simulateurs" chapter2="economie_collaborative">
<div css="transform: translateY(2rem)">
<Link
style={({ isActive }) => (isActive ? { display: 'none' } : {})}
to={indexPath}
end
style={({ isActive }) => (isActive ? { display: 'none' } : {})}
>
{' '}
<Trans i18nKey="économieCollaborative.retourAccueil">
@ -34,13 +37,11 @@ export default function ÉconomieCollaborative() {
</div>
<StoreProvider localStorageKey="app::économie-collaborative:v1">
<Routes>
<Route path={'/'} element={<ActivitésSelection />} />
<Route index element={<ActivitésSelection />} />
<Route
// TODO: react-router 6 use relative path now, we need to get relative path from sitepath instead of this replace
path={économieCollaborative.votreSituation.replace(
économieCollaborative.index,
''
)}
path={
relativeSitePaths.simulateurs.économieCollaborative.votreSituation
}
element={<VotreSituation />}
/>
<Route path={':title'} element={<Activité />} />