Regras do Blade MAD
Compilador MAD (BladeCompiler nativo do Illuminate + pré-processo <mad-*>): named slots, @props, escape de aspas em atributos.
O MAD compila views em duas camadas: primeiro o MadGridCompiler reescreve
tags <mad-xxx> em texto cru (regex sobre o arquivo, antes de
qualquer parser), depois o MadBladeCompiler compila o resultado como Blade
nativo. Essa combinação tem limitações específicas que não existem no Blade puro do
Laravel — esta página documenta as que mais geram bug silencioso.
Traduções i18n com __()
Três contextos, três formas diferentes de injetar texto traduzido — misturar gera bug.
| Contexto | Forma |
|---|---|
Atributo de componente (label="...", title="...") | Bind PHP: :label="__('...')" |
Conteúdo/slot de componente (entre <mad-btn>...</mad-btn>) | Raw echo: {!! __('...') !!} |
| HTML puro, fora de componente | Echo normal: {{ __('...') }} |
<!-- Atributo de componente: bind PHP -->
<mad-input-field :label="__('doc.recipe_name')" />
<mad-form-section :title="__('doc.ingredients')" icon="list">
<!-- Conteúdo/slot de componente: raw echo -->
<mad-btn variant="primary">{!! __('mad.save') !!}</mad-btn>
<!-- HTML puro, fora de componente: echo normal -->
<option value="">{{ __('doc.select_recipe') }}</option>
<h1>{{ __('doc.recipe') }}</h1>
{{ __() }} em atributo de componente
{{ }} aplica htmlentities(), que escapa aspas simples.
Num atributo de componente isso produz algo como
label="Traduç'ão" em vez do texto correto — o componente
recebe lixo, não o valor traduzido.
<!-- ERRADO — @{{ }} escapa aspas, quebra o valor -->
<mad-input-field label="{{ __('doc.recipe_name') }}" />
<mad-form-section title="{{ __('doc.details') }}" />
<!-- CERTO — :prop com bind PHP, sem escape de entidades -->
<mad-input-field :label="__('doc.recipe_name')" />
<mad-form-section :title="__('doc.details')" />
<!-- CERTO para valores fixos sem aspas no meio -->
<mad-input-field label="Nome" />
<mad-form-section title="Dados" />
Tags compiladas pelo MadGridCompiler
Tags como <mad-grid>, <mad-col>,
<mad-act>, <mad-detail-form>,
<mad-field-list-column> são processadas por regex antes
do MadBladeCompiler — não são componentes Blade nativos. Expressões PHP nesses atributos
sempre usam o prefixo ::
<mad-col field="nome" :label="__('doc.recipe_name')" sort />
<mad-detail-form name="itens" :form-title="__('doc.ingredient')" mode="drawer" />
Bug MadBladeCompiler — @if como primeiro filho de outro componente
O MadBladeCompiler falha ao compilar um <x-component> (incluindo os
resultantes da reescrita mad-xxx → x-xxx) quando ele é o
primeiro filho de outro componente e é precedido por @if.
Os atributos :prop="expr" passam direto para o HTML sem ser avaliados, e o
Alpine tenta interpretar a string crua como JS.
<!-- ERRADO — <mad-form-section> não compila, :title vira atributo HTML literal -->
<mad-form submit="onSave">
@if($showFile)
<mad-form-section :title="__('ged.upload')" icon="upload">
<mad-file-field :label="__('ged.filename')" />
</mad-form-section>
@endif
</mad-form>
<!-- CERTO — mover o @if para FORA do <mad-form>, ou o form inteiro para dentro do @if -->
@if($showFile)
<mad-form submit="onSave">
<mad-form-section :title="__('ged.upload')" icon="upload">
<mad-file-field :label="__('ged.filename')" />
</mad-form-section>
</mad-form>
@endif
Regra geral: nunca use @if como primeiro filho direto
dentro de <mad-form> ou de qualquer outro componente Blade.
Alternativas:
- Mover o
@ifpara fora do componente pai. - Inserir um
<div>wrapper entre o componente pai e o@if(menos elegante, mas funciona). - Separar em blocos condicionais independentes.
<!-- ALTERNATIVA: wrapper div -->
<mad-form submit="onSave">
<div>
@if($showSection)
<mad-form-section :title="$titulo">...</mad-form-section>
@endif
</div>
</mad-form>
Regras gerais do MadBladeCompiler (limitações vs. Blade nativo do Laravel)
-
@propsfunciona — o MadBladeCompiler registra a diretiva (declare defaults no topo do componente:@props(['size' => 'md', 'required' => false])). O que fica desligado é só o ComponentTagCompiler de componentes-classe do Laravel — os componentes anônimos<x-...>/<mad-...>recebem props normalmente. -
Named slots
<x-slot name="...">são suportados — o compilador MAD extrai a tag e converte em slot clássico (o antigo bug "Template not found: components.slot" foi corrigido). Para valores simples, uma prop costuma ser mais direta que um slot:<!-- OK — named slot via tag --> <mad-modal name="meu-modal" size="md"> <x-slot name="footer"><button class="mad-btn">OK</button></x-slot> Conteúdo... </mad-modal> <!-- Também OK, mais direto p/ valor simples — título como prop --> <mad-modal name="meu-modal" :title="'Meu Título'" size="md"> Conteúdo... </mad-modal> {!! $slot !!}dentro de componentes — nunca{{ $slot }}(escaparia o HTML do conteúdo).- Strings multi-palavra em atributos — pré-definir num
@phpe passar com:prop="$var", em vez de tentar montar inline. - Cache de template — limpe
tmp/blade-cache/*.bladec(ou rodephp artisan view:clear) ao mudar um template e a alteração não aparecer. -
attrscom aspas duplas internas — pré-compute no@php:$at = 'data-x="val"';e passe com:attrs="$at"(ver também Aspas em atributos). ??em props — o MadBladeCompiler não faz parse de:prop="$arr['key'] ?? ''"direto no atributo. Pré-compute no@php.- Sem
@component/@endcomponent— essa diretiva não é registrada. Use<x-component>(ou<mad-xxx>) ou PHP direto. -
mad:modelobrigatório em campos de formulário — todo componente de campo (mad-input-field,mad-select-field, etc.) precisa garantir quemad:modelchegue no<input>/<select>renderizado mesmo quando$attrsjá contém outros atributos (ex:mad:change). Semmad:model, o MadWire não coleta o valor do campo no POST:<!-- ERRADO — mad:model só é adicionado quando $attrs está vazio --> if ($name && $attrs === '') { $attrs = 'mad:model="' . $name . '"'; } <!-- CERTO — verifica se mad:model já existe antes de adicionar --> if ($name && strpos($attrs, 'mad:model') === false && strpos($attrs, 'data-mad-model') === false) { $attrs = 'mad:model="' . $name . '" ' . $attrs; } -
Sem
<form>nativo — nunca escreva<form data-mad-submit="...">à mão. Sempre<mad-form submit="metodo">(ele gera o<form>real por baixo, incluindo o token de schema):<!-- ERRADO --> <form data-mad-submit="onSave">...</form> <!-- CERTO --> <mad-form submit="onSave">...</mad-form>
Sync especial de componentes em mad-detail-form
O madDetailForm (Alpine) sincroniza o DOM com o estado interno em alguns
componentes que mantêm seu próprio Alpine state — esses precisam de tratamento
especial além de value/x-model simples:
| Componente | Sync necessário |
|---|---|
mad-numeric-field | Setar Alpine.$data().rawValue + atualizar o display visível |
mad-dbseek-field | Setar Alpine.$data().selectedId + displayText |
| MAD Select (select, dbcombo, multi-search) | Usar el._madSelect.setValue(val, true) — widget JS próprio do framework, não é TomSelect nem outra lib de terceiros |
mad-html-editor-field | Quill clipboard.dangerouslyPasteHTML() |
mad-checklist-field | Setar array checkedIds + checkboxes individuais |
Componentes que não precisam de sync especial (o value
direto já funciona): input-field, textarea-field,
number-field, date-field, time-field,
switch-field, checkbox-field, radio-field,
range-field, color-field.