Save France

Composants

Documentation des composants réutilisables et modulaires de l'application

Vue d'Ensemble

Cette section documente tous les composants réutilisables de l'application, organisés par catégorie. Chaque composant est conçu pour être modulaire, réutilisable et facilement personnalisable.

Catégories de Composants

  1. Composants Partagés
    • Composants génériques réutilisables dans toute l'application
    • Inclut les éléments d'interface utilisateur de base
  2. Composants de Mise en Page
    • Structure globale de l'application
    • En-têtes, pieds de page et systèmes de grille
  3. Composants d'Équipement
    • Affichage et gestion des équipements
    • Formulaires de création/édition
  4. Composants de Contact
    • Formulaires de contact
    • Cartes de contact et informations
  5. Composants de Tarification
    • Tableaux comparatifs
    • Sélecteurs d'options tarifaires

Bonnes Pratiques

Création de Nouveaux Composants

  1. Structure de Fichier
    components/
    └── feature/
        ├── ComponentName.vue    # Le composant principal
        ├── ComponentName.ts     # Logique TypeScript
        ├── ComponentName.spec.ts # Tests
        └── index.ts            # Export du composant
    
  2. Conventions de Nommage
    • Utilisez la casse PascalCase pour les noms de fichiers
    • Les noms doivent être descriptifs et en anglais
    • Préfixez les composants avec leur domaine (ex: EquipmentCard.vue)
  3. Documentation
    • Documentez toutes les props, événements et slots
    • Incluez des exemples d'utilisation
    • Ajoutez des notes sur les cas particuliers

Guide de Style

Structure d'un Composant

<template>
  <div class="component-name">
    <!-- Contenu du composant -->
  </div>
</template>

<script setup lang="ts">
// Imports
import { ref } from 'vue';

// Props
defineProps({
  /** Description de la prop */
  title: {
    type: String,
    required: true,
    validator: (value: string) => value.length > 0
  }
});

// Événements
const emit = defineEmits<{
  (e: 'update:modelValue', value: string): void;
  (e: 'submit'): void;
}>();

// Logique du composant
const count = ref(0);
</script>

<styles scoped>
.component-name {
  /* Styles spécifiques au composant */
}
</styles>

Règles de Style

  1. Séparation des Préoccupations
    • Une seule responsabilité par composant
    • Logique métier dans des composables séparés
    • Styles isolés avec scoped
  2. Accessibilité
    • Utilisez des balises sémantiques
    • Implémentez la navigation au clavier
    • Ajoutez des attributs ARIA
  3. Performance
    • Utilisez v-if au lieu de v-show pour les éléments rarement affichés
    • Évitez les re-rendus inutiles avec v-memo
    • Utilisez le lazy loading pour les composants lourds

Contribution

  1. Processus de Revue
    • Créez une branche pour vos modifications
    • Soumettez une pull request avec une description claire
    • Assurez-vous que les tests passent
  2. Tests
    • Écrivez des tests unitaires pour la logique
    • Testez les cas limites et les erreurs
    • Vérifiez le support des différents navigateurs
  3. Documentation
    • Mettez à jour la documentation du composant
    • Ajoutez des exemples d'utilisation
    • Documentez les changements dans le CHANGELOG.md

Composants Documentés

Composants Partagés

Composants de Layout

Ressources

Modèles

Nouveau Composant

<template>
  <div class="component-name">
    <slot />
  </div>
</template>

<script setup lang="ts">
// Imports
import { ref } from 'vue';

// Props
const props = defineProps({
  /**
   * Titre du composant
   * @required
   */
  title: {
    type: String,
    required: true
  },
  
  /**
   * État actif
   * @default false
   */
  active: {
    type: Boolean,
    default: false
  }
});

// Événements
const emit = defineEmits<{
  /** Émis lors du clic */
  (e: 'click', event: MouseEvent): void;
  
  /** Émis lors de la mise à jour de la valeur */
  (e: 'update:modelValue', value: string): void;
}>();

// Logique du composant
const count = ref(0);

// Méthodes exposées
defineExpose({
  /** Réinitialise le compteur */
  reset: () => {
    count.value = 0;
  }
});
</script>

<style scoped>
.component-name {
  /* Styles de base */
  padding: 1rem;
  border: 1px solid #e2e8f0;
  border-radius: 0.375rem;
  
  /* Styles conditionnels */
  &[data-active] {
    border-color: #3b82f6;
    background-color: #eff6ff;
  }
}
</style>

Test Unitaire de Base

// tests/components/__tests__/ComponentName.spec.ts
import { mount } from '@vue/test-utils';
import { describe, it, expect } from 'vitest';
import ComponentName from '../ComponentName.vue';

describe('ComponentName', () => {
  it('affiche le titre', () => {
    const wrapper = mount(ComponentName, {
      props: {
        title: 'Mon Titre'
      }
    });
    
    expect(wrapper.text()).toContain('Mon Titre');
  });
  
  it('émet un événement au clic', async () => {
    const wrapper = mount(ComponentName);
    
    await wrapper.trigger('click');
    
    expect(wrapper.emitted('click')).toHaveLength(1);
  });
});