mad-html-editor-field
Editor rico (Quill snow) para HTML formatado.
Editor de texto rico baseado em TinyMCE 5 (self-hosted, sem CDN/API key).
Gera conteudo HTML e armazena num <textarea> oculto sincronizado via
mad:model — integra direto com MadForm sem codigo extra.
Props
| Prop | Tipo | Default | Descricao |
|---|---|---|---|
| name | string | '' | Nome do campo (obrigatorio) |
| label | string | '' | Label do campo |
| value | string | '' | HTML inicial (sobrescrito pelo MadRenderContext quando o form estiver populado) |
| height | int/string | 300 | Altura da area de edicao em px |
| placeholder | string | '' | Texto placeholder dentro do editor |
| hint | string | '' | Texto de ajuda |
| error | string | '' | Mensagem de erro |
| required | bool | false | Campo obrigatorio |
| disabled | bool | false | Editor somente leitura (readonly no TinyMCE) |
| attrs | string | '' | Atributos HTML extras no <textarea> interno |
| width / max-width | string | '' | Largura do wrapper (CSS) |
| locale | string | '' (= pt_BR) |
Idioma da UI: pt_BR, pt_PT, en, es. en e nativo; demais carregam /langs/{locale}.js |
| toolbar | string | '' (preset completo) | Override total da string de toolbar do TinyMCE |
| plugins | string | '' (preset completo) | Override total da lista de plugins do TinyMCE |
| menubar | string|bool | '' (= preset ativo) | false desliga o menubar; string custom troca os menus |
| statusbar | bool | true | Mostra a barra inferior (contador de palavras etc) |
| skin | string | '' (= oxide) |
Skin do TinyMCE — aceita oxide-dark |
| content_css | string | '' (= default) |
CSS do iframe de conteudo — aceita dark |
O id do <textarea> e gerado automaticamente (mad_{name}_{rand}), nao e
uma prop configuravel.
Presets default (usados quando toolbar/plugins/menubar ficam vazios):
- plugins:
advlist autolink lists link image charmap preview anchor searchreplace visualblocks visualchars code fullscreen insertdatetime media table paste help wordcount codesample hr nonbreaking pagebreak quickbars directionality - toolbar:
undo redo | blocks fontsize | bold italic underline strikethrough | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image media table codesample | removeformat searchreplace fullscreen code preview | help - menubar:
file edit view insert format tools table help
Uso basico
<mad-html-editor-field name="descricao" label="Descricao" />
Com altura customizada
<mad-html-editor-field name="mensagem" label="Mensagem" height="200" required />
Com placeholder
<mad-html-editor-field name="reply_message"
placeholder="Escreva sua resposta..." height="100" />
Dentro de formulario
<mad-form submit="onSave">
<mad-form-section title="Conteudo" icon="file-text">
<mad-input-field name="titulo" label="Titulo" required />
<mad-html-editor-field name="conteudo" label="Conteudo" height="300" required />
</mad-form-section>
<mad-form-actions>
<mad-btn type="submit" variant="primary" icon="save">Salvar</mad-btn>
</mad-form-actions>
</mad-form>
use Illuminate\Support\Facades\DB;
public function onSave(): MadResponse
{
try {
$this->form->validate(Artigo::rules($this->registroId));
DB::connection('business')->transaction(function () {
$artigo = Artigo::findOrNew($this->registroId);
$this->form->save($artigo); // $artigo->conteudo recebe o HTML do TinyMCE
$this->registroId = (int) $artigo->id;
});
return (new MadResponse())
->toast('Salvo!', 'success')
->closeDrawer();
} catch (MadValidationException $e) {
return $e->asModal();
} catch (\Throwable $e) {
return MadMessage::error('Erro', $e->getMessage());
}
}
Carregar valor existente (onEdit)
O editor le do MadRenderContext automaticamente — basta form->fill($record).
public function onEdit(int $id): void
{
$artigo = Artigo::findOrFail($id);
$this->registroId = (int) $artigo->id;
$this->form->fill($artigo); // o HTML de $artigo->conteudo aparece no editor
}
Sync em detail-form
O _syncFormInputs() do madDetailForm precisa de tratamento especial para o html-editor: ao re-popular linhas do detail (ex: ao reabrir um drawer/modal de edicao de item), o conteudo e injetado via tinymce.get(textarea.id).setContent(html) (resolvido pelo id do <textarea> interno). Isso ja e feito automaticamente pelo framework — nao precisa codigo extra. Basta declarar o campo no detail normalmente:
<mad-detail-form name="paragrafos" model="ArtigoParagrafo" foreign-key="artigo_id" mode="drawer">
<mad-input-field name="titulo" label="Titulo" required />
<mad-html-editor-field name="texto" label="Texto" height="250" />
</mad-detail-form>
Validacao
O valor do textarea oculto (HTML do TinyMCE) e enviado normalmente no POST. Validacao via Modelo::rules() funciona igual aos demais campos:
public static function rules($id = null): array
{
return [
'titulo' => 'required|max:200',
'conteudo' => 'required',
];
}
Observacao: o TinyMCE pode enviar markup "vazio" (ex: <p> </p>) quando
o usuario apaga todo o conteudo, dependendo do navegador. Se precisar tratar
isso como vazio, normalize na validacao customizada ou no onSave.
NUNCA fazer
{{-- ERRADO: usar textarea para campos com HTML rico --}}
<mad-textarea-field name="descricao" label="Descricao" />
{{-- CERTO --}}
<mad-html-editor-field name="descricao" label="Descricao" />
{{-- ERRADO: instanciar TinyMCE manualmente --}}
<textarea id="meu-editor"></textarea>
<script>
tinymce.init({ target: document.getElementById('meu-editor') });
document.querySelector('form').addEventListener('submit', function() {
document.getElementById('meu-input').value = tinymce.get('meu-editor').getContent();
});
</script>
{{-- CERTO --}}
<mad-html-editor-field name="conteudo" label="Conteudo" />
{{-- ERRADO: manipular a instancia do TinyMCE via JS externo para setar valor --}}
<script>
tinymce.get('algum-id').setContent('<p>texto</p>');
</script>
{{-- CERTO: setar via PHP (auto-bind) --}}
$this->form->set('conteudo', '<p>texto</p>');
{{-- ERRADO: input type=hidden recebendo HTML serializado a mao --}}
<input type="hidden" name="conteudo" value="{{ $html }}">
{{-- CERTO --}}
<mad-html-editor-field name="conteudo" :value="$html" />