Skip to content
This repository was archived by the owner on Mar 18, 2025. It is now read-only.

Commit 327f294

Browse files
authored
[Feature] Quill Rich Text Editor (#53)
* Add quill editor component * Update js deps
1 parent 478f276 commit 327f294

File tree

9 files changed

+713
-20
lines changed

9 files changed

+713
-20
lines changed

config/form-components.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@
8888
'tree-select' => Components\Inputs\TreeSelect::class,
8989
'tree-select-option' => Components\Inputs\TreeSelectOption::class,
9090

91+
// Rich Text
92+
'quill' => Components\RichText\Quill::class,
93+
9194
],
9295

9396
/*
@@ -171,6 +174,11 @@
171174
],
172175

173176
'popper' => 'https://unpkg.com/@popperjs/core@2',
177+
178+
'quill' => [
179+
'https://cdn.quilljs.com/1.3.6/quill.snow.css',
180+
'https://cdn.quilljs.com/1.3.6/quill.js',
181+
],
174182
],
175183

176184
/*

dist/form-components.js

Lines changed: 240 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/mix-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"/form-components.js": "/form-components.js?id=aa42a80457d5af2a5e64"
2+
"/form-components.js": "/form-components.js?id=8cd94f15e0bfe6dd5376"
33
}

package-lock.json

Lines changed: 18 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

resources/js/components/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import customSelect from './custom-select';
22
import customSelectOption from './custom-select-option';
3+
import quill from './quill';
34
import treeSelect from './tree-select';
45
import treeSelectOption from './tree-select-option';
56

67
document.addEventListener('alpine:init', () => {
78
Alpine.data('customSelect', customSelect);
89
Alpine.data('customSelectOption', customSelectOption);
10+
Alpine.data('quill', quill);
911
Alpine.data('treeSelect', treeSelect);
1012
Alpine.data('treeSelectOption', treeSelectOption);
1113
});

resources/js/components/quill.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
export default options => ({
2+
autofocus: false,
3+
value: '',
4+
theme: 'snow',
5+
readOnly: false,
6+
placeholder: null,
7+
toolbar: {},
8+
toolbarHandlers: {},
9+
...options,
10+
_quill: null,
11+
12+
init() {
13+
if (typeof Quill !== 'function') {
14+
throw new TypeError(`Quill Editor requires Quill (https://quilljs.com)`);
15+
}
16+
17+
this._quill = new Quill(this.$refs.quill, this._quillOptions());
18+
19+
this._quill.root.innerHTML = this.value;
20+
21+
this._quill.on('text-change', () => {
22+
this.value = this._quill.root.innerHTML;
23+
24+
this.$dispatch('quill-input', this.value);
25+
});
26+
27+
if (this.autofocus) {
28+
this.$nextTick(() => this._quill.focus());
29+
}
30+
},
31+
32+
_quillOptions() {
33+
const toolbarHandlers = this.toolbarHandlers;
34+
if (toolbarHandlers !== null) {
35+
Object.keys(toolbarHandlers).forEach(key => {
36+
toolbarHandlers[key] = new Function('value', toolbarHandlers[key]);
37+
});
38+
}
39+
40+
return {
41+
theme: this.theme,
42+
readOnly: this.readOnly,
43+
placeholder: this.placeholder,
44+
modules: {
45+
toolbar: {
46+
container: this.toolbar,
47+
handlers: toolbarHandlers || {},
48+
},
49+
},
50+
};
51+
}
52+
});
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<div x-data="quill({
2+
@if ($hasWireModel())
3+
value: @entangle($attributes->wire('model')),
4+
@elseif ($hasXModel())
5+
value: {{ $attributes->first('x-model') }},
6+
@else
7+
value: {{ \Illuminate\Support\Js::from($value) }},
8+
@endif
9+
...{{ $options() }}
10+
})"
11+
x-cloak
12+
id="{{ $id }}"
13+
@class([
14+
'quill-wrapper',
15+
'has-error' => $hasErrorsAndShow($name),
16+
])
17+
>
18+
<input type="hidden" name="{{ $name }}" x-bind:value="value">
19+
<div @if ($hasWireModel()) wire:ignore @endif>
20+
<div x-ref="quill"></div>
21+
</div>
22+
</div>

src/Components/RichText/Quill.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rawilk\FormComponents\Components\RichText;
6+
7+
use Illuminate\Support\Js;
8+
use Rawilk\FormComponents\Components\BladeComponent;
9+
use Rawilk\FormComponents\Concerns\HandlesValidationErrors;
10+
use Rawilk\FormComponents\Concerns\HasModels;
11+
use Rawilk\FormComponents\Dto\QuillOptions;
12+
13+
class Quill extends BladeComponent
14+
{
15+
use HandlesValidationErrors;
16+
use HasModels;
17+
18+
public function __construct(
19+
public null|string $name = null,
20+
public null|string $id = null,
21+
public null|string $value = null,
22+
bool $showErrors = true,
23+
public bool $autofocus = false,
24+
public bool $readonly = false,
25+
public null|string $placeholder = null,
26+
public null|QuillOptions $quillOptions = null,
27+
) {
28+
$this->id = $this->id ?? $this->name;
29+
$this->value = $this->name ? old($this->name, $this->value) : $this->value;
30+
$this->showErrors = $showErrors;
31+
32+
if (is_null($this->quillOptions)) {
33+
$this->quillOptions = QuillOptions::defaults();
34+
}
35+
}
36+
37+
public function options(): Js
38+
{
39+
return Js::from([
40+
'autofocus' => $this->autofocus,
41+
'theme' => $this->quillOptions->theme,
42+
'readOnly' => $this->readonly,
43+
'placeholder' => $this->placeholder,
44+
'toolbar' => $this->quillOptions->getToolbar(),
45+
'toolbarHandlers' => count($this->quillOptions->toolbarHandlers) ? $this->quillOptions->toolbarHandlers : null,
46+
]);
47+
}
48+
}

0 commit comments

Comments
 (0)