Skip to content

Commit f15593b

Browse files
authored
Rich text focus and selection improvements (#1728)
* Make full rich-text-field clickable * Allow clicking on labels to focus rich-text input * Don't clear rich-text-input selection on blur to mimic native inputs
1 parent 0fbf8eb commit f15593b

1 file changed

Lines changed: 19 additions & 7 deletions

File tree

frontend/viewer/src/lib/components/lcm-rich-text-editor/lcm-rich-text-editor.svelte

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,18 @@
3434
<script lang="ts">
3535
import type {IRichString} from '$lib/dotnet-types/generated-types/MiniLcm/Models/IRichString';
3636
import {Label} from '$lib/components/ui/label';
37-
import InputShell from '../ui/input/input-shell.svelte';
3837
import {EditorView} from 'prosemirror-view';
39-
import {AllSelection, EditorState, TextSelection} from 'prosemirror-state';
38+
import {AllSelection, EditorState} from 'prosemirror-state';
4039
import {keymap} from 'prosemirror-keymap';
4140
import {baseKeymap} from 'prosemirror-commands';
4241
import {undo, redo, history} from 'prosemirror-history';
4342
import {onDestroy, onMount} from 'svelte';
4443
import {watch} from 'runed';
4544
import type {HTMLAttributes} from 'svelte/elements';
46-
import {IsUsingKeyboard, mergeProps} from 'bits-ui';
45+
import {IsUsingKeyboard} from 'bits-ui';
4746
import type {IRichSpan} from '$lib/dotnet-types/generated-types/MiniLcm/Models/IRichSpan';
47+
import {inputVariants} from '../ui/input/input.svelte';
48+
import {on} from 'svelte/events';
4849
4950
let {
5051
value = $bindable(),
@@ -83,6 +84,9 @@
8384
}
8485
editor.updateState(newState);
8586
},
87+
attributes: {
88+
class: inputVariants({class: 'min-h-10 h-auto block'}),
89+
},
8690
editable() {
8791
return !readonly;
8892
},
@@ -92,6 +96,9 @@
9296
}
9397
});
9498
editor.dom.setAttribute('tabindex', '0');
99+
100+
const parentLabel = elementRef?.closest('label');
101+
if (parentLabel) return on(parentLabel, 'click', onFocusTargetClick);
95102
});
96103
97104
function onfocus(editor: EditorView) {
@@ -174,7 +181,6 @@
174181
if (selection && editor.dom.contains(selection.anchorNode) && editor.dom.contains(selection.focusNode)) {
175182
selection.removeAllRanges();
176183
}
177-
editor.dispatch(editor.state.tr.setSelection(TextSelection.create(editor.state.doc, 0)));
178184
}
179185
180186
//lcm expects line separators, but html does not render them, so we replace them with \n
@@ -184,6 +190,12 @@
184190
function replaceLineSeparatorWithNewLine(text: string) {
185191
return text.replaceAll(lineSeparator, newLine);
186192
}
193+
194+
function onFocusTargetClick(event: MouseEvent) {
195+
if (!editor) return;
196+
if (event.target === editor?.dom) return; // the editor will handle focus itself
197+
editor.focus();
198+
}
187199
</script>
188200
<style>
189201
:global(.ProseMirror) {
@@ -201,9 +213,9 @@
201213

202214
{#if label}
203215
<div {...rest}>
204-
<Label>{label}</Label>
205-
<InputShell {autofocus} class="p-2 h-auto" bind:ref={elementRef}/>
216+
<Label onclick={onFocusTargetClick}>{label}</Label>
217+
<div bind:this={elementRef}></div>
206218
</div>
207219
{:else}
208-
<InputShell {autofocus} {...mergeProps({ class: 'p-2 h-auto'}, rest)} bind:ref={elementRef}/>
220+
<div bind:this={elementRef}></div>
209221
{/if}

0 commit comments

Comments
 (0)