diff --git a/site/source/components/Notifications.tsx b/site/source/components/Notifications.tsx index c8aa780ee..9cb4ceecb 100644 --- a/site/source/components/Notifications.tsx +++ b/site/source/components/Notifications.tsx @@ -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)` +const HideButton = styled(Button)` && { display: flex; align-items: center; diff --git a/site/source/components/RuleLink.tsx b/site/source/components/RuleLink.tsx index fd65751ca..a40c8507b 100644 --- a/site/source/components/RuleLink.tsx +++ b/site/source/components/RuleLink.tsx @@ -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' diff --git a/site/source/design-system/banner/index.ts b/site/source/design-system/banner/index.ts index ec41ad8f9..cfb83987d 100644 --- a/site/source/design-system/banner/index.ts +++ b/site/source/design-system/banner/index.ts @@ -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)` +export const HideButton = styled(Button)` display: flex; align-items: center; justify-content: center; diff --git a/site/source/design-system/buttons/Button.tsx b/site/source/design-system/buttons/Button.tsx index 05b6f6ac1..04bcfa3b8 100644 --- a/site/source/design-system/buttons/Button.tsx +++ b/site/source/design-system/buttons/Button.tsx @@ -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 ( + | (AriaButtonProps & ComponentPropsWithRef) + | AriaButtonProps<'button'> +) & { + openInSameWindow?: true +} + export type GenericCardProps = { title?: React.ReactNode children?: React.ReactNode diff --git a/site/source/design-system/typography/link.tsx b/site/source/design-system/typography/link.tsx index 885ecf7f8..77fb36b8b 100644 --- a/site/source/design-system/typography/link.tsx +++ b/site/source/design-system/typography/link.tsx @@ -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 & { + _style?: ComponentProps['style'] + _className?: ComponentProps['className'] + }, + forwardedRef: ForwardedRef +) { + const navLinkProps = { ...props } + delete navLinkProps._style + delete navLinkProps._className + + return ( + ({ + ...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 & ComponentPropsWithRef) | AriaButtonProps<'button'> ) & { openInSameWindow?: true - className?: string - style?: CSSProperties } export function useButtonOrLink( - props: GenericButtonOrLinkProps, + props: GenericButtonOrNavLinkProps, forwardedRef: ForwardedRef ) { - 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(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, } diff --git a/site/source/pages/Nouveautes/Nouveautes.tsx b/site/source/pages/Nouveautes/Nouveautes.tsx index bbe1a9b3a..476d44717 100644 --- a/site/source/pages/Nouveautes/Nouveautes.tsx +++ b/site/source/pages/Nouveautes/Nouveautes.tsx @@ -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)` +const SidebarLink = styled(Link)` display: block; border-radius: 0; padding: 0.5rem 1rem; diff --git a/site/source/pages/Simulateurs/EconomieCollaborative/index.tsx b/site/source/pages/Simulateurs/EconomieCollaborative/index.tsx index 7b6b66002..8a9a9c35f 100644 --- a/site/source/pages/Simulateurs/EconomieCollaborative/index.tsx +++ b/site/source/pages/Simulateurs/EconomieCollaborative/index.tsx @@ -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 (
(isActive ? { display: 'none' } : {})} to={indexPath} + end + style={({ isActive }) => (isActive ? { display: 'none' } : {})} > ←{' '} @@ -34,13 +37,11 @@ export default function ÉconomieCollaborative() {
- } /> + } /> } /> } />