Version de développement
Cette documentation décrit la version « next » (develop), non encore publiée. Pour la version stable, basculez sur « v5 » dans l'en-tête.
Composants UI

Composer

Référence des composants Vue EmailComposer et CommentComposer de @framework/ui pour rédiger un email ou un commentaire dans une application Dodock.

Composer

Le Composer est un éditeur de message pour les applications Vue construites sur Dodock. Il existe en deux composants qui partagent le même éditeur :

ComposantUsageEn-tête
EmailComposerRédiger un emailLignes « De », « À », « Cc », « Cci », « Objet », puis réponse citée
CommentComposerRédiger un commentaire interneAucun en-tête. Mentions @

Le Composer n'envoie rien lui-même. Au clic sur le bouton d'envoi, ou avec Ctrl+Entrée (⌘+Entrée sur Mac), il émet l'événement submit avec le contenu. Votre application fait l'envoi, puis appelle reset().

Importer le composant

Les deux composants sont exportés par le paquet @framework/ui (dossier ui/ de Dodock) :

import { EmailComposer, CommentComposer } from "@framework/ui";
// ou, depuis le sous-chemin du composant :
import { EmailComposer } from "@framework/ui/components/Composer";

Pour une fenêtre de réponse flottante, placez le composant dans FloatingWindow de frappe-ui.

Répondre à un email

<template>
    <EmailComposer
        ref="composer"
        v-model="body"
        v-model:to="to"
        v-model:cc="cc"
        v-model:quoted="quoted"
        show-subject
        v-model:subject="subject"
        :search-recipients="searchContacts"
        :submitting="sending"
        @submit="onSend"
    />
</template>

<script setup>
import { ref } from "vue";
import { call } from "frappe-ui";
import { EmailComposer } from "@framework/ui";

const composer = ref(null);
const body = ref("");
const to = ref([{ email: "camille.martin@example.com", label: "Camille Martin" }]);
const cc = ref([]);
const subject = ref("Re: Commande SAL-ORD-2026-00142");
const quoted = ref("<p>Bonjour, pouvez-vous confirmer la date de livraison ?</p>");
const sending = ref(false);

async function searchContacts(query) {
    const contacts = await call("frappe.client.get_list", {
        doctype: "Contact",
        fields: ["full_name", "email_id"],
        filters: [["email_id", "like", `%${query}%`]],
        limit_page_length: 10,
    });
    return contacts.map((c) => ({ email: c.email_id, label: c.full_name }));
}

async function onSend(payload) {
    sending.value = true;
    try {
        await call("frappe.core.doctype.communication.email.make", {
            recipients: payload.to.map((r) => r.email).join(", "),
            cc: payload.cc.map((r) => r.email).join(", "),
            subject: payload.subject,
            content: payload.body,
            send_email: 1,
        });
        composer.value.reset();
    } finally {
        sending.value = false;
    }
}
</script>

Exemple fictif. Les noms et adresses sont inventés. searchRecipients est appelée à chaque frappe, et une fois avec une chaîne vide à l'ouverture.

Propriétés communes

PropriétéTypeDéfautRôle
placeholderstring— (« This message is only visible to your team. » pour CommentComposer)Texte affiché dans le corps vide.
submitLabelstring— (« Comment » pour CommentComposer)Libellé du bouton d'envoi.
submittingbooleanfalseL'application est en train d'envoyer. Le bouton affiche un indicateur et ignore les clics.
uploadFunction(file: File) => Promise—Envoi des images insérées dans le corps.
maxAttachmentsnumber10Nombre maximum de pièces jointes. Au-delà, le bouton de pièce jointe est désactivé et une notification Attachment limit reached (10). s'affiche.
allowedFileTypesstring[][] (tous)Types acceptés, en extensions (".pdf") ou en types MIME ("image/*"). Un fichier refusé est ignoré et une notification s'affiche : "<nom>" was skipped — file type not allowed. Le serveur revérifie le type.
extensionsExtension[]—Extensions Tiptap ajoutées après les extensions standard. Lues une seule fois, au montage.

Propriétés d'EmailComposer

PropriétéDéfautRôle
showTo, showCc, showBcctrueAffichent les lignes « À », « Cc » et « Cci ».
showFrom, showSubjectfalseAffichent les lignes « De » et « Objet ».
senders—Identités proposées dans la ligne « De » : tableau de { email, label }.
searchRecipients—Fonction de recherche des destinataires. Sans elle, le champ accepte seulement des adresses saisies.

Modèles v-model : body (modèle par défaut), from, to, cc, bcc, subject, quoted. Un destinataire est un objet { email, label?, image? }.

Destinataires

Chaque destinataire s'affiche en jeton, avec son avatar. Les lignes « Cc » et « Cci » s'ouvrent avec leur bouton. Fermer une ligne vide ses destinataires, pour qu'aucun ne soit envoyé sans être visible.

Glissez un jeton vers une autre ligne pour déplacer le destinataire, par exemple de « À » à « Cc ». Pendant le glissement, les lignes « Cc » et « Cci » s'ouvrent si showCc et showBcc sont actifs.

Réponse citée

Le texte de quoted s'affiche sous le corps, dans un bloc repliable « ••• ». Le bloc reste hors de l'éditeur pour garder le HTML d'origine (tableaux, styles). À l'envoi, le Composer ajoute ce bloc à la fin de body.

Propriétés de CommentComposer

CommentComposer accepte les propriétés communes, plus mentions : tableau de { label, value }. label est affiché dans la liste, value est inséré dans le texte.

<CommentComposer
    v-model="comment"
    :mentions="[{ label: 'Camille Martin', value: 'camille.martin@example.com' }]"
    @submit="onComment"
/>

Événements

ÉvénementContenuQuand
submitEmailComposer : { from, subject, to, cc, bcc, body, attachments }. CommentComposer : { body, attachments }.Clic sur le bouton d'envoi ou Ctrl+Entrée. Le Composer ne valide pas les champs.
remove-attachmentLe fichier retiréL'utilisateur retire une pièce jointe. Supprimez alors le fichier sur le serveur si besoin.

Une pièce jointe est un objet { name, file_name, file_url, file_type, file_size }, comme le renvoie l'envoi de fichier.

Méthodes

Accédez aux méthodes avec une référence de modèle (ref) :

MéthodeRôle
reset()Vide le corps, les pièces jointes et la réponse citée. EmailComposer vide aussi les destinataires et l'objet, mais garde l'expéditeur.
focus()Place le curseur dans le corps.
submit()Déclenche l'envoi, comme le bouton.
editorInstance de l'éditeur Tiptap.

La touche Échap appelle aussi reset(), sauf si une liste ouverte (mentions) l'a déjà utilisée.

Emplacements (slots)

EmplacementComposantRôle
headerEmailComposerRemplace les lignes d'en-tête. Un modèle vide n'affiche aucun en-tête.
actionsles deuxActions supplémentaires à côté du bouton de pièce jointe. Reçoit addAttachment(file) et setUploading(value) pour un envoi de fichier personnalisé.
attachmentsles deuxRemplace l'affichage des pièces jointes. Reçoit attachments et remove(file).
footerles deuxContenu fixé entre le corps et la barre d'outils : avertissement, réponses enregistrées…
<EmailComposer ref="composer" v-model="body" v-model:to="to" @submit="onSend">
    <template #header>
        <div class="px-2.5 pb-1 text-p-sm text-ink-gray-5">Réponse à Camille Martin</div>
    </template>
</EmailComposer>