Composer
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 :
| Composant | Usage | En-tête |
|---|---|---|
EmailComposer | Rédiger un email | Lignes « De », « À », « Cc », « Cci », « Objet », puis réponse citée |
CommentComposer | Rédiger un commentaire interne | Aucun 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é | Type | Défaut | Rôle |
|---|---|---|---|
placeholder | string | — (« This message is only visible to your team. » pour CommentComposer) | Texte affiché dans le corps vide. |
submitLabel | string | — (« Comment » pour CommentComposer) | Libellé du bouton d'envoi. |
submitting | boolean | false | L'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. |
maxAttachments | number | 10 | Nombre 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. |
allowedFileTypes | string[] | [] (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. |
extensions | Extension[] | — | Extensions Tiptap ajoutées après les extensions standard. Lues une seule fois, au montage. |
Propriétés d'EmailComposer
| Propriété | Défaut | Rôle |
|---|---|---|
showTo, showCc, showBcc | true | Affichent les lignes « À », « Cc » et « Cci ». |
showFrom, showSubject | false | Affichent 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énement | Contenu | Quand |
|---|---|---|
submit | EmailComposer : { 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-attachment | Le 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éthode | Rô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. |
editor | Instance de l'éditeur Tiptap. |
La touche Échap appelle aussi reset(), sauf si une liste ouverte (mentions) l'a déjà utilisée.
Emplacements (slots)
| Emplacement | Composant | Rôle |
|---|---|---|
header | EmailComposer | Remplace les lignes d'en-tête. Un modèle vide n'affiche aucun en-tête. |
actions | les deux | Actions supplémentaires à côté du bouton de pièce jointe. Reçoit addAttachment(file) et setUploading(value) pour un envoi de fichier personnalisé. |
attachments | les deux | Remplace l'affichage des pièces jointes. Reçoit attachments et remove(file). |
footer | les deux | Contenu 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>