Workflow Diagram
Editor de fluxo interativo com nos, arestas conectaveis, zoom/pan, painel de propriedades e toolbar. Baseado em React (@xyflow/react) e executado como ilha isolada dentro do monolito PHP.
Uso
Quando e como utilizar o editor de fluxo para modelar processos com nos e arestas conectaveis.
- JSON data — Carrega nos e arestas de um endpoint JSON via atributo
data-propsno container. O componente faz fetch automatico ao montar. - Inline data — Dados passados diretamente no atributo
data-propscomo JSON serializado, sem fetch externo. - Programmatic — Monta a ilha manualmente via
ArenitoIslands.mount()passando o elemento container e as props como objeto JavaScript.
Exemplos
Veja abaixo os exemplos interativos do editor de fluxo, incluindo toolbar, painel de propriedades e diferentes tipos de nos.
Anatomia
Estrutura interna do componente e seus elementos.
| Parte | Elemento | Descricao |
|---|---|---|
| Container | .workflow-diagram | Wrapper principal com position relative e width 100% |
| Toolbar | .workflow-diagram__toolbar | Barra de ferramentas superior com flex row e gap 8px |
| Toolbar Btn | .workflow-diagram__toolbar-btn | Botao da toolbar, Inter 13px w500 |
| Btn Primary | .workflow-diagram__toolbar-btn--primary | Modificador com background brand e texto branco |
| Separator | .workflow-diagram__toolbar-separator | Divisor vertical 1px entre grupos de botoes |
| Body | .workflow-diagram__body | Flex container para canvas e painel lateral |
| Canvas | .workflow-diagram__canvas | Area do ReactFlow com nodes, edges e controles |
| Panel | .workflow-diagram__panel | Painel lateral de propriedades, width 280px |
| Panel Title | .workflow-diagram__panel-title | Titulo do painel, Space Grotesk 14px w600 |
| Panel Field | .workflow-diagram__panel-field | Grupo de campo com label + input |
| Panel Label | .workflow-diagram__panel-label | Label do campo, Inter 12px, texto secundario |
| Panel Input | .workflow-diagram__panel-input | Input com borda e focus ring |
| Node | .workflow-diagram__node | No base 60x60, circular, border 2px solid |
| Node Start | .workflow-diagram__node--start | No inicial com fill verde #10B981 |
| Node Process | .workflow-diagram__node--process | No de processo com fill azul accent-300 |
| Node Decision | .workflow-diagram__node--decision | No de decisao losango, rotacao 45deg, #F59E0B |
| Node End | .workflow-diagram__node--end | No final com fill vermelho #EF4444 |
| Node Label | .workflow-diagram__node-label | Texto do no, Inter 11px, text-align center |
| Edge Label | .workflow-diagram__edge-label | Label da aresta com background e borda arredondada |
| Minimap | .workflow-diagram__minimap | Minimap no canto inferior direito com opacity 0.7 |
| Vazio | .workflow-diagram__empty | Estado sem dados, borda dashed e padding 48px |
Tipos de Nos
O editor suporta 4 tipos de nos com estilos visuais e posicoes de Handle distintas.
Cada tipo de no possui um estilo visual especifico que indica sua funcao no fluxo. Os Handles (pontos de conexao) sao posicionados de acordo com a semantica do no.
| Tipo | Classe modificadora | Estilo visual | Handles |
|---|---|---|---|
| Start | .workflow-diagram__node--start | Circulo verde (#10B981), border 2px | 1 source (bottom) |
| Process | .workflow-diagram__node--process | Circulo azul (accent-300), border 2px | 1 target (top), 1 source (bottom) |
| Decision | .workflow-diagram__node--decision | Losango amarelo (#F59E0B), rotacao 45deg | 1 target (top), 2 sources (right, bottom) |
| End | .workflow-diagram__node--end | Circulo vermelho (#EF4444), border 2px | 1 target (top) |
O no de decisao usa transform: rotate(45deg) no container e rotate(-45deg) no label para manter o texto legivel. As arestas que saem do no de decisao podem receber labels como "Sim" e "Nao" via .workflow-diagram__edge-label.
Eventos
CustomEvents disparados pelo componente para integracao com o monolito PHP.
O Workflow Diagram emite CustomEvents no elemento container para que o codigo do monolito possa reagir a acoes do usuario sem acoplar-se ao React.
| Evento | detail | Quando dispara |
|---|---|---|
arenito:workflow:save | { nodes: Node[], edges: Edge[] } | Usuario clica no botao Salvar da toolbar |
arenito:workflow:node-click | { nodeId: string, nodeType: string, data: object } | Usuario clica em um no do diagrama |
document.querySelector('[data-island="WorkflowDiagram"]')
.addEventListener('arenito:workflow:save', (e) => {
console.log('Nodes:', e.detail.nodes);
console.log('Edges:', e.detail.edges);
});Propriedades
Classes CSS disponiveis para configurar o editor de fluxo.
| Propriedade | Tipo | Default | Descrição |
|---|---|---|---|
.workflow-diagram | classe | — | Container principal do editor de fluxo. |
.workflow-diagram__toolbar | classe | — | Barra de ferramentas superior com botoes de acao. |
.workflow-diagram__toolbar-btn | classe | — | Botao individual da toolbar (13px w500). |
.workflow-diagram__toolbar-btn--primary | classe | — | Modificador para botao primario (background brand). |
.workflow-diagram__toolbar-separator | classe | — | Separador vertical entre grupos de botoes. |
.workflow-diagram__body | classe | — | Wrapper flex do canvas e painel lateral. |
.workflow-diagram__canvas | classe | — | Area do ReactFlow com nodes e edges. |
.workflow-diagram__panel | classe | — | Painel lateral de propriedades do no selecionado (280px). |
.workflow-diagram__panel-title | classe | — | Titulo do painel de propriedades (14px w600). |
.workflow-diagram__panel-field | classe | — | Grupo de campo no painel (label + input). |
.workflow-diagram__panel-label | classe | — | Label do campo (12px, texto secundario). |
.workflow-diagram__panel-input | classe | — | Input do campo com borda e focus state. |
.workflow-diagram__node | classe | — | No customizado base (60x60, circular, border 2px). |
.workflow-diagram__node--start | classe | — | No inicial verde (#10B981). |
.workflow-diagram__node--process | classe | — | No de processo azul (accent-300). |
.workflow-diagram__node--decision | classe | — | No de decisao losango (rotacao 45deg, #F59E0B). |
.workflow-diagram__node--end | classe | — | No final vermelho (#EF4444). |
.workflow-diagram__node-label | classe | — | Label de texto do no (11px, text-align center). |
.workflow-diagram__edge-label | classe | — | Label da aresta com background e borda. |
.workflow-diagram__minimap | classe | — | Minimap posicionado no canto inferior direito. |
.workflow-diagram__empty | classe | — | Estado vazio com borda tracejada. |
Codigo
Snippets prontos para copiar e usar no seu projeto.
HTML com data-island e data-props
<div data-island="WorkflowDiagram"
data-props='{
"nodes": [
{ "id": "1", "type": "start", "position": { "x": 250, "y": 0 }, "data": { "label": "Inicio" } },
{ "id": "2", "type": "process", "position": { "x": 250, "y": 120 }, "data": { "label": "Analise" } },
{ "id": "3", "type": "decision", "position": { "x": 250, "y": 240 }, "data": { "label": "Aprovado?" } },
{ "id": "4", "type": "end", "position": { "x": 250, "y": 360 }, "data": { "label": "Fim" } }
],
"edges": [
{ "id": "e1-2", "source": "1", "target": "2" },
{ "id": "e2-3", "source": "2", "target": "3" },
{ "id": "e3-4", "source": "3", "target": "4", "label": "Sim" }
]
}'>
</div>Montagem programatica via ArenitoIslands.mount()
const container = document.getElementById('workflow-container');
ArenitoIslands.mount(container, 'WorkflowDiagram', {
nodes: [
{ id: '1', type: 'start', position: { x: 250, y: 0 }, data: { label: 'Inicio' } },
{ id: '2', type: 'process', position: { x: 250, y: 120 }, data: { label: 'Revisao' } },
{ id: '3', type: 'decision', position: { x: 250, y: 240 }, data: { label: 'OK?' } },
{ id: '4', type: 'end', position: { x: 250, y: 360 }, data: { label: 'Concluido' } }
],
edges: [
{ id: 'e1-2', source: '1', target: '2' },
{ id: 'e2-3', source: '2', target: '3' },
{ id: 'e3-4', source: '3', target: '4', label: 'Sim' }
]
});Integracao com Factory (PHP)
<div id="workflow-fiscalizacao"
data-island="WorkflowDiagram"
data-endpoint="/api/workflow/fiscalizacao/<?= $processo_id ?>">
</div>
<script src="/assets/arenito-islands.js"></script>Fonte de Dados
O componente aceita dados em JSON com arrays de nodes e edges seguindo o schema do ReactFlow.
JSON (formato recomendado)
O objeto JSON raiz contem dois arrays: nodes para os nos do diagrama e edges para as conexoes entre eles.
{
"nodes": [
{
"id": "1",
"type": "start",
"position": { "x": 250, "y": 0 },
"data": { "label": "Cadastro" }
},
{
"id": "2",
"type": "process",
"position": { "x": 250, "y": 120 },
"data": { "label": "Analise Documental" }
},
{
"id": "3",
"type": "decision",
"position": { "x": 250, "y": 240 },
"data": { "label": "Documentos OK?" }
},
{
"id": "4",
"type": "end",
"position": { "x": 250, "y": 360 },
"data": { "label": "Aprovado" }
}
],
"edges": [
{ "id": "e1-2", "source": "1", "target": "2" },
{ "id": "e2-3", "source": "2", "target": "3" },
{ "id": "e3-4", "source": "3", "target": "4", "label": "Sim" },
{ "id": "e3-2", "source": "3", "target": "2", "label": "Nao" }
]
}Mapeamento de campos
| Campo | Tipo | Obrigatorio | Descricao |
|---|---|---|---|
id | string | Sim | Identificador unico do no ou aresta |
type | string | Sim | Tipo do no: start, process, decision ou end |
position | object | Sim | Coordenadas { x, y } do no no canvas |
data | object | Sim | Dados do no, incluindo label para o texto exibido |
source | string | Sim (edge) | ID do no de origem da aresta |
target | string | Sim (edge) | ID do no de destino da aresta |
label | string | Nao (edge) | Texto exibido na aresta (ex: "Sim", "Nao") |
Dark Mode
O editor de fluxo adapta automaticamente ao tema escuro via classe .dark.
No dark mode, o canvas recebe um fundo escuro e os nos ajustam suas cores de borda e fill para manter contraste adequado. O painel lateral e a toolbar seguem os tokens semanticos de superficie.
| Propriedade | Light | Dark |
|---|---|---|
| Canvas background | --surface-base-neutral-container-default | --surface-base-neutral-container-default |
| Toolbar background | --surface-base-neutral-container-emphasis | --surface-base-neutral-container-emphasis |
| Node border | rgba(0,0,0,0.15) | rgba(255,255,255,0.15) |
| Node label color | --text-base-neutral-default | --text-base-neutral-default |
| Edge stroke | --border-base-neutral-default | --border-base-neutral-default |
| Edge label background | --surface-base-neutral-container-default | --surface-base-neutral-container-default |
| Panel background | --surface-base-neutral-container-emphasis | --surface-base-neutral-container-emphasis |
| Panel input border | --border-base-neutral-default | --border-base-neutral-default |
| Minimap background | rgba(0,0,0,0.06) | rgba(255,255,255,0.06) |
Os tokens semanticos de superficie e texto herdam automaticamente os valores do dark mode. A toolbar e o painel lateral mantam a mesma estrutura em ambos os temas, ajustando apenas cores de fundo e borda.