fix(tagging): keep focus on the instructions select after a pick (#431)
A pick re-renders the dialog's fields; the select it was made with gets focus back. The one-off note describes the textarea while it shows.
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
import { startCoverage, saveCoverage } from '../../tools/vendor/browser-coverage.mjs';
|
||||
import { test, expect } from './fixtures.mjs';
|
||||
import { saveImageTags } from './concept-inventory.mjs';
|
||||
import { taggingInventory } from './tagging-canonical-comparison.mjs';
|
||||
import { FIXTURE_INSTRUCTIONS_ID, taggingInventory } from './tagging-canonical-comparison.mjs';
|
||||
|
||||
const images = '/prompt_manager/workspace#/images';
|
||||
const MODULE = '/prompt_manager/js/workspace/image-tagging.mjs';
|
||||
@@ -878,9 +878,13 @@ test('the saved instructions picker fills, edits one-off and resets per engine (
|
||||
await expect(pick).toHaveAttribute('id', 'image-tag-instructions-pick');
|
||||
await expect(text).toHaveValue('Describe the image');
|
||||
await expect(note).toBeHidden();
|
||||
// A keyboard pick (the select focused) keeps focus on the select the fields are re-rendered with.
|
||||
await pick.focus();
|
||||
await pick.selectOption('builtin');
|
||||
await expect(text).toHaveValue(builtin);
|
||||
await expect(pick).toBeFocused();
|
||||
await text.fill('Only the sky.');
|
||||
await expect(text).toHaveAttribute('aria-describedby', 'image-tag-instructions-pick-note');
|
||||
await expect(pick.locator('option:checked')).toHaveText('Edited for this run');
|
||||
await expect(pick.locator('option[value="edited"]')).toBeDisabled();
|
||||
await expect(note).toHaveText('Edits apply to this run only. Manage saved instructions in System › Auto-tagging.');
|
||||
@@ -896,7 +900,7 @@ test('the saved instructions picker fills, edits one-off and resets per engine (
|
||||
await text.fill('Edited again.');
|
||||
await model(page).selectOption('hf');
|
||||
await expect(text).toHaveValue('Describe the image');
|
||||
await expect(pick).toHaveValue('d35c71be0a1e');
|
||||
await expect(pick).toHaveValue(FIXTURE_INSTRUCTIONS_ID);
|
||||
await model(page).selectOption('wd14-vit');
|
||||
await expect(pick).toHaveCount(0);
|
||||
await expect(text).toHaveCount(0);
|
||||
|
||||
@@ -243,8 +243,6 @@ async function readDefaults(api, signal) {
|
||||
defaults: {
|
||||
general_threshold: unit(value.wd14_general_threshold) ? value.wd14_general_threshold : DEFAULTS.general_threshold,
|
||||
character_threshold: unit(value.wd14_character_threshold) ? value.wd14_character_threshold : DEFAULTS.character_threshold,
|
||||
// #431: the instructions come from the saved entries (`choices`), not `default_prompt`.
|
||||
instructions: DEFAULTS.instructions,
|
||||
suggestion_limit: limit(value.suggestion_limit) ? value.suggestion_limit : DEFAULTS.suggestion_limit,
|
||||
},
|
||||
models: object(value.models) ? value.models : null,
|
||||
|
||||
@@ -150,6 +150,10 @@ export function renderModelPanel({scope, controller, heading = 'Auto-tag this im
|
||||
}
|
||||
pick.value = state.instructionsEdited ? EDITED_VALUE : state.instructionId;
|
||||
editedNote.hidden = !state.instructionsEdited;
|
||||
// The note describes the textarea while it shows.
|
||||
const area = inputs.get('instructions');
|
||||
if (state.instructionsEdited) area?.setAttribute('aria-describedby', editedNote.id);
|
||||
else area?.removeAttribute('aria-describedby');
|
||||
}
|
||||
|
||||
function renderOptions(state) {
|
||||
@@ -174,6 +178,7 @@ export function renderModelPanel({scope, controller, heading = 'Auto-tag this im
|
||||
inputs.set('instructions', area);
|
||||
rows.push(field('Tagging instructions', area, OPTION_IDS.instructions));
|
||||
editedNote = el('p', EDITED_NOTE, 'small instructions-edited');
|
||||
editedNote.id = `${pickId}-note`;
|
||||
rows.push(editedNote);
|
||||
fillPick(state);
|
||||
}
|
||||
@@ -195,7 +200,10 @@ export function renderModelPanel({scope, controller, heading = 'Auto-tag this im
|
||||
shownModel = state.model;
|
||||
shownOptions = state.optionsRevision;
|
||||
select.value = state.model;
|
||||
// A pick re-renders the fields; keyboard focus stays on the select it was made with.
|
||||
const picking = pick !== null && document.activeElement === pick;
|
||||
renderOptions(state);
|
||||
if (picking) pick?.focus();
|
||||
} else if (pick && state.instructionsEdited !== shownEdited) {
|
||||
// Typing never re-renders the fields (I1): only the select and the note follow an edit.
|
||||
fillPick(state);
|
||||
|
||||
Reference in New Issue
Block a user