fix(ext/popup): fix reversed search, remove auto-focus, Enter opens items
- Search no longer auto-focuses; use "/" to focus it - Typing in search no longer re-renders the entire view, just the item list — fixes backwards text caused by cursor reset to pos 0 - Arrow keys also update list without full re-render - Enter opens the selected item even when search is focused Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -25,11 +25,10 @@ function typeIcon(t: ItemType): string {
|
||||
}
|
||||
}
|
||||
|
||||
export function renderItemList(app: HTMLElement): void {
|
||||
function buildRowsHtml(): string {
|
||||
const state = getState();
|
||||
const filtered = getFilteredEntries();
|
||||
|
||||
const rowsHtml = filtered.length > 0
|
||||
return filtered.length > 0
|
||||
? filtered.map(([id, e], i) => `
|
||||
<div class="entry-row ${i === state.selectedIndex ? 'selected' : ''}" data-id="${escapeHtml(id)}" data-index="${i}">
|
||||
<span class="entry-name"><span class="type-icon" aria-hidden="true">${typeIcon(e.type)}</span> ${escapeHtml(e.title)}${e.attachment_summaries.length > 0 ? ' <span class="entry-row__attach-indicator" title="has attachments">📎</span>' : ''}</span>
|
||||
@@ -37,7 +36,28 @@ export function renderItemList(app: HTMLElement): void {
|
||||
</div>
|
||||
`).join('')
|
||||
: '<div class="empty">no items</div>';
|
||||
}
|
||||
|
||||
function updateItemList(): void {
|
||||
const list = document.getElementById('item-list');
|
||||
if (list) {
|
||||
list.innerHTML = buildRowsHtml();
|
||||
wireRowClicks();
|
||||
}
|
||||
}
|
||||
|
||||
function wireRowClicks(): void {
|
||||
document.querySelectorAll('.entry-row').forEach(row => {
|
||||
row.addEventListener('click', async () => {
|
||||
const id = (row as HTMLElement).dataset.id!;
|
||||
document.removeEventListener('keydown', handleListKeydown);
|
||||
await openItem(id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function renderItemList(app: HTMLElement): void {
|
||||
const state = getState();
|
||||
app.innerHTML = `
|
||||
<div class="search-bar">
|
||||
<input type="text" id="search-input" placeholder="/ search..." value="${escapeHtml(state.searchQuery)}">
|
||||
@@ -50,7 +70,7 @@ export function renderItemList(app: HTMLElement): void {
|
||||
<button class="btn" id="lock-btn" style="font-size:11px;">lock</button>
|
||||
</div>
|
||||
<div class="entry-list" id="item-list">
|
||||
${rowsHtml}
|
||||
${buildRowsHtml()}
|
||||
</div>
|
||||
<div class="keyhints">
|
||||
<span><kbd>/</kbd> search</span>
|
||||
@@ -64,7 +84,12 @@ export function renderItemList(app: HTMLElement): void {
|
||||
|
||||
const searchInput = document.getElementById('search-input') as HTMLInputElement | null;
|
||||
searchInput?.addEventListener('input', () => {
|
||||
setState({ searchQuery: searchInput.value, selectedIndex: 0 });
|
||||
const state2 = getState();
|
||||
state2.searchQuery = searchInput.value;
|
||||
state2.selectedIndex = 0;
|
||||
const list = document.getElementById('item-list');
|
||||
if (list) list.innerHTML = buildRowsHtml();
|
||||
wireRowClicks();
|
||||
});
|
||||
|
||||
document.getElementById('new-btn')?.addEventListener('click', () => {
|
||||
@@ -98,21 +123,9 @@ export function renderItemList(app: HTMLElement): void {
|
||||
showSettingsPicker(e.currentTarget as HTMLElement);
|
||||
});
|
||||
|
||||
// Item row clicks.
|
||||
const rows = app.querySelectorAll('.entry-row');
|
||||
rows.forEach(row => {
|
||||
row.addEventListener('click', async () => {
|
||||
const id = (row as HTMLElement).dataset.id!;
|
||||
document.removeEventListener('keydown', handleListKeydown);
|
||||
await openItem(id);
|
||||
});
|
||||
});
|
||||
wireRowClicks();
|
||||
|
||||
// Keyboard navigation.
|
||||
document.addEventListener('keydown', handleListKeydown);
|
||||
|
||||
// Focus search on open.
|
||||
searchInput?.focus();
|
||||
}
|
||||
|
||||
async function openItem(id: ItemId): Promise<void> {
|
||||
@@ -195,17 +208,19 @@ function handleListKeydown(e: KeyboardEvent): void {
|
||||
if (e.key === 'ArrowDown') {
|
||||
e.preventDefault();
|
||||
const max = Math.max(filtered.length - 1, 0);
|
||||
setState({ selectedIndex: Math.min(state.selectedIndex + 1, max) });
|
||||
state.selectedIndex = Math.min(state.selectedIndex + 1, max);
|
||||
updateItemList();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.key === 'ArrowUp') {
|
||||
e.preventDefault();
|
||||
setState({ selectedIndex: Math.max(state.selectedIndex - 1, 0) });
|
||||
state.selectedIndex = Math.max(state.selectedIndex - 1, 0);
|
||||
updateItemList();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.key === 'Enter' && !isSearch) {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
const selected = filtered[state.selectedIndex];
|
||||
if (selected) {
|
||||
|
||||
Reference in New Issue
Block a user