import { ChangeDetectionStrategy, Component, booleanAttribute, inject, input, output } from '@angular/core'; import { FieldNames } from '../../core/field-names'; let nextId = 0; /** * Fila de formulario SBO: etiqueta a la izquierda y, a la derecha, uno o varios * controles en una misma línea (input + botón, select + botón, serie + número...). * `action` pinta la flecha dorada de SAP (campo que enlaza a otro objeto o a una lista). * * El primer control de la fila toma el `id` al que apunta la etiqueta (ver `claimId`). */ @Component({ selector: 'sbo-field', changeDetection: ChangeDetectionStrategy.OnPush, template: `
@if (error()) { {{ error() }} }
`, styles: ` :host { display: block; } .f { display: grid; grid-template-columns: var(--label-w, 165px) minmax(0, 1fr); align-items: start; gap: 8px; min-height: 24px; } label { padding-top: 3px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } label.req .t::after { content: ' *'; color: var(--err); } label.ga { position: relative; padding-left: 14px; } label.ga::before { content: ''; position: absolute; left: 0; top: 50%; transform: translateY(-50%); border-left: 8px solid var(--gold); border-top: 5px solid transparent; border-bottom: 5px solid transparent; } .db { display: block; margin-top: -2px; font: 10.5px/1.2 var(--mono, monospace); color: var(--quiet); white-space: normal; overflow-wrap: anywhere; } label.link { cursor: pointer; } label.link:hover { text-decoration: underline; } .ctl { min-width: 0; } .err { display: block; margin-top: 1px; font-size: 11.5px; color: var(--err); } `, }) export class SboField { protected readonly names = inject(FieldNames); readonly label = input.required(); /** Nombre del campo de SAP; sale como ayuda del cursor y, con «Ver campos», debajo de la etiqueta. */ readonly dbName = input(); readonly required = input(false, { transform: booleanAttribute }); readonly action = input(false, { transform: booleanAttribute }); /** La etiqueta es un enlace (ej. abrir el socio de negocio). */ readonly linkable = input(false, { transform: booleanAttribute }); readonly error = input(); readonly labelClick = output(); readonly controlId = `sbo-f-${++nextId}`; readonly errorId = `${this.controlId}-err`; private claimed = false; /** El primer control de la fila recibe el id de la etiqueta; los demás deben llevar su `ariaLabel`. */ claimId(): string | null { if (this.claimed) return null; this.claimed = true; return this.controlId; } }