-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Can't use custom Tiptap extensions with Editor component #746
Comments
@philippbuerger With a little experimentation, I was able to access the editor object and create a
Maybe this can help as a starting point for your exploration into custom toolbar buttons. |
@jeffchown thanks for the hint. I was able implement the same logic with |
Thinking about what is the best way to install custom extensions for tiptap for e.g. https://tiptap.dev/docs/editor/extensions/nodes/table and using it? Any suggestions? |
Not yet. I have some experimentation to do with the new Fluxified version of TipTap. I won't have time to experiment with this until next week, but will post any findings here when I do. |
Yes, I mentioned this in #739 (comment) as well. |
@philippbuerger can you provide code for how you are currently trying to add a custom button or how you expect it to work, so we can replicate it and see what is the best way? Thanks! |
@philippbuerger - Your However, you're right, having a way to add your own extensions would be nice. We could add an event hook or something that allows you to append your own extension object onto ours. The tricky thing is that I think you have to include extensions when you initialize the editor (and can't after initialization). This means we would need some kind of event-driven setup that allows you to add it at the right time in the boot process. Something like this maybe?:
This would be part of your app bundle and you would have to make sure it executes before Flux's JS... (which may actually be difficult) Can anyone else think of any other way out-of-the-box alternatives for this story? I could see
|
@calebporzio On first think, the event-driven/hook approach will probably be the best. Anyone who wants to customize The first of last two possibles you present:
|
Just a quick thought, and not sure if it could work as I haven't any experience on building webcomponents: I noticed that flux extends the webcomponent classes, and that (if i'm correct) the js that defines the webcomponent is loaded using AssetManager::editorScripts() So wouldn't it be possible to create a custom editor webcomponent class that extends the base editor class. And possibly through a property on de flux:editor component the js file of that custom class is passed to editorScripts() to make sure the correct script is loaded? In case none is passed, editorScripts will use the default editor implementation. The base class could look something like this: class BaseEditor extends UIControl {
constructor() {
super();
this.editor = null;
}
connectedCallback() {
this.initializeEditor();
this.setupEventListeners();
this.setupToolbar();
this.setupAccessibility();
}
initializeEditor() {
const defaultExtensions = [
// Default extensions
];
this.editor = new Editor({
extensions: [
...defaultExtensions,
...this.getCustomExtensions()
],
content: getContent()
});
}
getContent(){
return this.innerHTML
}
getCustomExtensions(){
return [
// the custom extensions, method can be overridden
]
}
setupEventListeners() {
this.addEventListener('keydown', e => {
//
});
}
setupToolbar() {
initializeToolbar(this.editor, this.querySelector('ui-toolbar'));
}
setupAccessibility() {
this._disableable.onInitAndChange(disabled => {
//
});
}
// and other methods getValue, setValue, mount, focus, ...
} The custom class could look something like this import TextAlign from '@tiptap/extension-text-align'
class CustomEditor extends BaseEditor {
constructor() {
super();
}
// simply pass the extensions through getCustomExtensions
getCustomExtensions() {
// Return an array of custom extensions
return [
TextAlign.configure({
types: ['paragraph', 'heading'],
alignments: ['left', 'center', 'right'],
})
];
}
// or redefine initializeEditor() completely if necessary
initializeEditor() {
const defaultExtensions = [
// Default extensions
];
this.editor = new Editor({
extensions: [
...defaultExtensions,
this.getCustomExtensions()
],
content: this.innerHTML,
});
}
getValue() {
// Override getValue method
return this.editor.getJSON(); // Example of returning JSON instead of HTML
}
setValue(value) {
// Override setValue method
this.editor.commands.setContent(value, false); // Example of setting content without replacing all
}
} which is then passed to flux like this <flux:editor custom="/resources/js/myCustomEditor.js" /> |
How about providing a global array of editor extension and once the flux editor initializes, it looks for this global array and appends it to its extensions? This way it can be part of your app bundle and you won't have to figure out when to load it. Example: import TextAlign from '@tiptap/extension-text-align'
window.fluxEditorExtensions = [
TextAlign.configure({
types: ['paragraph', 'heading'],
alignments: ['left', 'center', 'right'],
}
] |
@calebporzio I think we can use the event-driven setup and ensure it executes before Flux's Js by allowing users to provide a script url to the flux editor using a 'customize' attribute (or 'configure or 'script' attribute? don't know what the best name would be) <flux:editor :customize="Vite::asset('resources/js/flux-editor-customizations.js') /> In the <!-- In flux/editor/index.blade.php -->
@assets
@if ($attributes->has('customize'))
<script src="{{ $attributes->get('customize') }}"></script>
@endif
<flux:editor.scripts />
<flux:editor.styles />
@endassets If the custom script is not deferred, then that script will always be loaded before it even starts to download and load the flux editor script file if I'm not mistaken 🤔 Maybe it is even possible to make the customize script deferred by waiting for it to be loaded in Flux editor js file 🤔 // In Flux Editor JS
var customizeScript = document.querySelector('#customize-flux-editor-script');
if (customizeScript) {
customizeScript.addEventListener('load', function() {
// start executing the flux editor js code ...
});
} else {
// start executing the flux editor js code ...
} The custom script can then use the event-driven setup you previously suggested: // In resources/js/flux-editor-customizations.js of your laravel project
import TextAlign from '@tiptap/extension-text-align'
document.addEventListener('flux:editor', e => {
e.target.appendExtension(TextAlign.configure({
types: ['paragraph', 'heading'],
alignments: ['left', 'center', 'right'],
}),)
}) |
It should also be possible to customize the existing extensions. In a project, I added custom protocols to the link extension using the following code: window.customElements.whenDefined('ui-editor').then(() => {
document.querySelectorAll('ui-editor').forEach(uiEditor => {
let editor = uiEditor.editor;
let toolbar = uiEditor.querySelector('ui-toolbar');
editor.extensionManager.extensions.filter(extension => extension.name == 'link')[0].options.protocols = ['mailto', 'page', 'procedure', 'legislation'];
editor.setOptions();
});
}) This works if the editor does not have any content yet. If the editor is loaded with existing content and the content contains links with those custom protocols, then the links with those custom protocols are purged by TipTap. This is because those custom protocols are added to the extension's configuration after loading the initial editor. To fix that, the Flux editor should have the ability to edit its default extensions while also adding new extensions. |
How can I access the current editor object in a custom toolbar button? I'm trying to implement the unset all marks function from tip tap.
The text was updated successfully, but these errors were encountered: