feat(web): grilla de líneas editable y página de componentes de desarrollo

- sbo-lines-grid: columnas declarativas (texto / número con decimales /
  solo lectura / calculadas), celdas con lista de valores (botón "..." y
  F4) cuyo apply rellena la línea, añadir y quitar línea, y "Elegir
  artículos..." para agregar varias líneas a la vez.
- Teclado: Enter confirma y baja a la misma columna (crea línea en la
  última fila), flechas arriba/abajo cambian de fila. Las celdas se
  confirman al salir de ellas; un número inválido conserva el anterior.
- Documento cerrado: grilla de solo lectura, sin botones ni listas.
- Columnas estándar de línea de SAP (artículo, descripción, cantidad,
  almacén, precio, % dto., impuesto, total) con TaxCode / SalesTaxCodes,
  verificado en el Service Layer real; recalcLine (cantidad x precio x
  (1 - dto)).
- Corrige el foco al crear una línea con Enter: se pedía antes de que la
  fila existiera en el DOM (ahora espera al render).
- /dev/componentes: página de componentes solo para desarrollo
  (canMatch isDevMode), sin entrada en el menú y sin escribir en SAP.
- Verificado en Chrome contra SAP real: artículo elegido de la lista,
  5 x 10,000 con 10 % = 45,000.00, Enter/flechas, varios artículos a la
  vez, quitar línea y subtotal del pie.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
GeorgeandClaude Sonnet 5.5 committed 2026-10-13 20:17:52 -05:00
1 parent 26f0649da9
commit 0a7bfb850a
11 files changed
+1150

No files matched your search

+138
View File
@@ -0,0 +1,138 @@
:host {
display: block;
}
.bar {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 6px;
}
.count {
font-size: 12px;
color: var(--quiet);
}
.sp {
flex: 1;
}
.gridwrap {
overflow-x: auto;
border: 1px solid var(--line);
border-radius: var(--radius-panel);
background: var(--panel);
}
.grid {
width: 100%;
min-width: 900px;
border-collapse: collapse;
}
th {
padding: 4px 6px;
background: var(--grid-head);
border-right: 1px solid var(--line);
border-bottom: 1px solid var(--line);
font-size: 12.5px;
font-weight: 600;
text-align: left;
white-space: nowrap;
}
th.num {
text-align: right;
}
th.req::after {
content: ' *';
color: var(--err);
}
td {
height: 27px;
padding: 0 2px;
border-right: 1px solid var(--line-soft);
border-bottom: 1px solid var(--line-soft);
white-space: nowrap;
}
tbody tr:nth-child(even) td {
background: var(--row-alt);
}
tbody tr:focus-within td {
background: var(--row-sel);
}
td.rn,
th.rn {
width: 34px;
text-align: center;
color: var(--quiet);
background: var(--grid-head);
}
tbody tr td.rn {
background: var(--grid-head);
}
td.ro {
background: var(--field-ro);
}
.cell {
width: 100%;
height: 22px;
padding: 1px 4px;
background: transparent;
border: 1px solid transparent;
border-radius: var(--radius);
}
.cell.num {
text-align: right;
}
.cell.mono {
font-family: ui-monospace, Menlo, Consolas, monospace;
}
.cell:hover:not([readonly]) {
border-color: var(--field-b);
}
.cell:focus {
background: var(--field);
border-color: var(--focus);
outline: none;
}
.cell[readonly] {
cursor: default;
}
.pick {
display: grid;
grid-template-columns: minmax(0, 1fr) 22px;
}
.pick button {
padding: 0;
background: var(--btn);
border: 1px solid var(--field-b);
border-radius: var(--radius);
cursor: pointer;
}
.pick button:hover {
background: var(--btn-h);
}
td.del,
th.del {
width: 30px;
text-align: center;
}
td.del button {
padding: 2px 6px;
background: none;
border: none;
color: var(--quiet);
font-size: 15px;
line-height: 1;
cursor: pointer;
border-radius: var(--radius);
}
td.del button:hover {
color: var(--err);
background: var(--err-bg);
}
tr.none td {
padding: 18px;
text-align: center;
color: var(--quiet);
background: transparent;
}
.sr {
position: absolute;
left: -9999px;
}