@@ -11,6 +11,7 @@ import type { FrIconClassName, RiIconClassName } from "./fr/generatedFromCss/cla
1111import { id } from "tsafe/id" ;
1212import { ModalProps } from "./Modal" ;
1313import { getBrandTopAndHomeLinkProps } from "./zz_internal/brandTopAndHomeLinkProps" ;
14+ import { typeGuard } from "tsafe/typeGuard" ;
1415
1516export type FooterProps = {
1617 className ?: string ;
@@ -22,7 +23,7 @@ export type FooterProps = {
2223 personalDataLinkProps ?: RegisteredLinkProps ;
2324 cookiesManagementLinkProps ?: RegisteredLinkProps ;
2425 cookiesManagementButtonProps ?: ModalProps . ModalButtonProps ;
25- bottomItems ?: FooterProps . BottomItem [ ] ;
26+ bottomItems ?: ( FooterProps . BottomItem | ReactNode ) [ ] ;
2627 partnersLogos ?: FooterProps . PartnersLogos ;
2728 operatorLogo ?: {
2829 orientation : "horizontal" | "vertical" ;
@@ -395,98 +396,76 @@ export const Footer = memo(
395396 ...( websiteMapLinkProps === undefined
396397 ? [ ]
397398 : [
398- id < FooterProps . BottomItem > ( {
399- "text" : t ( "website map" ) ,
400- "linkProps" : websiteMapLinkProps
401- } )
402- ] ) ,
399+ id < FooterProps . BottomItem > ( {
400+ "text" : t ( "website map" ) ,
401+ "linkProps" : websiteMapLinkProps
402+ } )
403+ ] ) ,
403404 id < FooterProps . BottomItem > ( {
404405 "text" : `${ t ( "accessibility" ) } : ${ t ( accessibility ) } ` ,
405406 "linkProps" : accessibilityLinkProps ?? { }
406407 } ) ,
407408 ...( termsLinkProps === undefined
408409 ? [ ]
409410 : [
410- id < FooterProps . BottomItem > ( {
411- "text" : t ( "terms" ) ,
412- "linkProps" : termsLinkProps
413- } )
414- ] ) ,
411+ id < FooterProps . BottomItem > ( {
412+ "text" : t ( "terms" ) ,
413+ "linkProps" : termsLinkProps
414+ } )
415+ ] ) ,
415416 ...( personalDataLinkProps === undefined
416417 ? [ ]
417418 : [
418- id < FooterProps . BottomItem > ( {
419- "text" : t ( "personal data" ) ,
420- "linkProps" : personalDataLinkProps
421- } )
422- ] ) ,
419+ id < FooterProps . BottomItem > ( {
420+ "text" : t ( "personal data" ) ,
421+ "linkProps" : personalDataLinkProps
422+ } )
423+ ] ) ,
423424 ...( cookiesManagementButtonProps === undefined
424425 ? // one or the other, but not both. Priority to button for consent modal control.
425- cookiesManagementLinkProps === undefined
426+ cookiesManagementLinkProps === undefined
426427 ? [ ]
427428 : [
428- id < FooterProps . BottomItem > ( {
429- "text" : t ( "cookies management" ) ,
430- "linkProps" : cookiesManagementLinkProps
431- } )
432- ]
429+ id < FooterProps . BottomItem > ( {
430+ "text" : t ( "cookies management" ) ,
431+ "linkProps" : cookiesManagementLinkProps
432+ } )
433+ ]
433434 : [
434- id < FooterProps . BottomItem > ( {
435- "text" : t ( "cookies management" ) ,
436- "buttonProps" :
437- cookiesManagementButtonProps . nativeButtonProps
438- } )
439- ] ) ,
435+ id < FooterProps . BottomItem > ( {
436+ "text" : t ( "cookies management" ) ,
437+ "buttonProps" :
438+ cookiesManagementButtonProps . nativeButtonProps
439+ } )
440+ ] ) ,
440441 ...bottomItems
441- ] . map ( ( { iconId, text, buttonProps, linkProps } , i ) => (
442- < li
443- key = { i }
444- className = { cx (
445- fr . cx ( "fr-footer__bottom-item" ) ,
446- classes . bottomItem
447- ) }
448- >
449- { ( ( ) => {
450- const className = cx (
451- fr . cx (
452- "fr-footer__bottom-link" ,
453- ...( iconId !== undefined
454- ? ( [ iconId , "fr-link--icon-left" ] as const )
455- : [ ] )
456- ) ,
457- classes . bottomLink
458- ) ;
459-
460- return linkProps !== undefined ? (
461- Object . keys ( linkProps ) . length === 0 ? (
462- < span className = { className } > { text } </ span >
463- ) : (
464- < Link
465- { ...linkProps }
466- className = { cx ( className , linkProps . className ) }
467- >
468- { text }
469- </ Link >
470- )
442+ ] . map ( ( bottomItem , i ) =>
443+ < li className = { cx ( fr . cx ( "fr-footer__bottom-item" ) , classes . bottomItem , className ) } key = { i } >
444+ {
445+ ! typeGuard < FooterProps . BottomItem > (
446+ bottomItem ,
447+ bottomItem instanceof Object && "text" in bottomItem
448+ ) ? (
449+ bottomItem
471450 ) : (
472- < button
473- { ... buttonProps }
474- className = { cx ( className , buttonProps . className ) }
475- >
476- { text }
477- </ button >
478- ) ;
479- } ) ( ) }
451+ < FooterBottomItem
452+ classes = { {
453+ "bottomLink" : classes . bottomLink
454+ } }
455+ bottomItem = { bottomItem }
456+ / >
457+ )
458+ }
480459 </ li >
481- ) ) }
460+ ) }
482461 </ ul >
483462 < div className = { cx ( fr . cx ( "fr-footer__bottom-copy" ) , classes . bottomCopy ) } >
484463 < p >
485464 { license === undefined
486465 ? t ( "license mention" , {
487- "licenseUrl" :
488- "https://github.com/etalab/licence-ouverte/blob/master/LO.md"
489- } )
466+ "licenseUrl" :
467+ "https://github.com/etalab/licence-ouverte/blob/master/LO.md"
468+ } )
490469 : license }
491470 </ p >
492471 </ div >
@@ -557,3 +536,47 @@ addFooterTranslations({
557536} ) ;
558537
559538export { addFooterTranslations } ;
539+
540+ export type FooterBottomItemProps = {
541+ className ?: string ;
542+ bottomItem : FooterProps . BottomItem ;
543+ classes ?: Partial < Record < "root" | "bottomLink" , string > > ;
544+ } ;
545+
546+ export function FooterBottomItem ( props : FooterBottomItemProps ) : JSX . Element {
547+ const { className : className_props , bottomItem, classes = { } } = props ;
548+
549+ const { Link } = getLink ( ) ;
550+
551+ const className = cx (
552+ fr . cx (
553+ "fr-footer__bottom-link" ,
554+ ...( bottomItem . iconId !== undefined
555+ ? ( [ bottomItem . iconId , "fr-link--icon-left" ] as const )
556+ : [ ] )
557+ ) ,
558+ classes . bottomLink ,
559+ classes . root ,
560+ className_props
561+ ) ;
562+
563+ return bottomItem . linkProps !== undefined ? (
564+ Object . keys ( bottomItem . linkProps ) . length === 0 ? (
565+ < span className = { className } > { bottomItem . text } </ span >
566+ ) : (
567+ < Link
568+ { ...bottomItem . linkProps }
569+ className = { cx ( className , bottomItem . linkProps . className ) }
570+ >
571+ { bottomItem . text }
572+ </ Link >
573+ )
574+ ) : (
575+ < button
576+ { ...bottomItem . buttonProps }
577+ className = { cx ( className , bottomItem . buttonProps . className ) }
578+ >
579+ { bottomItem . text }
580+ </ button >
581+ ) ;
582+ }
0 commit comments