Lexical: Range of fixes

- Prevented ui shortcuts running in editor
- Added form modal closing on submit
- Fixed ability to escape lists via enter on empty last item
This commit is contained in:
Dan Brown 2024-09-22 16:15:02 +01:00
parent ef3de1050f
commit c8ccb2bac7
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
6 changed files with 38 additions and 15 deletions

View File

@ -25,7 +25,7 @@ export class Shortcuts extends Component {
setupListeners() { setupListeners() {
window.addEventListener('keydown', event => { window.addEventListener('keydown', event => {
if (event.target.closest('input, select, textarea, .cm-editor')) { if (event.target.closest('input, select, textarea, .cm-editor, .editor-container')) {
return; return;
} }

View File

@ -259,9 +259,21 @@ export class ListItemNode extends ElementNode {
_: RangeSelection, _: RangeSelection,
restoreSelection = true, restoreSelection = true,
): ListItemNode | ParagraphNode { ): ListItemNode | ParagraphNode {
if (this.getTextContent().trim() === '' && this.isLastChild()) {
const list = this.getParentOrThrow<ListNode>();
if (!$isListItemNode(list.getParent())) {
const paragraph = $createParagraphNode();
list.insertAfter(paragraph, restoreSelection);
this.remove();
return paragraph;
}
}
const newElement = $createListItemNode( const newElement = $createListItemNode(
this.__checked == null ? undefined : false, this.__checked == null ? undefined : false,
); );
this.insertAfter(newElement, restoreSelection); this.insertAfter(newElement, restoreSelection);
return newElement; return newElement;

View File

@ -7,8 +7,6 @@
## Main Todo ## Main Todo
- Mac: Shortcut support via command. - Mac: Shortcut support via command.
- Translations
- Form closing on submit
- Update toolbar overflows to match existing editor, incl. direction dynamic controls - Update toolbar overflows to match existing editor, incl. direction dynamic controls
## Secondary Todo ## Secondary Todo
@ -17,11 +15,9 @@
- Color picker for color controls - Color picker for color controls
- Table caption text support - Table caption text support
- Support media src conversions (https://github.com/tinymce/tinymce/blob/release/6.6/modules/tinymce/src/plugins/media/main/ts/core/UrlPatterns.ts) - Support media src conversions (https://github.com/tinymce/tinymce/blob/release/6.6/modules/tinymce/src/plugins/media/main/ts/core/UrlPatterns.ts)
- Check translation coverage - Deep check of translation coverage
## Bugs ## Bugs
- List selection can get lost on nesting/unnesting - List selection can get lost on nesting/unnesting
- Can't escape lists when bottom element - Content not properly saving on new pages
- Content not properly saving on new pages
- BookStack UI (non-editor) shortcuts can trigger in editor (`/` for example)

View File

@ -100,13 +100,12 @@ export const image: EditorFormDefinition = {
export function $showLinkForm(link: LinkNode|null, context: EditorUiContext) { export function $showLinkForm(link: LinkNode|null, context: EditorUiContext) {
const linkModal = context.manager.createModal('link'); const linkModal = context.manager.createModal('link');
let formDefaults = {};
if (link) { if (link) {
formDefaults = { const formDefaults: Record<string, string> = {
url: link.getURL(), url: link.getURL(),
text: link.getTextContent(), text: link.getTextContent(),
title: link.getTitle(), title: link.getTitle() || '',
target: link.getTarget(), target: link.getTarget() || '',
} }
context.editor.update(() => { context.editor.update(() => {
@ -114,9 +113,16 @@ export function $showLinkForm(link: LinkNode|null, context: EditorUiContext) {
selection.add(link.getKey()); selection.add(link.getKey());
$setSelection(selection); $setSelection(selection);
}); });
}
linkModal.show(formDefaults); linkModal.show(formDefaults);
} else {
context.editor.getEditorState().read(() => {
const selection = $getSelection();
const text = selection?.getTextContent() || '';
const formDefaults = {text};
linkModal.show(formDefaults);
});
}
} }
export const link: EditorFormDefinition = { export const link: EditorFormDefinition = {

View File

@ -72,6 +72,7 @@ export class EditorFormField extends EditorUiElement {
export class EditorForm extends EditorContainerUiElement { export class EditorForm extends EditorContainerUiElement {
protected definition: EditorFormDefinition; protected definition: EditorFormDefinition;
protected onCancel: null|(() => void) = null; protected onCancel: null|(() => void) = null;
protected onSuccessfulSubmit: null|(() => void) = null;
constructor(definition: EditorFormDefinition) { constructor(definition: EditorFormDefinition) {
let children: (EditorFormField|EditorUiElement)[] = definition.fields.map(fieldDefinition => { let children: (EditorFormField|EditorUiElement)[] = definition.fields.map(fieldDefinition => {
@ -98,6 +99,10 @@ export class EditorForm extends EditorContainerUiElement {
this.onCancel = callback; this.onCancel = callback;
} }
setOnSuccessfulSubmit(callback: () => void) {
this.onSuccessfulSubmit = callback;
}
protected getFieldByName(name: string): EditorFormField|null { protected getFieldByName(name: string): EditorFormField|null {
const search = (children: EditorUiElement[]): EditorFormField|null => { const search = (children: EditorUiElement[]): EditorFormField|null => {
@ -128,10 +133,13 @@ export class EditorForm extends EditorContainerUiElement {
]) ])
]); ]);
form.addEventListener('submit', (event) => { form.addEventListener('submit', async (event) => {
event.preventDefault(); event.preventDefault();
const formData = new FormData(form as HTMLFormElement); const formData = new FormData(form as HTMLFormElement);
this.definition.action(formData, this.getContext()); const result = await this.definition.action(formData, this.getContext());
if (result && this.onSuccessfulSubmit) {
this.onSuccessfulSubmit();
}
}); });
cancelButton.addEventListener('click', (event) => { cancelButton.addEventListener('click', (event) => {

View File

@ -28,6 +28,7 @@ export class EditorFormModal extends EditorContainerUiElement {
const form = this.getForm(); const form = this.getForm();
form.setValues(defaultValues); form.setValues(defaultValues);
form.setOnCancel(this.hide.bind(this)); form.setOnCancel(this.hide.bind(this));
form.setOnSuccessfulSubmit(this.hide.bind(this));
this.getContext().manager.setModalActive(this.key, this); this.getContext().manager.setModalActive(this.key, this);
} }