Navigation principale - DsfrNavigation 
🌟 Introduction 
Le système de navigation principal permet d'orienter les utilisateurs à travers l'application. Il constitue l'épine dorsale de la navigation d'un site, offrant une structure claire et accessible pour explorer les différentes sections et fonctionnalités.
Le composant DsfrNavigation est le système central de navigation au sein d'un site. Il permet d'orienter aisément l'usager à travers l'application avec une structure hiérarchique claire et des menus déroulants.
🏅 La documentation sur la navigation sur le DSFR
La story sur la navigation sur le storybook de VueDsfr📐 Structure 
La navigation principale est composée des éléments suivants :
- un conteneur principal avec un identifiant unique (prop id)
- un label d'accessibilité (prop label)
- une liste de liens et sous-menus (prop navItems) organisée hiérarchiquement
- des menus déroulants qui s'ouvrent/ferment au clic
- une gestion des événements clavier pour l'accessibilité (touches Échap, flèches)
🛠️ Props 
| nom | type | défaut | obligatoire | description | 
|---|---|---|---|---|
| id | string | () => useRandomId(...) | Identifiant unique pour la navigation | |
| label | string | 'Menu principal' | Nom associé à la navigation pour l'accessibilité | |
| navItems | array | () => [] | ✅ | Tableau contenant les liens ou sous-menus de la navigation | 
📡 Événements 
DsfrNavigation déclenche les événements suivants :
| nom | donnée (payload) | description | 
|---|---|---|
| click | aucune | Émis au clic qui déclenche l'ouverture ou la fermeture d'un menu | 
| keydown | aucune | Émis en appuyant sur Échap qui déclenche la fermeture d'un menu ouvert | 
🧩 Slots 
DsfrNavigation possède un slot par défaut pour le contenu personnalisé de la navigation.
| nom | description | 
|---|---|
| default | Slot par défaut pour le contenu personnalisé de la navigation | 
📝 Exemples 
Exemple simple d'utilisation de DsfrNavigation :
<script lang="ts" setup>
import DsfrNavigation from '../DsfrNavigation.vue'
const navItemsDemo = [
  {
    to: '/accueil',
    text: 'Accueil',
  },
  {
    to: '/tableau-de-bord',
    text: 'Tableau de bord',
  },
  {
    to: '/historique',
    text: 'Historique',
  },
]
</script>
<template>
  <DsfrNavigation
    label="Menu principal démo"
    :nav-items="navItemsDemo"
  />
</template>⚙️ Code source du composant 
<script lang="ts" setup>
import type {
  DsfrNavigationMegaMenuProps,
  DsfrNavigationMenuLinkProps,
  DsfrNavigationMenuLinks,
  DsfrNavigationMenuProps,
  DsfrNavigationProps,
} from './DsfrNavigation.types'
import { onMounted, onUnmounted, ref } from 'vue'
import { useRandomId } from '../../utils/random-utils'
import DsfrNavigationItem from './DsfrNavigationItem.vue'
import DsfrNavigationMegaMenu from './DsfrNavigationMegaMenu.vue'
import DsfrNavigationMenu from './DsfrNavigationMenu.vue'
import DsfrNavigationMenuLink from './DsfrNavigationMenuLink.vue'
export type { DsfrNavigationMenuLinks, DsfrNavigationProps }
const props = withDefaults(defineProps<DsfrNavigationProps>(), {
  id: () => useRandomId('nav'),
  label: 'Menu principal',
  navItems: () => [],
})
const expandedMenuId = ref<string | undefined>(undefined)
const toggle = (id: string | undefined) => {
  if (id === expandedMenuId.value) {
    expandedMenuId.value = undefined
    return
  }
  expandedMenuId.value = id
}
const handleElementClick = (el: HTMLElement) => {
  if (el === document.getElementById(props.id)) {
    return
  }
  if (!el?.parentNode) {
    toggle(expandedMenuId.value)
    return
  }
  handleElementClick(el.parentNode as HTMLElement)
}
const onDocumentClick = (e: MouseEvent) => {
  handleElementClick(e.target as HTMLElement)
}
const onKeyDown = (e: KeyboardEvent) => {
  if (e.key === 'Escape') {
    toggle(expandedMenuId.value)
  }
}
onMounted(() => {
  document.addEventListener('click', onDocumentClick)
  document.addEventListener('keydown', onKeyDown)
})
onUnmounted(() => {
  document.removeEventListener('click', onDocumentClick)
  document.removeEventListener('keydown', onKeyDown)
})
</script>
<template>
  <nav
    :id="id"
    class="fr-nav"
    role="navigation"
    :aria-label="label"
  >
    <ul class="fr-nav__list">
      <!-- @slot Slot par défaut pour le contenu de la liste. Sera dans `<ul class="fr-nav__list">` -->
      <slot />
      <DsfrNavigationItem
        v-for="(navItem, idx) of navItems"
        :id="navItem.id"
        :key="idx"
      >
        <DsfrNavigationMenuLink
          v-if="(navItem as DsfrNavigationMenuLinkProps).to && (navItem as DsfrNavigationMenuLinkProps).text"
          v-bind="navItem"
          :expanded-id="expandedMenuId"
          @toggle-id="toggle($event)"
        />
        <!-- @vue-ignore -->
        <DsfrNavigationMenu
          v-else-if="(navItem as DsfrNavigationMenuProps).title && (navItem as DsfrNavigationMenuProps).links"
          v-bind="(navItem as DsfrNavigationMenuProps)"
          :expanded-id="expandedMenuId"
          @toggle-id="toggle($event)"
        />
        <!-- @vue-ignore -->
        <DsfrNavigationMegaMenu
          v-else-if="(navItem as DsfrNavigationMegaMenuProps).title && (navItem as DsfrNavigationMegaMenuProps).menus"
          v-bind="(navItem as DsfrNavigationMegaMenuProps)"
          :expanded-id="expandedMenuId"
          @toggle-id="toggle($event)"
        />
      </DsfrNavigationItem>
    </ul>
  </nav>
</template>
<style>
.fr-nav__list {
  position: relative;
}
</style>import type { RouteLocationRaw } from 'vue-router'
export type DsfrNavigationMenuLinkProps = {
  id?: string
  to?: string | RouteLocationRaw
  text?: string
  icon?: string
  onClick?: ($event: MouseEvent) => void
}
export type DsfrNavigationMenuItemProps = {
  id?: string
  active?: boolean
}
export type DsfrNavigationMenuProps = {
  id?: string
  title: string
  links?: DsfrNavigationMenuLinkProps[]
  expandedId?: string
  active?: boolean
}
export type DsfrNavigationItemProps = {
  id?: string
  active?: boolean
}
export type DsfrNavigationMegaMenuCategoryProps = {
  title: string
  active?: boolean
  links: DsfrNavigationMenuLinkProps[]
}
export type DsfrNavigationMegaMenuProps = {
  id?: string
  title: string
  description?: string
  link?: { to: RouteLocationRaw, text: string }
  menus?: DsfrNavigationMegaMenuCategoryProps[]
  expandedId?: string
  active?: boolean
}
export type DsfrNavigationMenuLinks = (DsfrNavigationMenuLinkProps | DsfrNavigationMegaMenuProps | DsfrNavigationMenuProps)[]
export type DsfrNavigationProps = {
  id?: string
  label?: string
  navItems: (
    DsfrNavigationMenuLinkProps
    | DsfrNavigationMenuProps
    | DsfrNavigationMegaMenuProps
  )[]
}