rawilk/filament-quill

为 Filament 提供的 Quill 富文本编辑器。

v1.0.3 2024-03-10 23:24 UTC

README

Latest Version on Packagist Tests Total Downloads PHP from Packagist License

social image

filament-quill 为 filament 管理面板和表单提供 Quill 富文本编辑器集成。

安装

您可以通过 composer 安装此包

composer require rawilk/filament-quill

您可以使用以下命令发布配置文件

php artisan vendor:publish --tag="filament-quill-config"

您可以在以下链接查看默认配置: https://github.com/rawilk/filament-quill/blob/main/config/filament-quill.php

如果需要,您可以使用以下命令发布视图和翻译

php artisan vendor:publish --tag="filament-quill-views"
php artisan vendor:publish --tag="filament-quill-translatinos"

有关渲染编辑器内容的设置信息,请参阅 渲染内容 部分。

用法

编辑器已配置为类似 Filament 提供的富文本编辑器组件的行为和 API。Filament 的编辑器和本包的编辑器之间的一大区别是 Filament 使用 Trix 作为编辑器,而本包使用 Quill。

以下是一个如何在 filament 表单中使用编辑器的快速示例

use Rawilk\FilamentQuill\Filament\Forms\Components\QuillEditor;

QuillEditor::make('content'),

这将提供在您的表单中看起来像这样的编辑器

basic example

工具栏按钮

您可以使用 toolbarButtons() 方法设置编辑器的工具栏按钮。此处显示的选项是默认值。请参考 ToolbarButton 枚举以获取可用工具栏按钮的完整列表。

use Rawilk\FilamentQuill\Filament\Forms\Components\QuillEditor;
use Rawilk\FilamentQuill\Enums\ToolbarButton;

QuillEditor::make('content')
    ->toolbarButtons([
        ToolbarButton::Font,
        ToolbarButton::Size,
        ToolbarButton::Bold,
        ToolbarButton::Italic,
        ToolbarButton::Underline,
        ToolbarButton::Strike,
        ToolbarButton::BlockQuote,
        ToolbarButton::OrderedList,
        ToolbarButton::UnorderedList,
        ToolbarButton::Indent,
        ToolbarButton::Link,
        ToolbarButton::Image,
        ToolbarButton::Scripts,
        ToolbarButton::TextAlign,
        ToolbarButton::TextColor,
        ToolbarButton::BackgroundColor,
        ToolbarButton::Undo,
        ToolbarButton::Redo,
        ToolbarButton::ClearFormat,
    ])

您也可以使用 disableToolbarButtons() 方法禁用特定按钮

use Rawilk\FilamentQuill\Filament\Forms\Components\QuillEditor;
use Rawilk\FilamentQuill\Enums\ToolbarButton;

QuillEditor::make('content')
    ->disableToolbarButtons([
        ToolbarButton::BlockQuote,
        ToolbarButton::Font,
    ])

要完全禁用所有工具栏按钮,请将空数组传递给 toolbarButtons([]),或使用 disableAllToolbarButtons() 方法。

您还可以使用 enableToolbarButtons() 方法启用特定工具栏按钮

use Rawilk\FilamentQuill\Filament\Forms\Components\QuillEditor;
use Rawilk\FilamentQuill\Enums\ToolbarButton;

QuillEditor::make('content')
    ->enableToolbarButtons([
        ToolbarButton::CodeBlock,
    ])

占位符

我对富文本编辑器的一个常见要求是能够提供一组占位符变量列表,最终用户可以选择并将其插入到编辑器中。我最常见的用例是电子邮件模板。我在这个包中简化了这一过程。您只需要向组件提供一组占位符即可。

use Rawilk\FilamentQuill\Filament\Forms\Components\QuillEditor;

QuillEditor::make('content')
    ->placeholders([
        'USER_NAME',
        'USER_EMAIL',
        'CURRENT_DATE',
    ])

placeholders example

如您所见,我们负责添加工具栏按钮并注册一个 处理程序,以将占位符变量插入到编辑器中。在插入变量之前,编辑器会使用 [] 字符包围变量,但这些字符可以被 自定义

注意:在内容中解析和替换变量超出了此表单组件的范围。您需要自行处理这部分。

包围字符

默认情况下,我们在将变量插入编辑器之前,会用 [] 字符包围它,因此 USER_NAME 变量在插入时会变成 [USER_NAME]

要更改这些字符,您可以使用 surroundPlaceholdersWith() 方法

use Rawilk\FilamentQuill\Filament\Forms\Components\QuillEditor;

QuillEditor::make('content')
    ->placeholders([
        'USER_NAME',
        'USER_EMAIL',
        'CURRENT_DATE',
    ])
    ->surroundPlaceholdersWith(start: '{{ ', end: ' }}')

现在,当插入变量时,它将看起来像 {{ USER_NAME }}

占位符按钮标签

要更改占位符按钮上的文本,您可以修改 filament-quill::quill.placeholders.label 翻译,或者您可以通过 placeholderButtonLabel() 方法传入一个标签。

处理程序

如果您想覆盖现有工具栏按钮的处理程序,您可以使用 handlers() 方法定义自己的自定义 JavaScript 处理程序。以下是一个如何为 bold 工具栏按钮使用自己的处理程序的示例

use Rawilk\FilamentQuill\Filament\Forms\Components\QuillEditor;

QuillEditor::make('content')
    ->handlers([
        'bold' => <<<'JS'
        function (value) {
            if (value) {
                // this.quill.format(...);
            }
        }
        JS,
    ])

注意:在您的回调函数中,只要您不使用箭头函数,就可以通过 this.quill 访问 quill 编辑器实例。

自定义工具栏按钮

要添加您自己的工具栏按钮,您可以使用 addToolbarButton() 方法。您需要提供名称、标签和按钮的 JavaScript 处理程序。如果您需要下拉菜单,还需要提供选项数组。

use Rawilk\FilamentQuill\Filament\Forms\Components\QuillEditor;

QuillEditor::make('content')
    ->addToolbarButton(
        name: 'custom',
        label: 'Custom button',
        handler: <<<'JS'
        function (value) {
            console.log(value);
            // this.quill.insertText(0, value);
        },
        JS,
        // options: ['option 1', 'option 2'],
        // showSelectedOption: true,
    )

最后一个参数 showSelectedOption 仅适用于下拉按钮。当设置为 true 时,当用户点击选项时,它将显示所选选项的文本作为下拉标签,就像字体家族或字体大小工具栏按钮一样。

上传图片

ToolbarButton::Image 按钮启用时,用户将能够将图片插入到编辑器中。类似于 Filament 的富文本编辑器,我们将上传图片到服务器,并使用服务器上该图片的 URL 而不是将其作为 base64 编码的图片存储在内容中。您可以使用这些方法自定义图片在服务器上的存储方式和位置

use Rawilk\FilamentQuill\Filament\Forms\Components\QuillEditor;

QuillEditor::make('content')
    ->fileAttachmentsDisk('s3')
    ->fileAttachmentsDirectory('attachments')
    ->fileAttachmentsVisibility('private')

注意:我们不处理上传图片的跟踪和管理。例如,如果图片从内容中删除,我们不会从服务器上删除它,因此图片有很高的概率成为孤儿。当上传图片时,我们将触发 quill-image-uploaded Alpine 事件,当我们的 JavaScript 检测到图片已从内容中删除时,将触发 quill-images-deleted Alpine 事件。这两个事件都将接收相关图片的完全限定 URL 以及事件派发的字段名称。您可以通过监听这些事件来跟踪图片的绝对 URL。

use Rawilk\FilamentQuill\Filament\Forms\Components\QuillEditor;

QuillEditor::make('content')
    ->extraAlpineAttributes([
        '@quill-image-uploaded' => <<<'JS'
        ({ detail: { url, statePath } }) => {
            // handle the upload here.
            // console.log(url);
        }
        JS,
        '@quill-images-deleted' => <<<'JS'
        ({ detail: { urls, statePath } }) => {
            // handle the event here.
        }
        JS,
    ])

您还可以为编辑器上的 saveUploadedFileAttachmentsUsing() 方法提供一个回调,以帮助您跟踪文件,但这可能需要您更多的工作。

注意:您可能希望在用户触发保存和/或重置编辑器的 历史 状态之前,延迟删除服务器上的图片以响应 quill-images-deleted 事件。

渲染内容

为了匹配您在编辑器中看到的外观,您应该将用户生成的内容包裹在一个具有 quill-content prose max-w-none 类的容器中。您还需要确保已加载来自本包的内容区域样式。我们已将那些样式提取到一个单独的样式表中,称为 content.css。根据您如何渲染内容,您可能会发现将 content.css 样式捆绑到您的主题样式表中更容易。如果您尚未设置自定义主题且正在使用面板,应首先按照 Filament 文档 进行操作。

以下内容适用于面板和独立应用。

  1. 在您的样式表中导入内容样式
@import "<path-to-vendor>/rawilk/filament-quill/resources/css/content.css";

/*
 * Alternatively, you may import the entire stylesheet, however that's not recommended
 * since Quill's editor styles are quite expensive, and we load the stylesheet necessary
 * for the editor automatically for you.
 */
/* @import '<path-to-vendor>/rawilk/filament-quill/resources/css/app.css'; */
  1. 将包的视图添加到您的 tailwind.config.js 文件中。
content: [
    // ...
    '<path-to-vendor>/rawilk/filament-quill/resources/**/*.blade.php',
],

// In some cases, it is necessary to safelist the root element selector so tailwind
// doesn't purge everything.
safelist: [
    'quill-content',
],
  1. tawilwindcss/nesting 插件添加到您的 postcss.config.js 文件中。
module.exports = {
    plugins: {
        "tailwindcss/nesting": {},
        tailwindcss: {},
        autoprefixer: {},
    },
};
  1. 重新构建您的自定义主题。
npm run build
  1. 渲染内容
@use(Illuminate\Support\HtmlString)

<div
    class="quill-content prose max-w-none"
    @style([
        // Adjust or omit as necessary depending on your default
        // font size for editor content.
        '--ql-default-size: 14px',
    ])
>
    {{ new HtmlString($yourContent) }}
</div>

如果您的支持内容渲染的暗黑模式,您还可以将 dark:prose-invert 添加到容器中。

通常,运行内容通过 html 清理器也是一个好主意,但这超出了这些文档的范围。

自定义字体

如果您启用了 ToolbarButton::Font 按钮,我们将渲染一个下拉菜单,允许用户使用 Sans SerifSerifMonospaced 字体家族格式化内容。但是,您需要手动拉取并注册这些字体家族。在一个面板中,您可以利用 panels::head.start 渲染钩子 来完成此操作。

在下面的代码中,我们将拉取 Fira CodePT Serif 的等宽和衬线字体来使用,但过程与自定义字体类似。

<link
    href="https://fonts.bunny.net/css?family=fira-code:300,400,500,600,700|pt-serif:400,400i,700,700i&display=swap"
    rel="stylesheet"
/>

<style>
    :root {
        --font-serif-family: "PT Serif";
        --font-mono-family: "Fira Code";
    }
</style>

注册字体家族

在包的样式表中,我们配置等宽和衬线字体家族在编辑区域查找 --font-serif-family--font-mono-family CSS 变量,然而当您独立渲染自己的内容时,您需要在主题的 tailwind.config.js 文件中配置您的字体。

import defaultTheme from "tailwindcss/defaultTheme";

export default {
    // ...
    theme: {
        extend: {
            fontFamily: {
                serif: [
                    "var(--font-serif-family)",
                    ...defaultTheme.fontFamily.serif,
                ],
                mono: [
                    "var(--font-mono-family)",
                    ...defaultTheme.fontFamily.mono,
                ],
            },
        },
    },
};

使用自定义字体家族

如果您想使用自定义字体家族,如“Times New Roman”等,您可以在组件上使用 useFonts() 方法。

请首先遵循内容渲染部分,以确保您已经为这一步骤做好了所有设置。

use Rawilk\FilamentQuill\Filament\Forms\Components\QuillEditor;

QuillEditor::make('content')
    ->useFonts([
        'Times New Roman',
    ])

根据注册字体家族部分,您需要在您的 Tailwind 配置中注册该字体。我们将将每个字体家族值映射到一个短名,因此上面的“Times New Roman”字体将被映射到“times-new-roman”。

fontFamily: {
    times: ['Times New Roman'],
}

在一个自定义样式表中,您需要针对使用此字体格式化的内容区域。

.quill-content {
    &,
    .ql-editor {
        .ql-times-new-roman,
        .ql-editor .ql-times-new-roman {
            @apply font-times;
        }
    }
}

请确保将 .ql-times-new-romanfont-times 替换为您的实际字体名称。

自定义字体大小

ToolbarButton::Size 按钮启用时,我们将显示用户可以使用来格式化内容的字体大小下拉菜单。与字体家族一样,您可以自由定义自己的大小。您可以将字体大小数组传递给 fontSizes 方法。

use Rawilk\FilamentQuill\Filament\Forms\Components\QuillEditor;

QuillEditor::make('content')
    ->fontSizes([
        '10px',
        '12px',
        '14px',
        '20px',
    ])

当您提供实际的 CSS 大小单位时,Quill 将将文本大小内联到内容中,因此不需要额外的样式。但是,如果您提供非标准大小,如“Small”或“Large”,您需要在您的 CSS 中针对这些选择器。选择器遵循以下方案:ql-size-{size}

.ql-size-small,
.ql-editor .ql-size-small {
    font-size: 0.75rem;
}

自定义颜色

当您启用了 ToolbarButton::TextColorToolbarButton::BackgroundColor 按钮,您可以使用 CSS 十六进制颜色代码指定自己的调色板。

use Rawilk\FilamentQuill\Filament\Forms\Components\QuillEditor;

$colors = [
    '#fff',
    '#ff0000',
    '#333',
    // ...
];

QuillEditor::make('content')
    ->textColors($colors)
    ->backgroundColors($colors)

历史记录

默认情况下,编辑器包含用于撤销/重做历史操作的工具栏按钮。当处理图片或其他某些用例时,您可能希望重置编辑器的历史状态,以便用户不能“撤销”到一个已从服务器上删除的破损图片。这可以通过在动作中调用组件上的 clearHistory 方法轻松完成。

以下是在编辑资源页面表单上使用 afterSave 钩子重置历史状态的示例。

use Filament\Forms\Components\Component;

protected function afterSave(): void
{
    $component = $this->form->getComponent('data.content');

    $component->clearHistory();
}

幕后,编辑器组件将派发 quill-history-clear 浏览器事件,我们的 JavaScript 将监听该事件。如果您无法获取组件实例,您可以手动派发该事件。您只需要知道组件的状态路径(通常是 data.your_field_name)。

$this->dispatch('quill-history-clear', id: 'data.content');

其他回调

onInit

使用 onInit 回调,您可以在 quill 编辑器实例上注册额外的处理程序或回调,等等。这是一个注册您自己的编辑器实例 事件 处理程序的好地方。您需要做的就是向 onInit() 方法提供一个 JavaScript 回调

use Rawilk\FilamentQuill\Filament\Forms\Components\QuillEditor;

QuillEditor::make('content')
    ->onInit(<<<'JS'
    function (quill, alpineInstance) {
        // quill.on('selection-change', function (range, oldRange, source) {
            // do stuff
        // )};
    }
    JS)

我们的 JavaScript 将传递一个 quill 编辑器实例以及 Alpine 组件实例给您的回调

文本更改

如果您只想连接到 quill 分发的 text-changed 事件,可以使用 onTextChange 方法

use Rawilk\FilamentQuill\Filament\Forms\Components\QuillEditor;

QuillEditor::make('content')
    ->onTextChange(<<<'JS'
    function (delta, oldDelta, source, alpineInstance) {
        // handle it
    },
    JS)

注意这里我们使用的是常规函数,而不是箭头函数。这样您就可以使用 this.quill 来引用编辑器实例。

除了 Quill 提供的常规参数之外,我们还提供了一个 Alpine 组件实例给您的回调,如果需要的话。如果您从回调中返回 false,则可以阻止我们的 JavaScript 处理此事件。

脚本

设置

为了方便,您可以运行设置 bin 脚本,以便于本地开发时的简单安装。

./bin/setup.sh

格式化

尽管格式化是通过工作流程自动完成的,但在提交之前,您可以使用 composer 脚本在本地格式化 php 代码

composer format

测试

composer test

变更日志

有关最近更改的更多信息,请参阅 变更日志

贡献

有关详细信息,请参阅 贡献指南

安全性

请审查 我的安全策略 了解如何报告安全漏洞。

致谢

替代方案

许可证

MIT 许可证 (MIT)。有关更多信息,请参阅 许可证文件