From 2774262c9057150b3310e743e059360d43f178f9 Mon Sep 17 00:00:00 2001 From: hreyes Date: Wed, 15 Apr 2026 10:23:21 -0600 Subject: [PATCH] feature/tab-buscador-vistas --- .../common/infinite-data-table.svelte | 51 +++++++++++++- .../classification_concepts/data-table.svelte | 6 +- .../company/data-table.svelte | 6 +- .../concepts/data-table.svelte | 6 +- .../customs_broker_concepts/data-table.svelte | 6 +- .../doda/child-detail-table.svelte | 6 +- .../general_catalogs/doda/data-table.svelte | 9 ++- .../electronic_notices/data-table.svelte | 6 +- .../data-equivalencies-dialog.svelte | 10 +-- .../equivalencies/data-table.svelte | 6 +- .../error_catalogs/data-table.svelte | 6 +- .../identifiers/data-table.svelte | 6 +- .../general_catalogs/inpc/data-table.svelte | 6 +- .../legends/data-table.svelte | 6 +- .../prevalidators/data-table.svelte | 6 +- .../sectors/SectorsList.svelte | 10 +-- .../signatures/data-table.svelte | 6 +- .../general_catalogs/simple-data-table.svelte | 6 +- .../unit_conversions/data-table.svelte | 6 +- .../units_of_measure/ace/data-table.svelte | 6 +- .../american/data-table.svelte | 6 +- .../customs/data-table.svelte | 6 +- .../general/data-table.svelte | 6 +- .../units_of_measure/main/data-table.svelte | 6 +- .../units_of_measure/oma/data-table.svelte | 6 +- .../keyboard/KeyboardManager.svelte | 69 ++++++++++++++++++- .../lib/components/ui/table/table-row.svelte | 7 +- 27 files changed, 195 insertions(+), 87 deletions(-) diff --git a/frontend/src/lib/components/dashboard/common/infinite-data-table.svelte b/frontend/src/lib/components/dashboard/common/infinite-data-table.svelte index 5fbee4e3..09c128cd 100644 --- a/frontend/src/lib/components/dashboard/common/infinite-data-table.svelte +++ b/frontend/src/lib/components/dashboard/common/infinite-data-table.svelte @@ -33,6 +33,49 @@ let scrollContainer = $state(); let loadingTrigger = $state(); + function findRowActionTrigger(tr: HTMLTableRowElement): HTMLElement | null { + const lastTd = tr.querySelector('td:last-of-type'); + if (!lastTd) return null; + return lastTd.querySelector( + '[data-slot="dropdown-menu-trigger"], button[aria-haspopup="menu"], button[aria-haspopup="dialog"]' + ); + } + + function handleCatalogTableKeydown(event: KeyboardEvent) { + if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return; + const target = event.target as HTMLElement | null; + if (!target || !scrollContainer?.contains(target)) return; + if ( + target.tagName === 'INPUT' || + target.tagName === 'TEXTAREA' || + target.tagName === 'SELECT' || + target.isContentEditable + ) { + return; + } + const row = target.closest('tr[data-slot="table-row"]'); + if (!row || row.closest('[role="dialog"]')) return; + const lastCell = row.querySelector('td:last-of-type'); + if (!lastCell || !lastCell.contains(target)) return; + + const tbody = row.closest('tbody'); + if (!tbody || !scrollContainer.contains(tbody)) return; + const rows = Array.from( + tbody.querySelectorAll('tr[data-slot="table-row"]') + ); + const idx = rows.indexOf(row); + if (idx < 0) return; + const delta = event.key === 'ArrowDown' ? 1 : -1; + const nextIdx = idx + delta; + if (nextIdx < 0 || nextIdx >= rows.length) return; + const nextTrigger = findRowActionTrigger(rows[nextIdx]); + if (!nextTrigger) return; + event.preventDefault(); + event.stopPropagation(); + nextTrigger.focus(); + rows[nextIdx].scrollIntoView({ block: 'nearest', behavior: 'smooth' }); + } + onMount(() => { const observer = new IntersectionObserver( (entries) => { @@ -61,13 +104,14 @@
{#each table.getHeaderGroups() as headerGroup (headerGroup.id)} {@const headerList = headerGroup.headers} {@const lastHeaderColId = headerList[headerList.length - 1]?.column.id} - + {#each headerList as header (header.id)} {@const colId = header.column.id} @@ -119,7 +164,7 @@ {/each} {:else} - + {emptyMessage} @@ -127,7 +172,7 @@ {/if} {#if hasMore} - +
{#if loading} diff --git a/frontend/src/lib/components/dashboard/general_catalogs/classification_concepts/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/classification_concepts/data-table.svelte index 72fb9bf3..a0163e72 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/classification_concepts/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/classification_concepts/data-table.svelte @@ -44,7 +44,7 @@ {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} {#if !header.isPlaceholder} @@ -60,7 +60,7 @@ {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} {:else} - + No hay resultados. diff --git a/frontend/src/lib/components/dashboard/general_catalogs/company/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/company/data-table.svelte index 547154cb..8081b34b 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/company/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/company/data-table.svelte @@ -47,7 +47,7 @@ {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} {#if !header.isPlaceholder} @@ -63,7 +63,7 @@ {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} {:else} - + No hay resultados. diff --git a/frontend/src/lib/components/dashboard/general_catalogs/concepts/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/concepts/data-table.svelte index 72fb9bf3..a0163e72 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/concepts/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/concepts/data-table.svelte @@ -44,7 +44,7 @@ {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} {#if !header.isPlaceholder} @@ -60,7 +60,7 @@ {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} {:else} - + No hay resultados. diff --git a/frontend/src/lib/components/dashboard/general_catalogs/customs_broker_concepts/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/customs_broker_concepts/data-table.svelte index 72fb9bf3..a0163e72 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/customs_broker_concepts/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/customs_broker_concepts/data-table.svelte @@ -44,7 +44,7 @@ {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} {#if !header.isPlaceholder} @@ -60,7 +60,7 @@ {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} {:else} - + No hay resultados. diff --git a/frontend/src/lib/components/dashboard/general_catalogs/doda/child-detail-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/doda/child-detail-table.svelte index 0feed7a4..b660ea7f 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/doda/child-detail-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/doda/child-detail-table.svelte @@ -39,7 +39,7 @@
- + {#each columns as col} {col.header} {#if data.length === 0} - + {:else} {#each data as row, i} - + {#each columns as col} {#if col.render} diff --git a/frontend/src/lib/components/dashboard/general_catalogs/doda/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/doda/data-table.svelte index 483cc79e..6ef37688 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/doda/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/doda/data-table.svelte @@ -76,7 +76,7 @@ {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} {#if !header.isPlaceholder} @@ -92,8 +92,7 @@ {#each table.getRowModel().rows as row (row.id)} - onRowClick?.(row.original)} class="cursor-pointer {row.getIsSelected() ? 'catalog-table-row-selected' : 'catalog-table-row'}" > @@ -104,7 +103,7 @@ {/each} {:else} - + No hay resultados. @@ -112,7 +111,7 @@ {/each} {#if hasMore} - +
{#if loading} diff --git a/frontend/src/lib/components/dashboard/general_catalogs/electronic_notices/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/electronic_notices/data-table.svelte index 68b898b3..7d373fdd 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/electronic_notices/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/electronic_notices/data-table.svelte @@ -42,7 +42,7 @@ {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} {#if !header.isPlaceholder} @@ -58,7 +58,7 @@ {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} {:else} - + No hay resultados. diff --git a/frontend/src/lib/components/dashboard/general_catalogs/equivalencies/data-equivalencies-dialog.svelte b/frontend/src/lib/components/dashboard/general_catalogs/equivalencies/data-equivalencies-dialog.svelte index 8a5df911..f35ff469 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/equivalencies/data-equivalencies-dialog.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/equivalencies/data-equivalencies-dialog.svelte @@ -286,7 +286,7 @@
- + Campo Original Campo Externo @@ -294,17 +294,17 @@ {#if loading} - + Cargando... {:else if error} - + {error} {:else if items.length === 0} - + No hay items en el pool. Usa "Insertar" para crear uno. @@ -312,7 +312,7 @@ {:else} {#each items as item} {@const isSelected = item.id === selectedItemId} - {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} {#if !header.isPlaceholder} @@ -59,7 +59,7 @@ {#if table.getRowModel().rows.length} {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} {/each} {:else} - + No hay resultados. diff --git a/frontend/src/lib/components/dashboard/general_catalogs/error_catalogs/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/error_catalogs/data-table.svelte index 72fb9bf3..a0163e72 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/error_catalogs/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/error_catalogs/data-table.svelte @@ -44,7 +44,7 @@ {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} {#if !header.isPlaceholder} @@ -60,7 +60,7 @@ {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} {:else} - + No hay resultados. diff --git a/frontend/src/lib/components/dashboard/general_catalogs/identifiers/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/identifiers/data-table.svelte index 68b898b3..7d373fdd 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/identifiers/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/identifiers/data-table.svelte @@ -42,7 +42,7 @@ {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} {#if !header.isPlaceholder} @@ -58,7 +58,7 @@ {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} {:else} - + No hay resultados. diff --git a/frontend/src/lib/components/dashboard/general_catalogs/inpc/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/inpc/data-table.svelte index 21ade40a..544e0bc6 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/inpc/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/inpc/data-table.svelte @@ -43,7 +43,7 @@ {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} {#if !header.isPlaceholder} @@ -60,7 +60,7 @@ {#if table.getRowModel().rows.length} {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} {/each} {:else} - + No hay resultados. diff --git a/frontend/src/lib/components/dashboard/general_catalogs/legends/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/legends/data-table.svelte index e1efce5b..e59871cf 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/legends/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/legends/data-table.svelte @@ -45,7 +45,7 @@ {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} {#if !header.isPlaceholder} @@ -61,7 +61,7 @@ {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} {:else} - + No hay resultados. diff --git a/frontend/src/lib/components/dashboard/general_catalogs/prevalidators/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/prevalidators/data-table.svelte index 1a36d5b7..de3d1b3e 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/prevalidators/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/prevalidators/data-table.svelte @@ -42,7 +42,7 @@ {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} {#if !header.isPlaceholder} @@ -58,7 +58,7 @@ {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} {:else} - + No hay resultados. diff --git a/frontend/src/lib/components/dashboard/general_catalogs/sectors/SectorsList.svelte b/frontend/src/lib/components/dashboard/general_catalogs/sectors/SectorsList.svelte index dd8be92c..53856879 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/sectors/SectorsList.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/sectors/SectorsList.svelte @@ -131,7 +131,7 @@
- + Clave Descripción Estatus @@ -139,7 +139,7 @@ {#if loading && page === 1} - +
@@ -147,14 +147,14 @@ {:else if sectors.length === 0} - + No se encontraron sectores. {:else} {#each sectors as sector} - + {sector.key} {sector.description} @@ -168,7 +168,7 @@ {/each} {/if} {#if loading && page > 1} - +
diff --git a/frontend/src/lib/components/dashboard/general_catalogs/signatures/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/signatures/data-table.svelte index 72fb9bf3..a0163e72 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/signatures/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/signatures/data-table.svelte @@ -44,7 +44,7 @@ {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} {#if !header.isPlaceholder} @@ -60,7 +60,7 @@ {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} {:else} - + No hay resultados. diff --git a/frontend/src/lib/components/dashboard/general_catalogs/simple-data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/simple-data-table.svelte index 2ebc136d..e4dba611 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/simple-data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/simple-data-table.svelte @@ -42,7 +42,7 @@
- + {#each columns as column (column.key)} {column.label} {/each} @@ -50,7 +50,7 @@ {#each data as row, i (i)} - + {#each columns as column (column.key)} {getCellValue(row, column)} @@ -58,7 +58,7 @@ {/each} {:else} - + No hay resultados. diff --git a/frontend/src/lib/components/dashboard/general_catalogs/unit_conversions/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/unit_conversions/data-table.svelte index 72fb9bf3..a0163e72 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/unit_conversions/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/unit_conversions/data-table.svelte @@ -44,7 +44,7 @@ {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} {#if !header.isPlaceholder} @@ -60,7 +60,7 @@ {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} {:else} - + No hay resultados. diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/ace/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/ace/data-table.svelte index 72fb9bf3..a0163e72 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/ace/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/ace/data-table.svelte @@ -44,7 +44,7 @@ {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} {#if !header.isPlaceholder} @@ -60,7 +60,7 @@ {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} {:else} - + No hay resultados. diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/american/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/american/data-table.svelte index 72fb9bf3..a0163e72 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/american/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/american/data-table.svelte @@ -44,7 +44,7 @@ {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} {#if !header.isPlaceholder} @@ -60,7 +60,7 @@ {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} {:else} - + No hay resultados. diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/customs/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/customs/data-table.svelte index 72fb9bf3..a0163e72 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/customs/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/customs/data-table.svelte @@ -44,7 +44,7 @@ {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} {#if !header.isPlaceholder} @@ -60,7 +60,7 @@ {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} {:else} - + No hay resultados. diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/general/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/general/data-table.svelte index 77c412d8..aff65917 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/general/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/general/data-table.svelte @@ -44,7 +44,7 @@ {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} {#if !header.isPlaceholder} @@ -60,7 +60,7 @@ {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} {:else} - + No hay resultados. diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/main/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/main/data-table.svelte index 77c412d8..aff65917 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/main/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/main/data-table.svelte @@ -44,7 +44,7 @@ {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} {#if !header.isPlaceholder} @@ -60,7 +60,7 @@ {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} {:else} - + No hay resultados. diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/oma/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/oma/data-table.svelte index 72fb9bf3..a0163e72 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/oma/data-table.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/oma/data-table.svelte @@ -44,7 +44,7 @@ {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - + {#each headerGroup.headers as header (header.id)} {#if !header.isPlaceholder} @@ -60,7 +60,7 @@ {#each table.getRowModel().rows as row (row.id)} - + {#each row.getVisibleCells() as cell (cell.id)} {:else} - + No hay resultados. diff --git a/frontend/src/lib/components/keyboard/KeyboardManager.svelte b/frontend/src/lib/components/keyboard/KeyboardManager.svelte index 5b52ec2b..19fc8a30 100644 --- a/frontend/src/lib/components/keyboard/KeyboardManager.svelte +++ b/frontend/src/lib/components/keyboard/KeyboardManager.svelte @@ -39,6 +39,69 @@ return !!(htmlEl.offsetWidth || htmlEl.offsetHeight || htmlEl.getClientRects().length); } + function inputIsSearchCandidate(el: HTMLInputElement): boolean { + const t = (el.type || 'text').toLowerCase(); + return !['hidden', 'checkbox', 'radio', 'file', 'button', 'submit', 'reset'].includes(t); + } + + /** + * Alt+B: focus the current view's primary filter/search when possible. + * Order: [data-view-search] → placeholder hints (buscar/search/…) → + * first visible text-like input before the main table / catalog scroll → global sr-only fallback. + */ + function focusViewSearchOrGlobal() { + const main = + document.getElementById('dashboard-main-content') || + document.getElementById('main-form-content'); + + const tryFocus = (el: HTMLElement | null | undefined): boolean => { + if (!el || !isVisibleInMainContent(el)) return false; + if (el.closest('[role="dialog"]')) return false; + try { + el.focus(); + } catch { + return false; + } + setTimeout(() => { + el.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center' }); + }, 50); + return true; + }; + + if (main) { + const explicit = main.querySelector('[data-view-search]:not([disabled])'); + if (tryFocus(explicit)) return; + + const phPattern = /buscar|search|filtrar|filter|búsqueda|busqueda/i; + const inputs = Array.from( + main.querySelectorAll('input:not([disabled])') + ).filter(inputIsSearchCandidate); + + for (const input of inputs) { + if (!isVisibleInMainContent(input)) continue; + if (input.closest('[role="dialog"]')) continue; + if (phPattern.test(input.placeholder || '')) { + if (tryFocus(input)) return; + } + } + + const boundary = main.querySelector( + 'table, tbody, .catalog-table-scroll, [data-slot="table-container"]' + ); + if (boundary) { + for (const input of inputs) { + if (!isVisibleInMainContent(input)) continue; + if (input.closest('[role="dialog"]')) continue; + if (input.compareDocumentPosition(boundary) & Node.DOCUMENT_POSITION_FOLLOWING) { + if (tryFocus(input)) return; + } + } + } + } + + document.getElementById('global-search-input')?.focus(); + } + /** First meaningful control in main area (forms); optional delay for post-navigation paint. */ function focusMainContentPrimary(options?: { delay?: number }) { const delay = options?.delay ?? 350; @@ -295,11 +358,11 @@ // Solo permitir si está autenticado if (authenticated && altKey && modifiers.length === 1) { // Exactly Alt + Key (no shift/ctrl) - // Special: Alt+B -> Focus Search + // Special: Alt+B -> Focus view search / filters or global fallback if (lowerKey === 'b') { event.preventDefault(); - const searchInput = document.getElementById('global-search-input'); - searchInput?.focus(); + lastShortcutTime = Date.now(); + focusViewSearchOrGlobal(); return; } diff --git a/frontend/src/lib/components/ui/table/table-row.svelte b/frontend/src/lib/components/ui/table/table-row.svelte index 91039ad8..44346c4e 100644 --- a/frontend/src/lib/components/ui/table/table-row.svelte +++ b/frontend/src/lib/components/ui/table/table-row.svelte @@ -6,20 +6,21 @@ ref = $bindable(null), class: className, children, + inTabOrder = true, ...restProps - }: WithElementRef> = $props(); + }: WithElementRef> & { inTabOrder?: boolean } = $props(); svelte-css-wrapper]:[&>th,td]:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors", "focus-visible:bg-accent focus-visible:text-accent-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", className )} - {...restProps} > {@render children?.()}