Skip to content

Commit

Permalink
LWS-260: Codemirror extension for submitting forms on enter key (#1155)
Browse files Browse the repository at this point in the history
* Add CodeMirror extension for submitting form on enter keypress

* Add test

* Add optional form attribute

* Add hidden textarea inside component for name and value attributes
  • Loading branch information
johanbissemattsson authored Nov 14, 2024
1 parent 4f818e8 commit 1be6379
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 7 deletions.
13 changes: 9 additions & 4 deletions lxl-web/src/lib/components/Search.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
let q = $page.params.fnurgel
? '' //don't reflect related search on resource pages
: showAdvanced
? $page.url.searchParams.get('_q')?.trim()
: $page.url.searchParams.get('_i')?.trim();
? $page.url.searchParams.get('_q')?.trim() || ''
: $page.url.searchParams.get('_i')?.trim() || '';
let params = getSortedSearchParams(addDefaultSearchParams($page.url.searchParams));
// Always reset these params on new search
Expand All @@ -30,7 +30,7 @@
/** Update input value after navigation on /find route */
if (to?.url) {
let param = showAdvanced ? '_q' : '_i';
q = $page.params.fnurgel ? '' : new URL(to.url).searchParams.get(param)?.trim();
q = $page.params.fnurgel ? '' : new URL(to.url).searchParams.get(param)?.trim() || '';
}
});
Expand All @@ -45,7 +45,12 @@

<form class="relative w-full" action="find" on:submit={handleSubmit}>
{#if env?.PUBLIC_USE_SUPERSEARCH === 'true'}
<SuperSearch language={lxlQueryLanguage} placeholder={$page.data.t('search.search')} />
<SuperSearch
name="_q"
bind:value={q}
language={lxlQueryLanguage}
placeholder={$page.data.t('search.search')}
/>
{:else}
<!-- svelte-ignore a11y-autofocus -->
<input
Expand Down
17 changes: 17 additions & 0 deletions packages/supersearch/e2e/supersearch.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { test, expect } from '@playwright/test';

test.beforeEach(async ({ page }) => {
await page.goto('/');
});

test('submits closest form on enter key press', async ({ page }) => {
await page.locator('[data-test-id="test1"]').getByRole('textbox').locator('div').fill('hello world')
await page.keyboard.press('Enter');
await expect(page).toHaveURL('/test1?q=hello+world')
});

test('submits form identified by form attribute on enter key press', async ({ page }) => {
await page.locator('[data-test-id="test2"]').getByRole('textbox').locator('div').fill('hello world')
await page.keyboard.press('Enter');
await expect(page).toHaveURL('/test2?q=hello+world')
});
9 changes: 7 additions & 2 deletions packages/supersearch/src/lib/components/SuperSearch.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,25 @@
import { EditorView, placeholder as placeholderExtension } from '@codemirror/view';
import { Compartment } from '@codemirror/state';
import { type LRLanguage } from '@codemirror/language';
import submitFormOnEnterKey from '$lib/extensions/submitFormOnEnterKey.js';
interface Props {
name: string;
value?: string;
form?: string;
language?: LRLanguage;
placeholder?: string;
}
let { language, placeholder = '' }: Props = $props();
let { name, value = $bindable(''), form, language, placeholder = '' }: Props = $props();
let value = $state('');
let editorView: EditorView | undefined = $state();
let placeholderCompartment = new Compartment();
let prevPlaceholder = placeholder;
const extensions = [
submitFormOnEnterKey(form),
...(language ? [language] : []),
placeholderCompartment.of(placeholderExtension(placeholder))
];
Expand All @@ -37,3 +41,4 @@
</script>

<CodeMirror {value} {extensions} onchange={handleChangeCodeMirror} bind:editorView />
<textarea {value} {name} {form} hidden readonly></textarea>
37 changes: 37 additions & 0 deletions packages/supersearch/src/lib/extensions/submitFormOnEnterKey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Prec } from '@codemirror/state';
import { EditorView, keymap } from '@codemirror/view';

/**
* CodeMirror extension that submits form elements (either the closest or by specified id using the `form` attribute) on enter keypresses.
*
* @param {string} form Optional id of the `<form>` element with which the form control should be associated with (equivalent with
* the [form attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#form) on HTML Input elements).
*/

const submitFormOnEnterKey = (form?: string) => {
const submitForm = (editorView: EditorView) => {
const formElement = form ? document.getElementById(form) : editorView.dom?.closest('form');

if (formElement && formElement instanceof HTMLFormElement) {
formElement.requestSubmit();
return true; // return true to prevent further commands to be tried
}

return false;
};

return Prec.highest(
keymap.of([
{
key: 'Enter',
run: submitForm
},
{
key: 'Shift-Enter',
run: submitForm
}
])
);
};

export default submitFormOnEnterKey;
17 changes: 16 additions & 1 deletion packages/supersearch/src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
<script lang="ts">
import SuperSearch from '$lib/components/SuperSearch.svelte';
let value = $state('');
let placeholder = $state('Search');
</script>

<SuperSearch {placeholder} />
<form action="test1">
<fieldset data-test-id="test1">
<legend>Supersearch inside <code>&lt;form&gt;</code> element</legend>
<SuperSearch name="q" bind:value {placeholder} />
</fieldset>
</form>

<form>
<fieldset data-test-id="test2">
<legend>Supersearch using <code>form</code> attribute</legend>
<SuperSearch name="q" bind:value {placeholder} form="form-outside" />
</fieldset>
</form>

<form action="test2" id="form-outside"></form>

<label>Placeholder:<input type="text" bind:value={placeholder} /></label>
1 change: 1 addition & 0 deletions packages/supersearch/src/routes/test1/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h1>A test route</h1>
1 change: 1 addition & 0 deletions packages/supersearch/src/routes/test2/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h1>Another test route</h1>

0 comments on commit 1be6379

Please sign in to comment.