{"id":15619478,"url":"https://github.com/awcodes/filament-tiptap-editor","last_synced_at":"2025-05-14T10:14:59.109Z","repository":{"id":37075437,"uuid":"482085436","full_name":"awcodes/filament-tiptap-editor","owner":"awcodes","description":"A Rich Text Editor plugin for Filament Forms.","archived":false,"fork":false,"pushed_at":"2025-05-12T00:47:05.000Z","size":17049,"stargazers_count":353,"open_issues_count":8,"forks_count":106,"subscribers_count":7,"default_branch":"3.x","last_synced_at":"2025-05-12T01:32:07.818Z","etag":null,"topics":["filament","filament-plugin"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/awcodes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"awcodes"}},"created_at":"2022-04-15T21:10:52.000Z","updated_at":"2025-05-12T00:47:02.000Z","dependencies_parsed_at":"2023-12-14T17:44:31.498Z","dependency_job_id":"5f935745-76cf-4771-b449-abe038f2e028","html_url":"https://github.com/awcodes/filament-tiptap-editor","commit_stats":{"total_commits":517,"total_committers":47,"mean_commits":11.0,"dds":0.5454545454545454,"last_synced_commit":"372dad4c718566b66a57d203974e24d9ac3a6445"},"previous_names":[],"tags_count":193,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/awcodes%2Ffilament-tiptap-editor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/awcodes%2Ffilament-tiptap-editor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/awcodes%2Ffilament-tiptap-editor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/awcodes%2Ffilament-tiptap-editor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/awcodes","download_url":"https://codeload.github.com/awcodes/filament-tiptap-editor/tar.gz/refs/heads/3.x","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254120179,"owners_count":22017953,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["filament","filament-plugin"],"created_at":"2024-10-03T08:20:46.971Z","updated_at":"2025-05-14T10:14:59.100Z","avatar_url":"https://github.com/awcodes.png","language":"PHP","funding_links":["https://github.com/sponsors/awcodes"],"categories":["Integrations","PHP"],"sub_categories":[],"readme":"# Filament Tiptap Editor\n\nA Tiptap integration for Filament Admin/Forms.\n\n![tiptap-editor-og](https://res.cloudinary.com/aw-codes/image/upload/w_1200,f_auto,q_auto/plugins/tiptap-editor/awcodes-tiptap-editor.jpg)\n\n## Installation\n\nInstall the package via composer\n\n```bash\ncomposer require awcodes/filament-tiptap-editor:\"^3.0\"\n```\n\nIn an effort to align with Filament's theming methodology you will need to use a custom theme to use this plugin.\n\n\u003e **Note**\n\u003e If you have not set up a custom theme and are using a Panel follow the instructions in the [Filament Docs](https://filamentphp.com/docs/3.x/panels/themes#creating-a-custom-theme) first. The following applies to both the Panels Package and the standalone Forms package.\n\n1. Import the plugin's stylesheet and tippy.js stylesheet (if not already included) into your theme's css file.\n\n```css\n@import '\u003cpath-to-vendor\u003e/awcodes/filament-tiptap-editor/resources/css/plugin.css';\n```\n\n2. Add the plugin's views to your `tailwind.config.js` file.\n\n```js\ncontent: [\n    ...\n    '\u003cpath-to-vendor\u003e/awcodes/filament-tiptap-editor/resources/**/*.blade.php',\n]\n```\n\n3. Add the `tailwindcss/nesting` plugin to your `postcss.config.js` file.\n\n```js\nmodule.exports = {\n    plugins: {\n        'tailwindcss/nesting': {},\n        tailwindcss: {},\n        autoprefixer: {},\n    },\n}\n```\n\n4. Rebuild your custom theme.\n\n```sh\nnpm run build\n```\n\n## Upgrading from 2.x to 3.x\n\n1. Output is now set with an Enum, please update your files to use `TiptapOutput` in all place where you are setting the output, including the config file.\n2. `barebone` profile setting was renamed to `minimal`\n\n## Usage\n\nThe editor extends the default Field class so most other methods available on that class can be used when adding it to a form.\n\n```php\nuse FilamentTiptapEditor\\TiptapEditor;\nuse FilamentTiptapEditor\\Enums\\TiptapOutput;\n\nTiptapEditor::make('content')\n    -\u003eprofile('default|simple|minimal|none|custom')\n    -\u003etools([]) // individual tools to use in the editor, overwrites profile\n    -\u003edisk('string') // optional, defaults to config setting\n    -\u003edirectory('string or Closure returning a string') // optional, defaults to config setting\n    -\u003eacceptedFileTypes(['array of file types']) // optional, defaults to config setting\n    -\u003emaxSize('integer in KB') // optional, defaults to config setting\n    -\u003eoutput(TiptapOutput::Html) // optional, change the format for saved data, default is html\n    -\u003emaxContentWidth('5xl')\n    -\u003erequired();\n```\n\n### Rendering content in Blade files\n\nIf you are storing your content as JSON then you will likely need to parse the data to HTML for output in Blade files. To help with this there is a helper function `tiptap_converter` that will convert the data to one of the three supported Tiptap formats. \n\nStyling the output is entirely up to you.\n\n```blade\n{!! tiptap_converter()-\u003easHTML($post-\u003econtent) !!}\n{!! tiptap_converter()-\u003easJSON($post-\u003econtent) !!}\n{!! tiptap_converter()-\u003easText($post-\u003econtent) !!}\n```\n\n#### Table of Contents\n\nIf you are using the `heading` tool in your editor you can also generate a table of contents from the headings in the content. This is done by passing the content to the `asHTML()` method and setting the `toc` option to `true`. You can also pass a `maxDepth` option to limit the depth of headings to include in the table of contents.\n\n```blade\n\u003c!-- this will generate links for all headings up to h3 --\u003e\n{!! tiptap_converter()-\u003easHTML($post-\u003econtent, toc: true, maxDepth: 3) !!}\n\n\u003c!-- this will generate a table of contents with headings up to h3 --\u003e\n{!! tiptap_converter()-\u003easToc($post-\u003econtent, maxDepth: 3) !!}\n```\n\nAlternatively, you can use \u0026 extend the `table-of-contents` blade component to generate the table of contents.\n\n```blade\n\u003c!-- This will generate the TOC as a nested array, and use it as a parameter in the contents table --\u003e\n\u003cx-filament-tiptap-editor::table-of-contents :headings=\"tiptap_converter()-\u003easTOC($page-\u003ebody, array: true)\" /\u003e\n```\n\n## Config\n\nThe plugin will work without publishing the config, but should you need to change any of the default settings you can publish the config file with the following Artisan command:\n\n```bash\nphp artisan vendor:publish --tag=\"filament-tiptap-editor-config\"\n```\n\n### Profiles / Tools\n\nThe package comes with 3 profiles (or toolbars) out of the box. You can also use a pipe `|` to separate tools into groups. The default profile is the full set of tools.\n\n```php\n'profiles' =\u003e [\n    'default' =\u003e [\n        'heading', 'bullet-list', 'ordered-list', 'checked-list', 'blockquote', 'hr',\n        'bold', 'italic', 'strike', 'underline', 'superscript', 'subscript', 'lead', 'small', 'align-left', 'align-center', 'align-right',\n        'link', 'media', 'oembed', 'table', 'grid-builder', 'details',\n        'code', 'code-block', 'source',\n    ],\n    'simple' =\u003e [\n        'heading', 'hr', 'bullet-list', 'ordered-list', 'checked-list',\n        'bold', 'italic', 'lead', 'small',\n        'link', 'media',\n    ],\n    'minimal' =\u003e [\n        'bold', 'italic', 'link', 'bullet-list', 'ordered-list',\n    ],\n],\n```\n\nSee `filament-tiptap-editor.php` config file for modifying profiles to add / remove buttons from the editor or to add your own.\n\nTools can also be added on a per-instance basis by using the `-\u003etools()` modifier to overwrite the profile set for the instance. A full list of tools can be found in the `filament-tiptap-editor.php` config file under the default profile setting.\n\n### Media / Images\n\n```php\n[\n    'accepted_file_types' =\u003e ['image/jpeg', 'image/png', 'image/webp', 'image/svg+xml', 'application/pdf'],\n    'disk' =\u003e 'public',\n    'directory' =\u003e 'images',\n    'visibility' =\u003e 'public',\n    'preserve_file_names' =\u003e false,\n    'max_file_size' =\u003e 2042,\n    'image_crop_aspect_ratio' =\u003e null,\n    'image_resize_target_width' =\u003e null,\n    'image_resize_target_height' =\u003e null,\n]\n```\n\n### Output format\n\nTiptap has 3 different output formats.\nSee: https://tiptap.dev/guide/output\n\nIf you want to change the output format that is stored in the database you can change the default config or specify it in each instance.\n\n```php\nuse FilamentTiptapEditor\\Enums\\TiptapOutput;\n\nTiptapEditor::make('content')\n    -\u003eoutput(FilamentTiptapEditor\\TiptapOutput::Json);\n```\n\n\u003e **Note**\n\u003e If you want to store the editor content as array / json you have to set the database column as `longText` or `json` type. And cast it appropriately in your model class.\n\n```php\n// in your migration\n$table-\u003ejson('content');\n\n// in your model\nprotected $casts = [\n    'content' =\u003e 'json' // or 'array'\n];\n```\n\n### RTL Support\n\nIn order for things like text align to work properly with RTL languages you \ncan switch the `direction` key in the config to 'rtl'.\n\n```php\n// config/filament-tiptap-editor.php\n'direction' =\u003e 'rtl'\n```\n\n### Max Content Width\n\nTo adjust the max content width of the editor globally set `max_content_width` \nkey in the config to one of the tailwind max width sizes or `full` for full width. \nThis could also be set on a per-instance basis with the `-\u003emaxContentWidth()` method.\n\n```php\n'max_content_width' =\u003e 'full'\n```\n\n```php\nuse FilamentTiptapEditor\\TiptapEditor;\n\nTiptapEditor::make('content')\n    -\u003emaxContentWidth('3xl');\n```\n\n## Overrides\n\nThe Link, Media and Grid Builder modals are built using Filament Form Component Actions. This means it is easy enough to swap them out with your own implementations.\n\n### Link Modal\n\nYou may override the default Link modal with your own Action and assign to the `link_action` key in the config file. Make sure the default name for your action is `filament_tiptap_link`.\n\nSee `vendor/awcodes/filament-tiptap-editor/src/Actions/LinkAction.php` for implementation.\n\n### Media Modal\n\nYou may override the default Media modal with your own Action and assign to the `media_action` key in the config file. Make sure the default name for your action is `filament_tiptap_media`.\n\nThe Media Modal can make use of 3 attributes not exposed by default:\n\n- `srcset` is used for selecting a series of responsive images to display for different browser viewports. [Docs](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/srcset)\n- `sizes` goes alongside `srcset` to specify sizing rules for responsive images. [Docs](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/sizes)\n- `media` provides support for an arbitrary ID value to better integrate with Media stored within a Database.\n\nSee `vendor/awcodes/filament-tiptap-editor/src/Actions/MediaAction.php` for implementation.\n\n### Grid Builder Modal\n\nYou may override the default Grid Builder modal with your own Action and assign to the `grid_builder_action` key in the config file. Make sure the default name for your action is `filament_tiptap_grid`.\n\nSee `vendor/awcodes/filament-tiptap-editor/src/Actions/GridBuilderAction.php` for implementation.\n\n### OEmbed Modal\n\nYou may override the default OEmbed modal with your own Action and assign to the `oembed_action` key in the config file. Make sure the default name for your action is `filament_tiptap_oembed`.\n\nSee `vendor/awcodes/filament-tiptap-editor/src/Actions/OEmbedAction.php` for implementation.\n\n### Initial height of editor field\n\nYou can add extra input attributes to the field with the `extraInputAttributes()` method. This allows you to do things like set the initial height of the editor.\n\n```php\nTiptapEditor::make('content')\n    -\u003eextraInputAttributes(['style' =\u003e 'min-height: 12rem;']),\n```\n\n## Colors preset\n\nBy default, the ColorPicker shows a picker and a field to set hexadecimal color to selected text. Registering specific colors in config file, you can choose one of them directly in ColorPicker\nTo do, simply set your custom colors in config file ```preset_colors``` key\n\n    \n```php\n'preset_colors' =\u003e [\n    'primary' =\u003e '#f59e0b',\n    'secondary' =\u003e '#14b8a6',\n    'red' =\u003e '#ef4444',\n    //..\n]\n```\n\n\n## Bubble and Floating Menus\n\nBy default, the editor uses Bubble and Floating menus to help with creating content inline, so you don't have to use the toolbar. If you'd prefer to not use the menus you can disable them on a per-instance basis or globally in the config file.\n\n```php\nTiptapEditor::make('content')\n    -\u003edisableFloatingMenus()\n    -\u003edisableBubbleMenus();\n```\n    \n```php\n'disable_floating_menus' =\u003e true,\n'disable_bubble_menus' =\u003e true,\n```\n\nYou can also provide you own tools to for the floating menu, should you choose. Defaults can be overwritten via the config file.\n\n```php\nTiptapEditor::make('content')\n    -\u003efloatingMenuTools(['grid-builder', 'media', 'link'])\n```\n\n```php\n'floating_menu_tools' =\u003e ['media', 'grid-builder', 'details', 'table', 'oembed', 'code-block'],\n'bubble_menu_tools' =\u003e ['bold', 'italic', 'strike', 'underline', 'superscript', 'subscript', 'lead', 'small', 'link'],\n```\n\nBesides providing your own tools, you can also configure the placement of the tippy toolbar\n\n```php\nTiptapEditor::make('content')\n    -\u003etippyPlacement(TippyPlacement::Left)\n```\n\n## Grid layouts\n\nWhen using the `grid` tool, you can customize the available layouts in the dropdown by passing them to the `gridLayouts()` method:\n\n```php\nTiptapEditor::make('content')\n    -\u003egridLayouts([\n        'two-columns',\n        'three-columns',\n        'four-columns',\n        'five-columns',\n        'fixed-two-columns',\n        'fixed-three-columns',\n        'fixed-four-columns',\n        'fixed-five-columns',\n        'asymmetric-left-thirds',\n        'asymmetric-right-thirds',\n        'asymmetric-left-fourths',\n        'asymmetric-right-fourths',\n    ]);\n```\n\n## Custom Blocks\n\n\u003e **Note**\n\u003e To use custom blocks you must store your content as JSON.\n\n```php\nuse FilamentTiptapEditor\\Enums\\TiptapOutput;\n\nTiptapEditor::make('content')\n    -\u003eoutput(FilamentTiptapEditor\\TiptapOutput::Json);\n```\n\nThere are 3 components you need to create a custom block for Tiptap Editor.\n\n* A block class that extends `TiptapBlock` and defines the settings for the block.\n* A 'preview' blade file\n* A 'rendered' blade file\n\n### Creating a custom block\n\n#### Block class\n\n```php\nuse FilamentTiptapEditor\\TiptapBlock;\n\nclass BatmanBlock extends TiptapBlock\n{\n    public string $preview = 'blocks.previews.batman';\n\n    public string $rendered = 'blocks.rendered.batman';\n\n    public function getFormSchema(): array\n    {\n        return [\n            TextInput::make('name'),\n            TextInput::make('color'),\n            Select::make('side')\n                -\u003eoptions([\n                    'Hero' =\u003e 'Hero',\n                    'Villain' =\u003e 'Villain',\n                ])\n                -\u003edefault('Hero')\n        ];\n    }\n}\n```\n\n#### Static blocks\n\nIf you simply need a placeholder to output a block that doesn't have settings you can simply not provide a `getFormSchema` method and no modal will be shown and blocks will be directly inserted into the editor.\n\n```php\nuse FilamentTiptapEditor\\TiptapBlock;\n\nclass StaticBlock extends TiptapBlock\n{\n    public string $preview = 'blocks.previews.static';\n\n    public string $rendered = 'blocks.rendered.static';\n}\n```\n\n#### Modal width, slide overs and icons\n\n***Note***: Currently, icons will only be show on the drag and drop block panel\n\n```php\nclass BatmanBlock extends TiptapBlock\n{\n    public string $width = 'xl';\n    \n    public bool $slideOver = true;\n    \n    public ?string $icon = 'heroicon-o-film';\n}\n```\n\n#### Preview view\n\nPreview views are just standard blade views. Unfortunately, you cannot use Livewire components in a block preview as they will not work correctly due to the editor having to be wire:ignore.\n\n`resources/views/blocks/previews/batman.blade.php`\n```html\n\u003cdiv class=\"flex items-center gap-6\"\u003e\n    \u003cdiv class=\"text-5xl\"\u003e\n        @php\n            echo match($name) {\n                'robin' =\u003e '🐤',\n                'ivy' =\u003e '🥀',\n                'joker' =\u003e '🤡',\n                default =\u003e '🦇'\n            }\n        @endphp\n    \u003c/div\u003e\n    \u003cdiv\u003e\n        \u003cp\u003eName: {{ $name }}\u003c/p\u003e\n        \u003cp style=\"color: {{ $color }};\"\u003eColor: {{ $color }}\u003c/p\u003e\n        \u003cp\u003eSide: {{ $side ?? 'Good' }}\u003c/p\u003e\n    \u003c/div\u003e\n\u003c/div\u003e\n```\n\n#### Rendered view\n\nRendered views are normal blade files and can also be used to output livewire components with your block data.\n\n`resources/views/blocks/rendered/batman.blade.php`\n```html\n\u003cdiv\u003e\n    \u003clivewire:batman-block\n        :name=\"$name\"\n        :color=\"$color\"\n        :side=\"$side\"\n    /\u003e\n\u003c/div\u003e\n```\n\n#### Registering your blocks with the editor\n\nIn the register method of a service provider you can add your blocks to the editor via `configureUsing`.\n\n\u003e **Note**\n\u003e You will also need to add the 'blocks' key where appropriate in your profiles in the tiptap config.\n\n```php\nuse App\\TiptapBlocks\\BatmanBlock;\nuse App\\TiptapBlocks\\StaticBlock;\nuse FilamentTiptapEditor\\TiptapEditor;\n\nTiptapEditor::configureUsing(function (TiptapEditor $component) {\n    $component\n        -\u003eblocks([\n            BatmanBlock::class,\n            StaticBlock::class,\n        ]);\n});\n```\n\nBy default, the drag and drop blocks panel will be open in the editor. If you want to change this you can use the `collapseBlocksPanel` modifier on the Editor instance or globally with `configureUsing`.\n\n```php\nuse App\\TiptapBlocks\\BatmanBlock;\nuse App\\TiptapBlocks\\StaticBlock;\nuse FilamentTiptapEditor\\TiptapEditor;\n\nTiptapEditor::configureUsing(function (TiptapEditor $component) {\n    $component\n        -\u003ecollapseBlocksPanel()\n        -\u003eblocks([...]);\n});\n```\n\n## Merge tags\n\nMerge tags can be used with JSON-based editor content to replace placeholders with dynamic content. Merge tags are defined in the `mergeTags()` method of the editor instance:\n\n```php\nTiptapEditor::make('content')\n    -\u003emergeTags([\n        'first_name',\n        'last_name',\n    ])\n```\n\nTo insert a merge tag, the user can either type `{{` to open an autocomplete menu, or drag a merge tag into the editor from the \"blocks panel\". You can remove the tags from the blocks panel using `showMergeTagsInBlocksPanel(false)`:\n\n```php\nTiptapEditor::make('content')\n    -\u003emergeTags([...])\n    -\u003eshowMergeTagsInBlocksPanel(false)\n```\n\n### Rendering merge tags\n\nWhile you have full control over how the content of the merge tags are replaced, you can use the `mergeTagsMap()` method on the `tiptap_converter` helper to replace the tags with the provided data:\n\n```blade\n{!! tiptap_converter()-\u003emergeTagsMap(['first_name' =\u003e 'John', 'last_name' =\u003e 'Doe'])-\u003easHTML($content) !!}\n```\n\n## Usage in Standalone Forms Package\n\nIf you are using any of the tools that require a modal (e.g. Insert media, Insert video, etc.), make sure to add `{{ $this-\u003emodal }}` to your view after the custom form:\n\n```php\n\u003cform wire:submit.prevent=\"submit\"\u003e\n    {{ $this-\u003eform }}\n\n    \u003cbutton type=\"submit\"\u003e\n        Save\n    \u003c/button\u003e\n\u003c/form\u003e\n\n{{ $this-\u003emodal }}\n```\n### Placeholders\n\nYou can easily set a placeholder, the Filament way:\n\n```php\nTiptapEditor::make('content')\n    -\u003eplaceholder('Write something...')\n```\n\nYou can define specific placeholders for each node type using the `-\u003enodePlaceholders()` method. This method accepts an associative array, where the keys are the node type names, and the values are the corresponding placeholder texts.\n\n```php\nTiptapEditor::make('content')\n    -\u003enodePlaceholders([\n        'paragraph' =\u003e 'Start writing your paragraph...',\n        'heading' =\u003e 'Insert a heading...',\n    ])\n```\n\nThe `-\u003eshowOnlyCurrentPlaceholder()` method allows you to control whether placeholders are shown for all nodes simultaneously or only for the currently active node.\n\n```php\nTiptapEditor::make('content')\n    // All nodes will immediately be displayed, instead of only the selected node\n    -\u003eshowOnlyCurrentPlaceholder(false)\n```\n\n### Mentions\n\nThe [Tiptap Mention extension](https://tiptap.dev/docs/editor/extensions/nodes/mention) has been integrated into this package.\n\n#### Static Mentions\n\nYou can pass an array of suggestions using `-\u003ementionItems()`. The most convenient way is to use instances of the `MentionItem` object, which accepts several parameters:\n\n```php\nTiptapEditor::make(name: 'content')\n    -\u003ementionItems([\n        // The simplest mention item: a label and a id\n        new MentionItem(label: 'Banana', id: 1),\n        \n         // Add a href to make the mention clickable in the final HTML output\n        new MentionItem(id: 1, label: 'Strawberry', href: 'https://filamentphp.com'),\n        \n        // Include additional data to be stored in the final JSON output\n        new MentionItem(id: 1, label: 'Strawberry', data: ['type' =\u003e 'fruit_mentions']),\n    ])\n```\n\nAlternatively, you can use arrays instead of `MentionItem` objects:\n\n```php\nTiptapEditor::make(name: 'content')\n    -\u003ementionItems([\n        ['label' =\u003e 'Apple', 'id' =\u003e 1],\n        ['label' =\u003e 'Banana', 'id' =\u003e 2],\n        ['label' =\u003e 'Strawberry', 'id' =\u003e 3],\n    ])\n```\n\nYou can specify a search strategy for mentions. By default, the search uses a \"starts with\" approach, matching labels that begin with your query. Alternatively, you can opt for the tokenized strategy, which is suited for matching multiple keywords within a label.\n\n```php\nTiptapEditor::make(name: 'content')\n    // You can also use MentionSearchStrategy::Tokenized\n    -\u003ementionSearchStrategy(MentionSearchStrategy::StartsWith)\n```\n\n#### Dynamic Mentions\nIn many scenarios, you may want to load mentionable items dynamically, such as through an API. To enable this functionality, start by adding the following trait to your Livewire component:\n\n```php\nuse FilamentTiptapEditor\\Concerns\\HasFormMentions;\n\nclass YourClass\n{\nuse HasFormMentions;\n```\n\nNext, you can provide dynamic suggestions using the `getMentionItemsUsing()` method. Here's an example:\n\n```php\nTiptapEditor::make(name: 'content')\n    -\u003egetMentionItemsUsing(function (string $query) {\n        // Get suggestions based of the $query\n        return User::search($query)-\u003eget()-\u003emap(fn ($user) =\u003e new MentionItem(\n            id: $user-\u003eid,\n            label: $user-\u003ename\n        ))-\u003etake(5)-\u003etoArray();\n    })\n```\n\nThere is a default debounce time to prevent excessive searches. You can adjust this duration to suit your needs:\n\n```php\nTiptapEditor::make(name: 'content')\n    -\u003ementionDebounce(debounceInMs: 300)\n```\n\n#### Adding image prefixes to mention items\n\nYou may add images as a prefix to your mention items:\n\n```php\nTiptapEditor::make(name: 'content')\n    -\u003ementionItems([\n        new MentionItem(id: 1, label: 'John Doe', image: 'YOUR_IMAGE_URL'),\n        \n        // Optional: Show rounded image, useful for avatars\n        new MentionItem(id: 1, label: 'John Doe', image: 'YOUR_IMAGE_URL', roundedImage: true),\n    ])\n```\n\n#### Additional Mention Features\nYou can customize a few other aspects of the mention feature:\n\n```php\nTiptapEditor::make(name: 'content')\n    // Customize the \"No results found\" message\n    -\u003eemptyMentionItemsMessage(\"No users found\")\n    \n    // Set a custom placeholder message. Note: if you set a placeholder, then it will ONLY show suggestions when the query is not empty.\n    -\u003ementionItemsPlaceholder(\"Search for users...\")\n    \n    // Set a custom loading message. This will be displayed instead of a loading spinner.\n    -\u003ementionItemsLoading(\"Loading...\")\n    \n    // Customize how many mention items should be shown at once, 8 by default. Is nullable and only works with static suggestions.\n    -\u003emaxMentionItems()\n\n    // Set a custom character trigger for mentioning. This is '@' by default\n    -\u003ementionTrigger('#')\n\n```\n\n## Custom Extensions\n\nYou can add your own extensions to the editor by creating the necessary files and adding them to the config file extensions array.\n\n***This only support CSS and JS with Vite.***\n\nYou can read more about custom extensions at [https://tiptap.dev/guide/custom-extensions](https://tiptap.dev/guide/custom-extensions).\n\n### JS\n\nFirst, create a directory for you custom extensions at `resources/js/tiptap` and add your extension files.\n\n```js\nimport { Node, mergeAttributes } from \"@tiptap/core\";\n\nconst Hero = Node.create({\n    name: \"hero\",\n    ...\n})\n\nexport default Hero\n\n```\n\nNext, create at a file at `resources/js/tiptap/extensions.js` and add the following code.\n\n***Note that when adding your extension to the array you must register them a key:array set.***\n\n```js\nimport Hero from \"./hero.js\";\n\nwindow.TiptapEditorExtensions = {\n    hero: [Hero]\n}\n```\n\n### CSS\n\nCreate a css file for your custom extensions at `resources/css/tiptap/extensions.css`. All styles should be scoped to the parent class of `.tiptap-content`.\n\n```css\n.tiptap-content {\n    .hero-block {\n        ...\n    }\n}\n```\n\n### Vite Config\n\nNow you need to add these to your `vite.config.js` file and run a build to generate the files.\n\n```js\nexport default defineConfig({\n    plugins: [\n        laravel({\n            input: [\n                ...\n                'resources/js/tiptap/extensions.js',\n                'resources/css/tiptap/extensions.css',\n            ],\n            refresh: true,\n        }),\n    ],\n});\n```\n\n### PHP Parser\n\nYou will also need to create a PHP version of your extension in order for the content to be read from the database and rendered in the editor or to your front end display. You are free to create this anywhere in your app, a good place is something like `app/TiptapExtensions/YourExtenion.php`.\n\nYou can read more about the php parsers at [https://github.com/ueberdosis/tiptap-php](https://github.com/ueberdosis/tiptap-php)\n\n```php\nnamespace App\\TiptapExtensions;\n\nuse Tiptap\\Core\\Node;\n\nclass Hero extends Node\n{\n    public static $name = 'hero';\n    ...\n}\n```\n\n### Toolbar Button\n\nYou will also need to crate a dedicated view for you toolbar button. This should be placed somewhere in your app's `resources/views/components` directory. You are free to code the buttons as you see fit, but it is recommended to use the plugin's view components for uniformity.\n\n```blade\n\u003cx-filament-tiptap-editor::button\n    label=\"Hero\"\n    active=\"hero\"\n    action=\"editor().commands.toggleHero()\"\n\u003e\n    \u003csvg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\"\u003e\u003cpath fill=\"currentColor\" d=\"M5 21q-.825 0-1.413-.588T3 19V5q0-.825.588-1.413T5 3h14q.825 0 1.413.588T21 5v14q0 .825-.588 1.413T19 21H5Zm0-2h14v-5H5v5Z\"/\u003e\u003c/svg\u003e\n    \n    \u003cspan class=\"sr-only\"\u003e{{ $label }}\u003c/span\u003e\n\u003c/x-filament-tiptap-editor::button\u003e\n```\n\n### Registering the Extensions\n\nFinally, you need to register your extensions in the config file and add the new extension to the appropriate `profile`.\n\n```php\n'profiles' =\u003e [\n    'minimal' =\u003e [\n        ..., \n        'hero',\n    ],\n],\n'extensions_script' =\u003e 'resources/js/tiptap/extensions.js',\n'extensions_styles' =\u003e 'resources/css/tiptap/extensions.css',\n'extensions' =\u003e [\n    [\n        'id' =\u003e 'hero',\n        'name' =\u003e 'Hero',\n        'button' =\u003e 'tools.hero',\n        'parser' =\u003e \\App\\TiptapExtensions\\Hero::class,\n    ],\n],\n```\n\n## Versioning\n\nThis project follow the [Semantic Versioning](https://semver.org/) guidelines.\n\n## License\n\nCopyright (c) 2022 Adam Weston and contributors\n\nLicensed under the MIT license, see [LICENSE.md](LICENSE.md) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fawcodes%2Ffilament-tiptap-editor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fawcodes%2Ffilament-tiptap-editor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fawcodes%2Ffilament-tiptap-editor/lists"}