Document
Usage
MeDocument composes MeLayout, MeHeader, MeDocumentToolbar and MeDocumentView into a full document screen, driven entirely by mode and the v-model payload. No branch of markup differs between create and edit, only the initial data does. read renders every field as plain text. summary is read with no app shell, for a preview pane, a modal or a page of its own; see Summary mode.
The chassis knows nothing about any document type. Sections, labels, cards and per-mode visibility all come from the payload.
<template>
<MeDocument
v-model="formData"
:document="document"
mode="create"
/>
</template>
<script setup lang="ts">
import { DocumentFieldType, type DocumentFormData, type DocumentMeta } from '@mercadoeletronico/eds-next'
const document: DocumentMeta = { type: 'request', number: '', title: 'Novo documento' }
const formData = ref<DocumentFormData>({
sections: [
{
id: 'campos-de-texto',
label: 'Campos de texto',
fields: [
{ label: 'Campo de texto', value: '', type: DocumentFieldType.text }
]
}
]
})
</script>
Field schema
Every field is a DocumentField: a value alone renders as plain text; adding type (+ config) renders the matching editable input (MeInput, UTextarea, UInputNumber, MeInputDate, USelect, UCheckbox). Fields group into DocumentFormSection/DocumentFormSubsection. A disabled field in config automatically gets variant: 'soft' (unless it already sets its own variant), and help renders as a tooltip after a longer-than-default hover.
A link renders the value as a hyperlink. It is orthogonal to type on purpose: type picks an input, and a link is how the value is displayed, so a field only renders as a link where it renders as plain text. That includes every field in read, since the read transform strips type.
Sections
A section is identified by id and titled by label. Two things beyond fields:
modeslimits the section to some of the three full-page screens. Omitted, it appears in all of them. A section holding decisions made while writing the document typically declaresmodes: ['create', 'edit'].summarykeeps the section in the condensed read. Opt-in and independent ofmodes; see Summary mode.component+componentPropsreplace the field grid with a component of your own, for a section the chassis has no renderer for (a table, an attachment grid, a timeline). Forwarded straight toMeDocumentView, which takes it over the slot. Wrap it inmarkRaw, or Vue proxies it once it lands in reactive data.kindpicks the body renderer; see Section kinds for the table of kinds and their data.
Summary mode
mode="summary" renders the same payload as the condensed read of the document: what a preview pane, a modal or a page of its own shows before the reader opens the full document. Three things change, nothing else:
- No app shell. No
UApp, noMeLayout, noMeHeader: the pane or modal that holds the summary already has them. The toolbar, when the consumer passes one, is drawn as the document's own band above the Forehead. There is no default toolbar in this mode: a condensed document with nothing to press draws no band, rather than aVoltarthat leads nowhere inside a pane. - Only the sections that opted in. A section stays by declaring
summary: true, whatever itsmodessay. Nothing opts in by default: a summary is a choice of what stays, and a default of everything would be no summary. Party cards still render. - Container-driven spacing.
MeDocumentViewgetscompact: the gutter and the gap between sections follow the width of the box the summary sits in, not the viewport, and the view has no scroll box of its own because the container scrolls.
The Forehead needs no extra data: identity, statuses, total, trailing facts, progress and workflow steps are the same DocumentMeta the full read carries.
<template>
<MeDocument
v-model="payload"
:document="document"
mode="summary"
:toolbar="toolbar"
/>
</template>
Party cards
cards renders above the sections, in edit and read only: a document being created has no parties resolved yet. A banner card renders full width through MeForehead; a tile card, the default, joins a row that fills the width whatever the card count. Each card is a role eyebrow, a title and a list of { label, value } rows.
API
Props
| Prop | Default | Type |
|---|---|---|
document | DocumentMeta Passed to MeDocumentView, see DocumentView. The number is blanked while mode is 'create'. Also takes identity, trailingFacts, progressLabel, steps and alerts (alerts above the Forehead, as data), see DocumentView. | |
mode | 'create' | 'edit' | 'read' | 'summary' summary is the condensed read with no app shell, see Summary mode. | |
actions | per mode | ButtonBarAction[] Overrides the default toolbar. Defaults: Criar/Cancelar, Salvar/Cancelar, Voltar. |
sectionNav | false | boolean Turns on the anchor strip. Forwarded to MeDocumentView, see DocumentView. |
header | built-in mock | DocumentHeaderConfig User, brand, navigation and profile items for MeHeader. |
Model
| Model | Type |
|---|---|
v-model | DocumentFormData { sections: DocumentFormSection[], cards?: DocumentPartyCard[] }. |
A section's kind and its data are described on the template page and below, under Payload reference.
Slots
| Slot | Description |
|---|---|
alerts | Markup above the Forehead, after the document.alerts drawn from data. Escape hatch: a modal that must live inside the chassis's UApp goes here too. |
rail | A column beside the scroll box, e.g. MePhasesPanel. The rail stays put while the sections scroll. |
section-<id>-actions | Controls in a section's header row, beside the approval state when the section carries one. |
section-<id>-footer | Replaces the section's footer. Only hand it on when filled: the shell draws a footer box on the slot's presence. |
Events
| Event | Payload | Description |
|---|---|---|
copy | value: string | The Forehead copied the document number. The screen may raise a toast; the chassis does not. |
copyError | value: string | The copy failed. |
itemAction | sectionId: string, name: string, item: DocumentItem | A control inside an item row was pressed. What it opens is the document's business. |
identityAction | name: 'edit' | 'chat' | 'issuedByChat' | A control in the Forehead's identity block was pressed: the edit pencil or one of the two chat controls. Same rule: the chassis names the control, the page decides what it opens. |
Payload reference
Three objects describe a document in read mode. All of them are plain data: a page generator can produce them and nothing in them names a document type.
document: DocumentMeta
{
type: 'preorder', // picks the badge label and icon from documentTypes.ts
number: '15392701',
subNumber: '#ME 23088952', // a second identifier under the number in the badge (`Série 33`, `ME# 570844`)
title: 'Demonstração',
alerts: [{ id: 'offer', title: '...', description: '...', color: 'primary', link: { label: '...', href: '#' } }],
identity: {
title: '...',
editAction: true, // the edit pencil beside the title; set by the page, since access is its rule
issuedBy: { label: 'Requisitante', value: '...', chatAction: true, note: 'Who issued the document...' },
facts: [{ label: 'Fornecedor', value: '...' }]
},
total: { currency: 'BRL', amount: '1.320,375' },
statuses: [{ kind: 'Status do processo', label: 'APROVAÇÃO NÍVEL 1', color: 'warning' }],
trailingFacts: [{ label: 'Criado em', value: '04/09/2026 03:04:42' }, { label: 'Atualizado em', value: '04/09/2026 23:32:30' }],
progress: 32, progressLabel: 'Utilizado: BRL 0,0000 (0,00%)',
steps: [{ label: 'Condições Gerais', done: true }, { label: 'Confirmação', current: true }]
}
A document with two trailing dates (a Pedido prints Criado em ... - Atualizado em ...) carries two trailingFacts; there is no field for the second date. The pencil and the chat controls emit identityAction with their name and nothing else: the legacy opens an edit page from the pencil and Genius Orchestration edits the title inline from the same control, so the chassis cannot know which one a page wants. issuedBy.note is a tooltip, not a control, and emits nothing.
modelValue: DocumentFormData
{ sections: DocumentFormSection[], cards?: DocumentPartyCard[] }. A party card (role, title, variant: 'banner' | 'tile', rows or lines (each line { text, icon?, link? }), codeChip, chatAction, mapHref, statuses) renders above the sections. Every section has id, label, an optional kind (the field grid when omitted), description, footer (a sentence or { text, legend }), empty (starts collapsed) and count (derived from the rows when omitted). The data a section carries depends on its kind:
kind | Data | Shape |
|---|---|---|
fields | fields, subsections | DocumentField[]: { label, value }, or lines: string[], link: { label, href }, attachments: { count, href }, span: 'full', tone, icon. |
table | table, selectable | { title, columns: [{ accessorKey, header }], rows: [{ id, ...cells }] }. A cell is a string, a number, { label, href }, { badge }, { statusIcon }, { attachments }, { actions } or an array of those. |
items | items, totals | { columns, items: DocumentItem[], selectable, search, emptyCell, pinActions, actions, expandAll, toggle: { toDetail, toSummary }, massActions: [{ label, icon, requiresSelection }] }. An item is { id, title, values, badges?, status?, detail?: { fields, tables, attachments } }. |
approval | history, currentState | { steps: [{ title, description, pendingNote, icon, done }], columns: [{ key, header }], rows: [{ id, ...cells, statusVariant, hasLog }], legend }; currentState is a sentence or { title, badge, at } beside the section title. |
attachments | attachments | [{ label, count, href, files? }], one slot per attachment group. |
totals | totals | [{ label, value, emphasis? }]. |
cards | cards | InfoCardData[], a wrapping row of cards. |
empty | message | The empty-state sentence. A list kind with no rows prints its message the same way. |
tabs | tabs | [{ id, label, kind, ...the kind's data }]: link tabs under the section header, one body per tab (a Cotação's approval history has a "Cotação Criada" and a "Cotação Fechada" tab). |
toolbar: DocumentToolbarProps
{ actions: ButtonBarProps, options?: DropdownMenuItem[][], views?: DocumentToolbarView[] }. The bar is ghost primary by default; actions beyond maxVisibleActions go to the bar's own overflow menu, options is the Opções dropdown on the right and views the view switch beside it.
A complete example per document type lives in packages/ui/app/review/documents/, rendered by the review route /document-read?doc=<slug> of the packages/ui dev server.
Notes
- Consumed by pages that hand it a payload (see Documentos), not routed at a fixed path itself, which is why it's documented and ejected as a block rather than a
registry:pagetemplate. - Fields are mutated in place: the chassis writes edits straight into
field.value. A payload built by mapping from another shape must pass the sameDocumentFieldinstances through rather than cloning them, or the form will silently stop writing back. - A document type is a payload, not a component: its field shape is whatever its page generator sends, and nothing of it lives here.