From 07f5553fd9a3d40af8a53927039fa56ce2ad8427 Mon Sep 17 00:00:00 2001 From: hreyes Date: Wed, 15 Apr 2026 09:56:15 -0600 Subject: [PATCH] feature/correccion-tabs-funciones-nuevas-nav --- docs/keyboard_shortcuts_alt_digit_matrix.md | 24 + .../modals/broker-selector-dialog.svelte | 9 + .../modals/driver-selector-dialog.svelte | 9 + .../modals/port-selector-dialog.svelte | 9 + .../modals/trailer-selector-dialog.svelte | 9 + .../transport-mode-selector-dialog.svelte | 9 + .../transport-type-selector-dialog.svelte | 9 + .../modals/transporter-selector-dialog.svelte | 9 + .../modals/vehicle-selector-dialog.svelte | 9 + .../dashboard/goods/parts/partForm.svelte | 58 ++ .../edit/items/fa/country-dialog.svelte | 30 +- .../edit/items/fa/item-sheet-fa.svelte | 55 ++ .../items/fa/location-selector-dialog.svelte | 9 + .../edit/items/fa/package-dialog.svelte | 9 + .../items/fa/payment-method-dialog.svelte | 9 + .../edit/items/fa/state-dialog.svelte | 9 + .../items/fa/unit-of-measure-dialog.svelte | 9 + .../edit/items/inv/item-sheet-inv.svelte | 22 + .../customs-section-selector-dialog.svelte | 9 + .../keyboard/KeyboardManager.svelte | 898 ++++++++++-------- .../keyboard/ShortcutsHelpModal.svelte | 10 +- .../lib/components/sidebar/app-sidebar.svelte | 15 +- .../lib/components/sidebar/nav-main.svelte | 2 +- frontend/src/lib/config/shortcuts.ts | 2 + .../general_catalogs/common/factory.ts | 9 +- .../company_information/edit.ts | 2 +- .../dashboard/general_catalogs/doda/edit.ts | 9 +- .../customs_brokers/edit/[[id]]/+page.svelte | 69 +- .../doda/edit/[[id]]/+page.svelte | 22 + .../routes/dashboard/invoices/+page.svelte | 58 +- 30 files changed, 914 insertions(+), 497 deletions(-) create mode 100644 docs/keyboard_shortcuts_alt_digit_matrix.md diff --git a/docs/keyboard_shortcuts_alt_digit_matrix.md b/docs/keyboard_shortcuts_alt_digit_matrix.md new file mode 100644 index 00000000..a52ceb0b --- /dev/null +++ b/docs/keyboard_shortcuts_alt_digit_matrix.md @@ -0,0 +1,24 @@ +# Alt+Numero Keyboard Navigation Matrix + +This matrix documents the active `Alt+DigitN` shortcuts used for fast tab/view navigation in dashboard flows. + +## Active contexts + +| Context | Shortcut Source | Alt+Digit targets | Focus strategy | +| --- | --- | --- | --- | +| `Edit Broker Tabs` | `frontend/src/lib/config/shortcuts/dashboard/customs_brokers/edit.ts` | `general`, `contact`, `address`, `vu`, `doda`, `anam` | `first-input` | +| `Edit Client Provider` | `frontend/src/lib/config/shortcuts/dashboard/clients_and_providers/edit.ts` | `general`, `address`, `programs`, `config` | `first-input` | +| `Formulario Empresa` | `frontend/src/lib/config/shortcuts/dashboard/general_catalogs/company_information/edit.ts` | `general`, `programa`, `responsable`, `certificaciones`, `direcciones`, `config`, `certificados` | `first-input` | +| `Formulario DODA` | `frontend/src/lib/config/shortcuts/dashboard/general_catalogs/doda/edit.ts` | `general`, `transport`, `sat`, `other` | `first-input` | +| `Invoice Edit` | `frontend/src/lib/config/shortcuts/dashboard/invoices/edit.ts` | `general`, `observations`, `items`, `others`, `continuation` | `first-input` | +| `Invoice Item Form (Inventory)` | `frontend/src/lib/config/shortcuts/dashboard/invoices/item/inventory.ts` | `tab1..tab4` mapped to `general`, `clasificacion`, `cantidades`, `otros` | `first-input` | +| `Invoice Item Form (Fixed Asset)` | `frontend/src/lib/config/shortcuts/dashboard/invoices/item/fixed_asset.ts` | `tab1..tab5` mapped to `generales`, `continuacion`, `series`, `etiquetado`, `identificadores` | `first-input` | +| `Part Form` | `frontend/src/lib/config/shortcuts/dashboard/goods/edit.ts` | `general`, `cont1`, `cont2` | `first-input` | +| `Customs Brokers List` | `frontend/src/lib/config/shortcuts/dashboard/customs_brokers/list.ts` | `brokers`, `customs` | `trigger` | +| `Clients Providers List` | `frontend/src/lib/config/shortcuts/dashboard/clients_and_providers/list.ts` | `all`, `clients`, `providers` | `trigger` | + +## Notes + +- `KeyboardManager` now has explicit focus policy entries for all contexts listed above. +- `fixed_asset` shortcuts remain in place and are now connected in `item-sheet-fa`. +- No shortcut set was removed in this pass; changes are additive/corrective for keyboard-only navigation. diff --git a/frontend/src/lib/components/dashboard/export/manifest/modals/broker-selector-dialog.svelte b/frontend/src/lib/components/dashboard/export/manifest/modals/broker-selector-dialog.svelte index afaf62e5..9edf85d7 100644 --- a/frontend/src/lib/components/dashboard/export/manifest/modals/broker-selector-dialog.svelte +++ b/frontend/src/lib/components/dashboard/export/manifest/modals/broker-selector-dialog.svelte @@ -61,6 +61,13 @@ if (onSelect) onSelect(item); open = false; } + + function handleRowKeydown(event: KeyboardEvent, item: CustomsBroker) { + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + handleSelect(item); + } + } @@ -103,7 +110,9 @@ {#each filteredItems as item} handleSelect(item)} + onkeydown={(event) => handleRowKeydown(event, item)} > {item.license} diff --git a/frontend/src/lib/components/dashboard/export/manifest/modals/driver-selector-dialog.svelte b/frontend/src/lib/components/dashboard/export/manifest/modals/driver-selector-dialog.svelte index bcc2b305..0b22d751 100644 --- a/frontend/src/lib/components/dashboard/export/manifest/modals/driver-selector-dialog.svelte +++ b/frontend/src/lib/components/dashboard/export/manifest/modals/driver-selector-dialog.svelte @@ -54,6 +54,13 @@ if (onSelect) onSelect(item); open = false; } + + function handleRowKeydown(event: KeyboardEvent, item: Driver) { + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + handleSelect(item); + } + } @@ -95,7 +102,9 @@ {#each filteredItems as item} handleSelect(item)} + onkeydown={(event) => handleRowKeydown(event, item)} > {item.license_number || '-'} diff --git a/frontend/src/lib/components/dashboard/export/manifest/modals/port-selector-dialog.svelte b/frontend/src/lib/components/dashboard/export/manifest/modals/port-selector-dialog.svelte index 7867bcb1..f91bbdbb 100644 --- a/frontend/src/lib/components/dashboard/export/manifest/modals/port-selector-dialog.svelte +++ b/frontend/src/lib/components/dashboard/export/manifest/modals/port-selector-dialog.svelte @@ -67,6 +67,13 @@ if (onSelect) onSelect(item); open = false; } + + function handleRowKeydown(event: KeyboardEvent, item: Port) { + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + handleSelect(item); + } + } @@ -109,7 +116,9 @@ {#each filteredItems as item} handleSelect(item)} + onkeydown={(event) => handleRowKeydown(event, item)} > {item.port_code} diff --git a/frontend/src/lib/components/dashboard/export/manifest/modals/trailer-selector-dialog.svelte b/frontend/src/lib/components/dashboard/export/manifest/modals/trailer-selector-dialog.svelte index 5d8d59d5..ec2ec674 100644 --- a/frontend/src/lib/components/dashboard/export/manifest/modals/trailer-selector-dialog.svelte +++ b/frontend/src/lib/components/dashboard/export/manifest/modals/trailer-selector-dialog.svelte @@ -54,6 +54,13 @@ if (onSelect) onSelect(item); open = false; } + + function handleRowKeydown(event: KeyboardEvent, item: Trailer) { + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + handleSelect(item); + } + } @@ -96,7 +103,9 @@ {#each filteredItems as item} handleSelect(item)} + onkeydown={(event) => handleRowKeydown(event, item)} > {item.trailer_number} {item.plate_number || '-'} diff --git a/frontend/src/lib/components/dashboard/export/manifest/modals/transport-mode-selector-dialog.svelte b/frontend/src/lib/components/dashboard/export/manifest/modals/transport-mode-selector-dialog.svelte index db7c10e2..59ab5870 100644 --- a/frontend/src/lib/components/dashboard/export/manifest/modals/transport-mode-selector-dialog.svelte +++ b/frontend/src/lib/components/dashboard/export/manifest/modals/transport-mode-selector-dialog.svelte @@ -54,6 +54,13 @@ if (onSelect) onSelect(item); open = false; } + + function handleRowKeydown(event: KeyboardEvent, item: TransportMode) { + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + handleSelect(item); + } + } @@ -97,7 +104,9 @@ {#each filteredItems as item} handleSelect(item)} + onkeydown={(event) => handleRowKeydown(event, item)} > {item.key} {item.name} diff --git a/frontend/src/lib/components/dashboard/export/manifest/modals/transport-type-selector-dialog.svelte b/frontend/src/lib/components/dashboard/export/manifest/modals/transport-type-selector-dialog.svelte index d98b5db3..0c02911d 100644 --- a/frontend/src/lib/components/dashboard/export/manifest/modals/transport-type-selector-dialog.svelte +++ b/frontend/src/lib/components/dashboard/export/manifest/modals/transport-type-selector-dialog.svelte @@ -54,6 +54,13 @@ if (onSelect) onSelect(item); open = false; } + + function handleRowKeydown(event: KeyboardEvent, item: TransportType) { + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + handleSelect(item); + } + } @@ -95,7 +102,9 @@ {#each filteredItems as item} handleSelect(item)} + onkeydown={(event) => handleRowKeydown(event, item)} > {item.transport_code} diff --git a/frontend/src/lib/components/dashboard/export/manifest/modals/transporter-selector-dialog.svelte b/frontend/src/lib/components/dashboard/export/manifest/modals/transporter-selector-dialog.svelte index 49704472..fea1a070 100644 --- a/frontend/src/lib/components/dashboard/export/manifest/modals/transporter-selector-dialog.svelte +++ b/frontend/src/lib/components/dashboard/export/manifest/modals/transporter-selector-dialog.svelte @@ -73,6 +73,13 @@ if (onSelect) onSelect(item); open = false; } + + function handleRowKeydown(event: KeyboardEvent, item: Transporter) { + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + handleSelect(item); + } + } @@ -115,7 +122,9 @@ {#each filteredItems as item} handleSelect(item)} + onkeydown={(event) => handleRowKeydown(event, item)} > {item.transporter_key} {item.rfc || '-'} diff --git a/frontend/src/lib/components/dashboard/export/manifest/modals/vehicle-selector-dialog.svelte b/frontend/src/lib/components/dashboard/export/manifest/modals/vehicle-selector-dialog.svelte index bf3025d5..5cc15c91 100644 --- a/frontend/src/lib/components/dashboard/export/manifest/modals/vehicle-selector-dialog.svelte +++ b/frontend/src/lib/components/dashboard/export/manifest/modals/vehicle-selector-dialog.svelte @@ -55,6 +55,13 @@ if (onSelect) onSelect(item); open = false; } + + function handleRowKeydown(event: KeyboardEvent, item: Vehicle) { + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + handleSelect(item); + } + } @@ -97,7 +104,9 @@ {#each filteredItems as item} handleSelect(item)} + onkeydown={(event) => handleRowKeydown(event, item)} > {item.vehicle_key} {item.plate_number || '-'} diff --git a/frontend/src/lib/components/dashboard/goods/parts/partForm.svelte b/frontend/src/lib/components/dashboard/goods/parts/partForm.svelte index 8bf4baff..76b214ba 100644 --- a/frontend/src/lib/components/dashboard/goods/parts/partForm.svelte +++ b/frontend/src/lib/components/dashboard/goods/parts/partForm.svelte @@ -157,6 +157,13 @@ el.dispatchEvent(new Event('input', { bubbles: true })); } + function openOnEnterOrSpace(event: KeyboardEvent, action: () => void) { + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + action(); + } + } + // Estado Modales let showClientModal = $state(false); let showClassModal = $state(false); @@ -1201,6 +1208,9 @@ bind:value={selectedClientName} readonly onclick={() => (showClientModal = true)} + onkeydown={(event) => + openOnEnterOrSpace(event, () => (showClientModal = true))} + tabindex="0" class="cursor-pointer pl-9 transition-colors hover:bg-muted/50" placeholder="Seleccione un cliente..." /> @@ -1254,6 +1264,9 @@ bind:value={formData.part_class} readonly onclick={() => (showClassModal = true)} + onkeydown={(event) => + openOnEnterOrSpace(event, () => (showClassModal = true))} + tabindex="0" class="cursor-pointer font-mono" placeholder="Seleccione..." /> @@ -1282,6 +1295,9 @@ bind:value={formData.unit_of_measure} readonly onclick={() => (showUOMModal = true)} + onkeydown={(event) => + openOnEnterOrSpace(event, () => (showUOMModal = true))} + tabindex="0" class="cursor-pointer pl-9 font-mono" placeholder="Seleccione..." /> @@ -1308,6 +1324,9 @@ bind:value={selectedCountryName} readonly onclick={() => (showCountryModal = true)} + onkeydown={(event) => + openOnEnterOrSpace(event, () => (showCountryModal = true))} + tabindex="0" class="cursor-pointer pl-9" placeholder="Seleccione..." /> @@ -1423,6 +1442,9 @@ bind:value={formData.fraction} readonly onclick={() => (showFractionModal = true)} + onkeydown={(event) => + openOnEnterOrSpace(event, () => (showFractionModal = true))} + tabindex="0" class="cursor-pointer font-mono" placeholder="Seleccione..." /> @@ -1446,6 +1468,9 @@ placeholder="HTS Code" readonly onclick={() => (showUSFractionModal = true)} + onkeydown={(event) => + openOnEnterOrSpace(event, () => (showUSFractionModal = true))} + tabindex="0" /> - - - - +
+ Usa flechas para navegar filas y Enter/Espacio para seleccionar.
{/if}
- +
diff --git a/frontend/src/lib/components/dashboard/invoices/edit/items/fa/item-sheet-fa.svelte b/frontend/src/lib/components/dashboard/invoices/edit/items/fa/item-sheet-fa.svelte index 6afc5f7a..f536d294 100644 --- a/frontend/src/lib/components/dashboard/invoices/edit/items/fa/item-sheet-fa.svelte +++ b/frontend/src/lib/components/dashboard/invoices/edit/items/fa/item-sheet-fa.svelte @@ -13,6 +13,8 @@ import { invoicesApi } from '$lib/api/dashboard/a76/invoices'; import { itemsApi, type Item, type ImportLineWithBalance } from '$lib/api/dashboard/a76/items'; import { companyStore } from '$lib/stores/company.svelte'; + import { useShortcuts } from '$lib/hooks/use-shortcuts'; + import { obtenerAtajosPestanasItemFa } from '$lib/config/shortcuts/dashboard/invoices/item/fixed_asset'; // Child components import InvoiceSelectorModal from '../../InvoiceSelectorModal.svelte'; @@ -229,12 +231,41 @@ ].filter((tab) => tab.visible)); const tabListStyle = $derived(`grid-template-columns: repeat(${visibleTabs.length || 1}, minmax(0, 1fr));`); let activeTab = $state('generales'); + const tabMapping: Record = { + tab1: 'generales', + tab2: 'continuacion', + tab3: 'series', + tab4: 'etiquetado', + tab5: 'identificadores' + }; + + function openOnEnterOrSpace(event: KeyboardEvent, action: () => void) { + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + action(); + } + } $effect(() => { if (!visibleTabs.some((tab) => tab.value === activeTab)) { activeTab = visibleTabs[0]?.value || 'generales'; } }); + + useShortcuts( + 'Invoice Item Form (Fixed Asset)', + obtenerAtajosPestanasItemFa({ + cambiarPestana: (target) => { + const mappedTab = tabMapping[target]; + if (!mappedTab) return; + if (visibleTabs.some((tab) => tab.value === mappedTab)) { + activeTab = mappedTab; + } + }, + manejarGuardar: onSave, + manejarCancelar: () => onCancel?.() + }) + ); @@ -299,6 +330,9 @@ class="h-8 flex-1 bg-muted cursor-pointer text-sm" placeholder="Seleccionar factura..." onclick={() => (showExportInvoiceModal = true)} + tabindex="0" + onkeydown={(event) => + openOnEnterOrSpace(event, () => (showExportInvoiceModal = true))} /> - + +
+ + +
- + diff --git a/frontend/src/routes/dashboard/general_catalogs/doda/edit/[[id]]/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/doda/edit/[[id]]/+page.svelte index db7208ec..3b0d13bc 100644 --- a/frontend/src/routes/dashboard/general_catalogs/doda/edit/[[id]]/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/doda/edit/[[id]]/+page.svelte @@ -248,6 +248,13 @@ function handleTransporterSelect(transporter: any) { formData.carrier = transporter.name || ''; } + + function openOnEnterOrSpace(event: KeyboardEvent, action: () => void) { + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + action(); + } + }
@@ -289,6 +296,9 @@ maxlength={14} placeholder="Clave" onclick={() => (showBrokerSelector = true)} + onkeydown={(event) => + openOnEnterOrSpace(event, () => (showBrokerSelector = true))} + tabindex="0" readonly />