@kaufmann-lab/ui 0.1.20 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/kaufmann-lab-ui-business.mjs +257 -17
- package/fesm2022/kaufmann-lab-ui-business.mjs.map +1 -1
- package/fesm2022/kaufmann-lab-ui-core.mjs +1408 -99
- package/fesm2022/kaufmann-lab-ui-core.mjs.map +1 -1
- package/fesm2022/kaufmann-lab-ui-map.mjs +1 -1
- package/fesm2022/kaufmann-lab-ui-map.mjs.map +1 -1
- package/package.json +1 -1
- package/types/kaufmann-lab-ui-business.d.ts +150 -13
- package/types/kaufmann-lab-ui-core.d.ts +859 -52
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kaufmann-lab-ui-business.mjs","sources":["../../../projects/ui/business/src/lib/company-selector/CompanySelector.ts","../../../projects/ui/business/src/lib/company-selector/CompanySelector.html","../../../projects/ui/business/src/lib/quote-picker/QuotePicker.ts","../../../projects/ui/business/src/lib/quote-picker/QuotePicker.html","../../../projects/ui/business/src/lib/reserve-block/ReserveBlock.ts","../../../projects/ui/business/src/lib/reserve-block/ReserveBlock.html","../../../projects/ui/business/src/lib/vehicle-header/VehicleHeader.ts","../../../projects/ui/business/src/lib/vehicle-header/VehicleHeader.html","../../../projects/ui/business/src/public-api.ts","../../../projects/ui/business/src/kaufmann-lab-ui-business.ts"],"sourcesContent":["import { Component, input, output } from '@angular/core';\nimport { Divider, Select, Text } from '@kaufmann-lab/ui/core';\n\n/** Metadato clave mostrado junto al selector (RUC, identificación, sucursal). */\nexport interface CompanySelectorMeta {\n label: string;\n value: string;\n}\n\n/**\n * Empresa elegible. `value` es el identificador único (ej. número de\n * cuenta) — dos empresas con el mismo `label` se seleccionan por separado.\n * `tag` se muestra como badge junto al nombre (ej. 'Personal' | 'Empresa')\n * y `detail` como línea secundaria en el panel (ej. 'RUC 20434860808').\n */\nexport interface CompanySelectorOption {\n value: string;\n label: string;\n tag?: string;\n detail?: string;\n}\n\n/**\n * Conmutador de empresa activa con metadatos clave (página 32) — encabeza\n * la pantalla de inicio del portal. Compone `kf-select` para el propio\n * selector (mismo panel propio, sin `<select>` nativo) y proyecta hasta 3\n * pares label/valor (RUC, Identificación, Sucursal en el ejemplo del PDF).\n *\n * <kf-company-selector\n * label=\"Selecciona empresa\"\n * [companies]=\"['TRANSPORTES DEL SUR S.A.C.', 'ANDES MAQ LTDA.']\"\n * [value]=\"activeCompany()\"\n * (valueChange)=\"activeCompany.set($event)\"\n * [meta]=\"[\n * { label: 'RUC', value: '20448712359' },\n * { label: 'Identificación', value: '0004002232' },\n * { label: 'Sucursal', value: 'Sucursal Norte' },\n * ]\"\n * />\n *\n * Con opciones en forma de objeto, `value`/`valueChange` usan el `value` de\n * la opción, no su nombre:\n *\n * <kf-company-selector\n * [companies]=\"[\n * { value: '1002099', label: 'DIANA CAROLINA PINZÓN MALDONADO', tag: 'Personal', detail: 'DNI 46594489' },\n * { value: '1004410', label: 'TRANSPORTES VIRGEN DE LA AGRICULTURA', tag: 'Empresa', detail: 'RUC 20434860808' },\n * ]\"\n * [value]=\"activeAccount()\"\n * (valueChange)=\"activeAccount.set($event)\"\n * />\n */\n@Component({\n selector: 'kf-company-selector',\n imports: [Divider, Select, Text],\n templateUrl: './CompanySelector.html',\n styleUrl: './CompanySelector.css',\n})\nexport class CompanySelector {\n readonly label = input('Selecciona empresa');\n readonly companies = input.required<readonly (string | CompanySelectorOption)[]>();\n readonly value = input<string>();\n readonly meta = input<CompanySelectorMeta[]>([]);\n\n readonly valueChange = output<string>();\n}\n","<kf-select\n class=\"kf-company-selector__select\"\n [label]=\"label()\"\n [options]=\"companies()\"\n [value]=\"value()\"\n (valueChange)=\"valueChange.emit($event)\"\n/>\n@if (meta().length) {\n <div class=\"kf-company-selector__meta\">\n @for (item of meta(); track item.label; let last = $last) {\n <div class=\"kf-company-selector__meta-item\">\n <kf-text as=\"span\" variant=\"overline\">{{ item.label }}</kf-text>\n <span class=\"kf-company-selector__meta-value\">{{ item.value }}</span>\n </div>\n @if (!last) {\n <kf-divider orientation=\"vertical\" />\n }\n }\n </div>\n}\n","import { NgTemplateOutlet } from '@angular/common';\nimport {\n Component,\n DestroyRef,\n ElementRef,\n TemplateRef,\n afterNextRender,\n computed,\n inject,\n input,\n model,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport {\n DataTable,\n DataTableColumn,\n EmptyState,\n Icon,\n IconName,\n Modal,\n Pagination,\n} from '@kaufmann-lab/ui/core';\nimport { matchMediaSignal, normalizeForSearch } from '@kaufmann-lab/ui/shared';\n\n/** Reexportado tal cual — el picker no inventa un concepto de columna propio,\n * usa el mismo `DataTableColumn` que ya consume `kf-data-table`. */\nexport type { DataTableColumn };\n\n/** Chip de filtro genérico con contador — nunca hardcodeado a un dominio\n * concreto (ej. estado de una cotización); el consumidor decide qué\n * representa cada `value` y cómo mapea sus items contra él vía `predicate`.\n *\n * Bug real corregido: la primera versión leía `item.status`/`item.chip` por\n * nombre de campo mágico en vez de un `predicate` — colisionaba con\n * dominios donde `status` ya significa otra cosa (ej. `Quote.status` en\n * `web-otd-frontend` es 'ok'|'error'|'warn' de aprobación, no \"tiene saldo\n * pendiente\"). Un chip \"Con saldo pendiente\" sobre cotizaciones terminaba\n * filtrando por un campo que no tenía nada que ver, mostrando 0 resultados\n * siempre. `predicate` es explícito y no depende de convenciones de nombre. */\nexport interface QuotePickerChip<T = unknown> {\n value: string;\n label: string;\n count: number;\n predicate: (item: T) => boolean;\n}\n\n/** Una opción del dropdown \"Ordenar por\", visible solo en `variant=\"modal\"`. */\nexport interface QuotePickerSortOption {\n value: string;\n label: string;\n}\n\n/** Filas visibles en el preview acotado (modo `inline`, volumen alto) antes del fade + CTA. */\nconst PREVIEW_ROWS = 5;\n/** Filas por página en la tabla del modo `modal`. */\nconst PAGE_SIZE = 10;\n\n/**\n * Selector de un ítem \"rico\" de una lista buscable/filtrable — generalización\n * del patrón \"elegir una cotización\" de Pagos y Facturas de OTD, pero sin\n * ningún acoplamiento a `Quote`: todo el contenido de cada fila/card llega\n * por `columns` (mismo `DataTableColumn` de `kf-data-table`, reexportado acá\n * en vez de duplicar el concepto) + `cellTemplates` para contenido custom\n * (thumbnail, monto formateado, etc. — mismo mecanismo `TemplateRef` +\n * `ngTemplateOutlet` que ya usa `kf-data-table`).\n *\n * Un solo componente, dos contenedores (`variant: 'inline' | 'modal'`), UNA\n * sola lógica de búsqueda/filtro/orden interna. Nunca dos implementaciones\n * paralelas: el riesgo real de eso es que un fix de filtro se aplique en un\n * modo y se olvide en el otro. Los `computed()` de más abajo\n * (`filteredItems`, `sortedItems`) son la ÚNICA fuente de verdad para ambos\n * `variant`; lo que cambia entre inline y modal es solo qué contenedor\n * envuelve esos datos ya resueltos.\n *\n * ## Modo `inline` (default)\n * Trigger a ANCHO COMPLETO (nunca una caja angosta de ancho fijo) que\n * muestra el ítem activo colapsado — thumbnail, id + modelo, unidades +\n * fecha + monto, CTA \"Cambiar cotización\" con chevron-down. Al click, el\n * panel se expande INLINE (empuja el contenido de abajo, nunca flota\n * encima) con buscador propio + chips de filtro + un grid de 2 columnas (1\n * en mobile, breakpoint `max-width: 900px` vía `matchMediaSignal` — mismo\n * mecanismo que ya usa el resto de la librería para decisiones de layout en\n * TypeScript, no solo CSS). Por encima de `expandThreshold` resultados\n * visibles, el panel recorta a un preview de `PREVIEW_ROWS` filas con un\n * fade inferior y un botón dashed \"Ver las N en pantalla completa\" que\n * emite `expandToModal` — el picker no decide qué pasa después (típicamente\n * el consumidor pone `variant` en `'modal'` y `open` en `true`).\n *\n * ## Modo `modal`\n * Mismo buscador, mismos chips, misma lógica de filtrado — compone\n * `kf-modal` (proyectando el contenido) en vez de reimplementar un\n * `<dialog>` a mano: la API de `Modal` (`[(open)]`, cierre con\n * Escape/backdrop/botón vía `<dialog>` nativo) ya cubre exactamente lo que\n * este modo necesita. Compone también `kf-data-table` para la tabla\n * completa (columnas configurables, fade de overflow horizontal ya\n * resuelto ahí) y `kf-pagination` para paginar — ninguno de los tres se\n * reimplementa. Agrega un dropdown propio de \"Ordenar por\" (calibrado\n * visualmente contra el trigger de `kf-select`, pero compacto: `kf-select`\n * fuerza un ancho fijo de 240px pensado para formularios, no para una\n * barra de herramientas de tabla — ver JSDoc de `sortOpen` más abajo).\n *\n * En mobile, `kf-data-table[cardable]` con `defaultView` forzado a\n * `'cards'` decide la vista (mismo criterio que `matchMediaSignal` ya\n * resolvió en otros consumidores): dentro de un modal a pantalla completa\n * no tiene sentido ofrecer un toggle tabla/cards que en mobile daría una\n * tabla angosta con scroll horizontal.\n *\n * DEUDA TÉCNICA CONOCIDA (confirmada con el usuario, ver CHANGELOG.md): el\n * diseño validado con mockups pedía que en mobile el modal ocupe el 100%\n * de la pantalla (botón \"atrás\", sin overlay centrado) — `kf-modal` no\n * tiene ese modo, así que hoy en mobile se ve como un diálogo centrado\n * angosto (`width: min(480px, ...)`). Es funcional (cards legibles,\n * búsqueda, chips, paginación), solo visualmente distinto del mockup.\n *\n * <kf-quote-picker\n * [items]=\"quotes()\"\n * [columns]=\"columns\"\n * [selectedId]=\"selectedQuoteId()\"\n * [idKey]=\"(q) => q.id\"\n * [chips]=\"statusChips()\"\n * [cellTemplates]=\"{ photo: photoCell(), amount: amountCell() }\"\n * (selectedIdChange)=\"selectedQuoteId.set($event)\"\n * (expandToModal)=\"variant.set('modal'); open.set(true)\"\n * />\n */\n@Component({\n selector: 'kf-quote-picker',\n imports: [NgTemplateOutlet, Icon, Modal, DataTable, EmptyState, Pagination],\n templateUrl: './QuotePicker.html',\n styleUrl: './QuotePicker.css',\n})\nexport class QuotePicker<T = unknown> {\n readonly items = input.required<T[]>();\n readonly columns = input.required<DataTableColumn[]>();\n readonly selectedId = input<string | null>(null);\n readonly idKey = input.required<(item: T) => string>();\n\n /**\n * Mapa `columnKey -> TemplateRef`, mismo mecanismo que `kf-data-table`\n * (`ngTemplateOutlet` + contexto `{ $implicit: item, index }`) — se\n * reenvía tal cual a la tabla interna del modo `modal`, y se usa\n * directamente en el grid de cards del modo `inline`. Un solo mapa para\n * ambos modos, consistente con la regla de \"una sola lógica interna\".\n */\n readonly cellTemplates = input<\n Record<string, TemplateRef<{ $implicit: T; index: number }>> | undefined\n >();\n\n readonly chips = input<QuotePickerChip<T>[]>([]);\n readonly sortOptions = input<QuotePickerSortOption[]>([]);\n readonly sort = model<string | null>(null);\n\n /**\n * Umbral de volumen alto — el consumidor decide el número exacto, nunca\n * hardcodeado a \"cotizaciones\" ni a ningún caso de uso puntual. Default\n * 15 según el diseño validado con mockups.\n */\n readonly expandThreshold = input(15);\n\n readonly variant = input<'inline' | 'modal'>('inline');\n /** Visibilidad del modo `modal`, two-way — mismo patrón que `[(open)]` de `kf-modal`. */\n readonly open = model(false);\n\n readonly title = input('Cambiar cotización');\n readonly searchPlaceholder = input('Buscar…');\n /** Ícono de placeholder cuando ninguna columna `cardRole: 'media'` resuelve\n * un thumbnail real vía `cellTemplates` — el picker no asume qué dominio\n * consume (cotización, vehículo, cliente...), así que no hardcodea un\n * ícono fijo. Default `'file'` solo por no dejar el input sin valor. */\n readonly placeholderIcon = input<IconName>('file');\n\n readonly selectedIdChange = output<string>();\n /** Disparado al superar `expandThreshold` en modo inline; el consumidor decide pasar a `modal`. */\n readonly expandToModal = output<void>();\n\n protected readonly searchQuery = signal('');\n protected readonly activeChip = signal<string | null>(null);\n protected readonly expanded = signal(false);\n protected readonly page = signal(1);\n protected readonly sortOpen = signal(false);\n\n /**\n * Mismo breakpoint (`max-width: 900px`) que el resto de la librería usa\n * para decisiones de layout en TypeScript (no solo CSS) — ver\n * `matchMediaSignal`. Decide 1 vs. 2 columnas en el grid inline, y tabla\n * vs. cards apiladas dentro del modal.\n */\n protected readonly isMobile = matchMediaSignal('(max-width: 900px)');\n\n private readonly destroyRef = inject(DestroyRef);\n private readonly previewScrollEl = viewChild<ElementRef<HTMLElement>>('previewScroll');\n\n /** Mismo mecanismo de fade que `kf-data-table` — ver comentario en QuotePicker.css. */\n protected readonly canFadeBottom = signal(false);\n\n readonly selectedItem = computed(() =>\n this.items().find((item) => this.idKey()(item) === this.selectedId()),\n );\n\n /** Filtro por texto (buscador propio) + filtro por chip activo, en ese orden. */\n protected readonly filteredItems = computed<T[]>(() => {\n const query = normalizeForSearch(this.searchQuery().trim());\n const chipValue = this.activeChip();\n const chip = chipValue ? this.chips().find((c) => c.value === chipValue) : undefined;\n const idKeyFn = this.idKey();\n const cols = this.columns();\n\n return this.items().filter((item) => {\n if (chip && !chip.predicate(item)) {\n return false;\n }\n if (!query) {\n return true;\n }\n const haystack = cols\n .map((column) => this.cellText(item, column))\n .concat(idKeyFn(item))\n .join(' ');\n return normalizeForSearch(haystack).includes(query);\n });\n });\n\n /**\n * Orden solo tiene efecto visible en modo `modal` (el diseño validado no\n * pide dropdown de orden en inline) — se calcula igual en ambos casos\n * porque es la MISMA lógica interna; en inline `sort()` simplemente se\n * queda en `null` salvo que el consumidor lo setee explícitamente.\n */\n protected readonly sortedItems = computed<T[]>(() => {\n const sortValue = this.sort();\n const items = this.filteredItems();\n if (!sortValue) {\n return items;\n }\n const [key, direction] = sortValue.split(':') as [string, 'asc' | 'desc' | undefined];\n const sorted = [...items].sort((a, b) => {\n const va = (a as Record<string, unknown>)[key];\n const vb = (b as Record<string, unknown>)[key];\n if (va === vb) {\n return 0;\n }\n return (va as string | number) > (vb as string | number) ? 1 : -1;\n });\n return direction === 'desc' ? sorted.reverse() : sorted;\n });\n\n /** Por encima del umbral, el preview inline se recorta salvo que el usuario ya haya expandido. */\n protected readonly isHighVolume = computed(\n () => this.sortedItems().length > this.expandThreshold(),\n );\n\n protected readonly previewItems = computed<T[]>(() => {\n const all = this.sortedItems();\n if (!this.isHighVolume() || this.expanded()) {\n return all;\n }\n return all.slice(0, PREVIEW_ROWS);\n });\n\n protected readonly pages = computed(() =>\n Math.max(Math.ceil(this.sortedItems().length / PAGE_SIZE), 1),\n );\n\n protected readonly pagedItems = computed<T[]>(() => {\n const start = (this.page() - 1) * PAGE_SIZE;\n return this.sortedItems().slice(start, start + PAGE_SIZE);\n });\n\n protected readonly sortLabel = computed(() => {\n const current = this.sortOptions().find((option) => option.value === this.sort());\n return current?.label ?? 'Ordenar por';\n });\n\n constructor() {\n afterNextRender(() => {\n const el = this.previewScrollEl()?.nativeElement;\n if (!el) {\n return;\n }\n const update = () => this.updateFadeState(el);\n update();\n el.addEventListener('scroll', update, { passive: true });\n const observer = new ResizeObserver(update);\n observer.observe(el);\n this.destroyRef.onDestroy(() => {\n el.removeEventListener('scroll', update);\n observer.disconnect();\n });\n });\n }\n\n private updateFadeState(el: HTMLElement): void {\n // 1px de margen por el mismo motivo que en DataTable: subpíxeles de\n // scroll dejarían el fade \"prendido\" en un preview que ya llegó al final.\n this.canFadeBottom.set(el.scrollHeight - el.clientHeight - el.scrollTop > 1);\n }\n\n private cellText(item: T, column: DataTableColumn): string {\n const value = (item as Record<string, unknown>)[column.key];\n return value === null || value === undefined ? '' : String(value);\n }\n\n toggleExpandedPanel(): void {\n this.expanded.set(!this.expanded());\n }\n\n onSearchInput(event: Event): void {\n this.searchQuery.set((event.target as HTMLInputElement).value);\n this.page.set(1);\n }\n\n selectChip(value: string): void {\n this.activeChip.set(this.activeChip() === value ? null : value);\n this.page.set(1);\n }\n\n select(item: T): void {\n const id = this.idKey()(item);\n // El panel se cierra siempre al elegir (haya cambiado el id o no) —\n // mismo comportamiento esperado de cualquier selector, ej. `kf-select`\n // cierra su panel al elegir opción; dejarle esa responsabilidad al\n // consumidor sería una carga que ningún otro componente de la\n // librería le pide.\n this.expanded.set(false);\n if (id === this.selectedId()) {\n return;\n }\n this.selectedIdChange.emit(id);\n }\n\n onItemKeydown(event: KeyboardEvent, item: T): void {\n if (event.key === 'Enter') {\n event.preventDefault();\n this.select(item);\n }\n }\n\n onSeeAll(): void {\n this.expandToModal.emit();\n }\n\n onTableRowClick(event: { row: T; index: number }): void {\n this.select(event.row);\n }\n\n toggleSort(): void {\n this.sortOpen.update((open) => !open);\n }\n\n setSort(value: string): void {\n this.sort.set(this.sort() === value ? null : value);\n this.sortOpen.set(false);\n }\n\n trackItem(item: T, index: number): string | number {\n const idKeyFn = this.idKey();\n return idKeyFn ? idKeyFn(item) : index;\n }\n\n /** Arrow function como campo (no un método) para que `[rowKey]` reciba\n * una referencia ESTABLE entre change detections — `trackItem.bind(this)`\n * en el template recrearía una función nueva en cada ciclo, invalidando\n * cualquier optimización de `kf-data-table` que dependa de identidad. */\n protected readonly rowKeyFn = (item: T, index: number): string | number =>\n this.trackItem(item, index);\n\n protected cellValue(item: T, column: DataTableColumn): string {\n return this.cellText(item, column);\n }\n\n protected readonly mediaColumn = computed(() =>\n this.columns().find((c) => c.cardRole === 'media'),\n );\n protected readonly titleColumn = computed(() =>\n this.columns().find((c) => c.cardRole === 'title'),\n );\n protected readonly fieldColumns = computed(() =>\n this.columns().filter((c) => !c.cardRole || c.cardRole === 'field'),\n );\n}\n","@if (variant() === 'inline') {\n <div class=\"kf-quote-picker__inline\">\n <!-- Trigger colapsado (default): ancho completo, nunca una caja angosta. -->\n <button\n type=\"button\"\n class=\"kf-quote-picker__trigger\"\n [attr.aria-expanded]=\"expanded()\"\n (click)=\"toggleExpandedPanel()\"\n >\n <span class=\"kf-quote-picker__thumb\">\n @if (mediaColumn(); as media) {\n @if (cellTemplates()?.[media.key]; as template) {\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"{ $implicit: selectedItem(), index: 0 }\"\n />\n }\n } @else {\n <kf-icon [name]=\"placeholderIcon()\" size=\"md\" />\n }\n </span>\n @if (selectedItem(); as item) {\n <span class=\"kf-quote-picker__trigger-summary\">\n @if (titleColumn(); as title) {\n <span class=\"kf-quote-picker__trigger-field kf-quote-picker__trigger-field--title\">{{\n cellValue(item, title)\n }}</span>\n }\n <!--\n En mobile solo se muestra el título (ID) — mostrar los 5 campos\n en una sola línea de ~90px de ancho real corta el texto sin\n elipsis a mitad del segundo campo (bug real medido:\n scrollWidth=519 vs. clientWidth=87 en 390px). El resto de los\n campos siguen disponibles en el panel expandido y en el modal,\n donde sí hay espacio horizontal.\n -->\n @if (!isMobile()) {\n @for (col of fieldColumns(); track col.key) {\n <span class=\"kf-quote-picker__trigger-sep\" aria-hidden=\"true\">·</span>\n <span class=\"kf-quote-picker__trigger-field\">{{ cellValue(item, col) }}</span>\n }\n }\n </span>\n } @else {\n <span class=\"kf-quote-picker__trigger-summary kf-quote-picker__trigger-summary--empty\"\n >Sin selección</span\n >\n }\n <span class=\"kf-quote-picker__trigger-action\">\n {{ expanded() ? 'Cerrar' : title() }}\n <kf-icon\n name=\"chevron-down\"\n size=\"sm\"\n class=\"kf-quote-picker__chevron\"\n [class.kf-quote-picker__chevron--open]=\"expanded()\"\n />\n </span>\n </button>\n\n @if (expanded()) {\n <div class=\"kf-quote-picker__panel\">\n <div class=\"kf-quote-picker__toolbar\">\n <div class=\"kf-quote-picker__search\">\n <kf-icon name=\"search\" size=\"sm\" />\n <input\n type=\"text\"\n class=\"kf-quote-picker__search-input\"\n [placeholder]=\"searchPlaceholder()\"\n [value]=\"searchQuery()\"\n (input)=\"onSearchInput($event)\"\n />\n </div>\n @for (chip of chips(); track chip.value) {\n <button\n type=\"button\"\n class=\"kf-quote-picker__chip\"\n [class.kf-quote-picker__chip--active]=\"activeChip() === chip.value\"\n (click)=\"selectChip(chip.value)\"\n >\n {{ chip.label }} ({{ chip.count }})\n </button>\n }\n </div>\n\n <div class=\"kf-quote-picker__results-wrap\">\n <div #previewScroll class=\"kf-quote-picker__results\" role=\"listbox\">\n @for (item of previewItems(); track trackItem(item, $index)) {\n <button\n type=\"button\"\n class=\"kf-quote-picker__result\"\n [class.kf-quote-picker__result--active]=\"idKey()(item) === selectedId()\"\n role=\"option\"\n [attr.aria-selected]=\"idKey()(item) === selectedId()\"\n (click)=\"select(item)\"\n (keydown)=\"onItemKeydown($event, item)\"\n >\n <span class=\"kf-quote-picker__thumb kf-quote-picker__thumb--sm\">\n @if (mediaColumn(); as media) {\n @if (cellTemplates()?.[media.key]; as template) {\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"{ $implicit: item, index: $index }\"\n />\n }\n } @else {\n <kf-icon [name]=\"placeholderIcon()\" size=\"sm\" />\n }\n </span>\n @if (titleColumn(); as title) {\n <span\n class=\"kf-quote-picker__result-field kf-quote-picker__result-field--title\"\n >{{ cellValue(item, title) }}</span\n >\n }\n <!--\n Wrapper propio (no los spans sueltos) para los campos\n secundarios: en mobile necesita saltar de línea COMPLETO\n (mismo criterio que \"unidades\" no debe competir con\n \"modelo\" en la primera línea) — `flex-basis: 100%` en un\n solo elemento fuerza ese salto sin tener que asumir cuál\n de los N campos genéricos es el más corto o el más largo.\n -->\n <span class=\"kf-quote-picker__result-fields\">\n @for (col of fieldColumns(); track col.key; let first = $first) {\n <span\n class=\"kf-quote-picker__result-field\"\n [class.kf-quote-picker__result-field--primary]=\"first\"\n >{{ cellValue(item, col) }}</span\n >\n }\n </span>\n </button>\n } @empty {\n <p class=\"kf-quote-picker__empty\">Sin resultados para esta búsqueda.</p>\n }\n </div>\n @if (canFadeBottom()) {\n <div class=\"kf-quote-picker__fade\" aria-hidden=\"true\"></div>\n }\n </div>\n\n @if (isHighVolume()) {\n <button type=\"button\" class=\"kf-quote-picker__see-all\" (click)=\"onSeeAll()\">\n Ver las {{ sortedItems().length }} en pantalla completa\n </button>\n }\n </div>\n }\n </div>\n} @else {\n <kf-modal [(open)]=\"open\" [title]=\"title()\" [dismissible]=\"true\">\n <div class=\"kf-quote-picker__modal-toolbar\">\n <div class=\"kf-quote-picker__search\">\n <kf-icon name=\"search\" size=\"sm\" />\n <input\n type=\"text\"\n class=\"kf-quote-picker__search-input\"\n [placeholder]=\"searchPlaceholder()\"\n [value]=\"searchQuery()\"\n (input)=\"onSearchInput($event)\"\n />\n </div>\n <div class=\"kf-quote-picker__modal-filters\">\n <div class=\"kf-quote-picker__modal-chips\">\n @for (chip of chips(); track chip.value) {\n <button\n type=\"button\"\n class=\"kf-quote-picker__chip\"\n [class.kf-quote-picker__chip--active]=\"activeChip() === chip.value\"\n (click)=\"selectChip(chip.value)\"\n >\n {{ chip.label }} ({{ chip.count }})\n </button>\n }\n </div>\n @if (sortOptions().length > 0) {\n <div class=\"kf-quote-picker__sort\">\n <button\n type=\"button\"\n class=\"kf-quote-picker__sort-trigger\"\n [attr.aria-expanded]=\"sortOpen()\"\n (click)=\"toggleSort()\"\n >\n <kf-icon name=\"sort\" size=\"sm\" />\n {{ sortLabel() }}\n <kf-icon name=\"chevron-down\" size=\"sm\" />\n </button>\n @if (sortOpen()) {\n <div class=\"kf-quote-picker__sort-panel\">\n @for (option of sortOptions(); track option.value) {\n <button\n type=\"button\"\n class=\"kf-quote-picker__sort-option\"\n [class.kf-quote-picker__sort-option--active]=\"sort() === option.value\"\n (click)=\"setSort(option.value)\"\n >\n {{ option.label }}\n </button>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n <kf-data-table\n [columns]=\"columns()\"\n [rows]=\"pagedItems()\"\n [cardable]=\"true\"\n [defaultView]=\"isMobile() ? 'cards' : 'table'\"\n [cellTemplates]=\"cellTemplates()\"\n [rowKey]=\"rowKeyFn\"\n (rowClick)=\"onTableRowClick($event)\"\n >\n <kf-empty-state empty icon=\"file\">Sin resultados para esta búsqueda.</kf-empty-state>\n @if (sortedItems().length > 0) {\n <kf-pagination footer [page]=\"page()\" [pages]=\"pages()\" (pageChange)=\"page.set($event)\">\n {{ sortedItems().length }} resultados\n </kf-pagination>\n }\n </kf-data-table>\n </kf-modal>\n}\n","import { booleanAttribute, Component, input, output } from '@angular/core';\nimport { Icon, Link } from '@kaufmann-lab/ui/core';\n\n/**\n * Estado vacío de reservas en taller con llamada a agendar (página 36):\n * barra de estado vacío arriba (\"No tienes reservas de taller\"), panel de\n * invitación al medio (ícono en círculo azul, título, descripción, link) y\n * una fila de dos acciones al pie — un slot `[actions]` proyectado, para no\n * acoplar el componente a botones fijos.\n *\n * Distinto de `kf-empty-state` genérico: este combina la barra + la\n * invitación + las acciones como un bloque compuesto propio del dominio\n * \"taller\", no un placeholder de una sola pieza.\n *\n * `grow` estira el panel de invitación para llenar el espacio vertical\n * disponible — solo cuando el consumidor comparte fila con una tarjeta más\n * alta (ej. junto a \"Total de vehículos\"); en un lugar sin esa presión\n * (home, debajo del carousel) se deja en su alto natural.\n *\n * <kf-reserve-block emptyLabel=\"No tienes reservas de taller\" grow\n * title=\"¿Necesitas mantención?\" description=\"Tenemos la mejor red de talleres.\"\n * actionLabel=\"Agenda tu reserva aquí\" actionHref=\"/taller/agendar\">\n * <kf-button actions icon=\"calendar\">Reservar hora</kf-button>\n * <kf-button actions variant=\"outline\" icon=\"list\">Ver agenda</kf-button>\n * </kf-reserve-block>\n *\n * Para apps con router: escuchar `actionClick` y llamar\n * `event.preventDefault()` antes de `router.navigateByUrl(...)`. El\n * `actionHref` se mantiene igual para que click-medio, \"abrir en pestaña\n * nueva\" y el hover de la barra de estado sigan funcionando.\n *\n * <kf-reserve-block title=\"¿Necesitas mantención?\" actionLabel=\"Agenda tu reserva aquí\"\n * actionHref=\"/taller/agendar\"\n * (actionClick)=\"$event.preventDefault(); router.navigateByUrl('/taller/agendar')\" />\n */\n@Component({\n selector: 'kf-reserve-block',\n imports: [Icon, Link],\n templateUrl: './ReserveBlock.html',\n styleUrl: './ReserveBlock.css',\n})\nexport class ReserveBlock {\n readonly emptyLabel = input('No tienes reservas de taller');\n readonly title = input.required<string>();\n readonly description = input<string>();\n readonly actionLabel = input<string>();\n readonly actionHref = input<string>();\n /** La invitación se estira para llenar la tarjeta (ej. junto a \"Total de vehículos\"). */\n readonly grow = input(false, { transform: booleanAttribute });\n\n /**\n * Click en el link de la invitación. Incluye el `MouseEvent` para que un\n * consumidor con router pueda cortar la navegación nativa — mismo patrón\n * que `itemClick` de `kf-breadcrumb`, sin depender de `@angular/router`.\n */\n readonly actionClick = output<MouseEvent>();\n}\n","<div class=\"kf-reserve-block__empty\">\n <kf-icon name=\"calendar\" size=\"sm\" />\n <span>{{ emptyLabel() }}</span>\n</div>\n<div class=\"kf-reserve-block__invite\" [class.kf-reserve-block__invite--grow]=\"grow()\">\n <span class=\"kf-reserve-block__invite-icon\">\n <kf-icon name=\"tool\" size=\"md\" />\n </span>\n <div class=\"kf-reserve-block__invite-text\">\n <span class=\"kf-reserve-block__invite-title\">{{ title() }}</span>\n @if (description()) {\n <span class=\"kf-reserve-block__invite-description\">{{ description() }}</span>\n }\n @if (actionLabel()) {\n <kf-link\n class=\"kf-reserve-block__invite-action\"\n [href]=\"actionHref() || '#'\"\n showArrow\n (click)=\"actionClick.emit($event)\"\n >\n {{ actionLabel() }}\n </kf-link>\n }\n </div>\n</div>\n<div class=\"kf-reserve-block__actions\">\n <ng-content select=\"[actions]\" />\n</div>\n","import { Component, input } from '@angular/core';\nimport { Icon, IconName, Text } from '@kaufmann-lab/ui/core';\n\n/**\n * Estado puntual mostrado junto a la identidad del vehículo (ej. \"En ruta\",\n * \"Mantenimiento\", \"Fuera de servicio\"). `tone` define el color semántico:\n * \"crit\" no tiene token propio en base.css, se mapea a var(--kf-color-error).\n */\nexport interface VehicleHeaderStatus {\n label: string;\n tone?: 'ok' | 'warn' | 'crit';\n icon?: IconName;\n}\n\n/**\n * Header de identidad de un vehículo de flota: unidad (patente/id), modelo\n * (como badge, no texto plano — página 24: \"ABC-123\" junto a un badge\n * \"TITAN 4X2\"), VIN en fuente mono y un estado opcional. Un área de acciones\n * opcional se proyecta vía `<ng-content select=\"[actions]\">` para no acoplar\n * el componente a un set fijo de botones — el patrón real de la spec es\n * `kf-button variant=\"outline\"` (ej. \"Llamar\", con ícono) + un `primary`\n * (ej. \"Crear Ticket\", con ícono \"+\"):\n *\n * <kf-vehicle-header unit=\"AB123CD\" model=\"Sprinter 415\" vin=\"9BW...\"\n * [status]=\"{ label: 'En ruta', tone: 'ok' }\">\n * <kf-button actions variant=\"outline\" icon=\"phone\">Llamar</kf-button>\n * <kf-button actions icon=\"plus\">Crear Ticket</kf-button>\n * </kf-vehicle-header>\n */\n@Component({\n selector: 'kf-vehicle-header',\n imports: [Icon, Text],\n templateUrl: './VehicleHeader.html',\n styleUrl: './VehicleHeader.css',\n})\nexport class VehicleHeader {\n readonly unit = input.required<string>();\n readonly model = input<string>();\n readonly vin = input<string>();\n readonly status = input<VehicleHeaderStatus>();\n}\n","<div class=\"kf-vehicle-header__identity\">\n <span class=\"kf-vehicle-header__unit\">{{ unit() }}</span>\n @if (model()) {\n <span class=\"kf-vehicle-header__model\">\n <kf-text as=\"span\" variant=\"overline-strong\">{{ model() }}</kf-text>\n </span>\n }\n @if (vin()) {\n <span class=\"kf-vehicle-header__vin\">VIN: {{ vin() }}</span>\n }\n</div>\n\n@if (status(); as currentStatus) {\n <span\n class=\"kf-vehicle-header__status\"\n [class]=\"'kf-vehicle-header__status--' + (currentStatus.tone ?? 'ok')\"\n >\n @if (currentStatus.icon; as iconName) {\n <kf-icon [name]=\"iconName\" size=\"sm\" />\n }\n {{ currentStatus.label }}\n </span>\n}\n\n<div class=\"kf-vehicle-header__actions\">\n <ng-content select=\"[actions]\" />\n</div>\n","/*\n * Public API Surface of ui/business — entry point secundario, `@kaufmann-lab/ui/business`.\n *\n * Componentes que modelan un concepto de negocio real de Kaufmann (una\n * cotización, una reserva de taller, un vehículo de flota, la empresa activa\n * de una sesión), no una preocupación de UI transversal — ver\n * `ENTRY-POINTS.md` en la raíz del repo para el criterio.\n *\n * Consume sus piezas base (`Icon`, `Text`, `Select`, `DataTable`, etc.) desde\n * `'@kaufmann-lab/ui/core'` y los helpers desde `'@kaufmann-lab/ui/shared'`,\n * nunca desde la raíz `'@kaufmann-lab/ui'` (agregador que depende de todos\n * los entry points — importarla desde acá cerraría un ciclo) ni por ruta\n * relativa cruzando la frontera entre entry points (ng-packagr calcula un\n * `rootDir` propio por entry point y rechaza archivos fuente fuera de él).\n *\n * La raíz `'@kaufmann-lab/ui'` los reexporta, así que\n * `import { QuotePicker } from '@kaufmann-lab/ui'` sigue funcionando igual.\n */\n\nexport * from './lib/company-selector/CompanySelector';\nexport * from './lib/quote-picker/QuotePicker';\nexport * from './lib/reserve-block/ReserveBlock';\nexport * from './lib/vehicle-header/VehicleHeader';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"kaufmann-lab-ui-business.mjs","sources":["../../../projects/ui/business/src/lib/company-selector/CompanySelector.ts","../../../projects/ui/business/src/lib/company-selector/CompanySelector.html","../../../projects/ui/business/src/lib/quote-picker/QuotePicker.ts","../../../projects/ui/business/src/lib/quote-picker/QuotePicker.html","../../../projects/ui/business/src/lib/reserve-block/ReserveBlock.ts","../../../projects/ui/business/src/lib/reserve-block/ReserveBlock.html","../../../projects/ui/business/src/lib/vehicle-header/VehicleHeader.ts","../../../projects/ui/business/src/lib/vehicle-header/VehicleHeader.html","../../../projects/ui/business/src/public-api.ts","../../../projects/ui/business/src/kaufmann-lab-ui-business.ts"],"sourcesContent":["import { Component, input, output } from '@angular/core';\nimport { Divider, Select, Text } from '@kaufmann-lab/ui/core';\n\n/** Metadato clave mostrado junto al selector (RUC, identificación, sucursal). */\nexport interface CompanySelectorMeta {\n label: string;\n value: string;\n}\n\n/**\n * Empresa elegible. `value` es el identificador único (ej. número de\n * cuenta) — dos empresas con el mismo `label` se seleccionan por separado.\n * `tag` se muestra como badge junto al nombre (ej. 'Personal' | 'Empresa')\n * y `detail` como línea secundaria en el panel (ej. 'RUC 20434860808').\n */\nexport interface CompanySelectorOption {\n value: string;\n label: string;\n tag?: string;\n detail?: string;\n}\n\n/**\n * Conmutador de empresa activa con metadatos clave (página 32) — encabeza\n * la pantalla de inicio del portal. Compone `kf-select` para el propio\n * selector (mismo panel propio, sin `<select>` nativo) y proyecta hasta 3\n * pares label/valor (RUC, Identificación, Sucursal en el ejemplo del PDF).\n *\n * <kf-company-selector\n * label=\"Selecciona empresa\"\n * [companies]=\"['TRANSPORTES DEL SUR S.A.C.', 'ANDES MAQ LTDA.']\"\n * [value]=\"activeCompany()\"\n * (valueChange)=\"activeCompany.set($event)\"\n * [meta]=\"[\n * { label: 'RUC', value: '20448712359' },\n * { label: 'Identificación', value: '0004002232' },\n * { label: 'Sucursal', value: 'Sucursal Norte' },\n * ]\"\n * />\n *\n * Con opciones en forma de objeto, `value`/`valueChange` usan el `value` de\n * la opción, no su nombre:\n *\n * <kf-company-selector\n * [companies]=\"[\n * { value: '1002099', label: 'DIANA CAROLINA PINZÓN MALDONADO', tag: 'Personal', detail: 'DNI 46594489' },\n * { value: '1004410', label: 'TRANSPORTES VIRGEN DE LA AGRICULTURA', tag: 'Empresa', detail: 'RUC 20434860808' },\n * ]\"\n * [value]=\"activeAccount()\"\n * (valueChange)=\"activeAccount.set($event)\"\n * />\n */\n@Component({\n selector: 'kf-company-selector',\n imports: [Divider, Select, Text],\n templateUrl: './CompanySelector.html',\n styleUrl: './CompanySelector.css',\n})\nexport class CompanySelector {\n readonly label = input('Selecciona empresa');\n readonly companies = input.required<readonly (string | CompanySelectorOption)[]>();\n readonly value = input<string>();\n readonly meta = input<CompanySelectorMeta[]>([]);\n\n readonly valueChange = output<string>();\n}\n","<kf-select\n class=\"kf-company-selector__select\"\n [label]=\"label()\"\n [options]=\"companies()\"\n [value]=\"value()\"\n (valueChange)=\"valueChange.emit($event)\"\n/>\n@if (meta().length) {\n <div class=\"kf-company-selector__meta\">\n @for (item of meta(); track item.label; let last = $last) {\n <div class=\"kf-company-selector__meta-item\">\n <kf-text as=\"span\" variant=\"overline\">{{ item.label }}</kf-text>\n <span class=\"kf-company-selector__meta-value\">{{ item.value }}</span>\n </div>\n @if (!last) {\n <kf-divider orientation=\"vertical\" />\n }\n }\n </div>\n}\n","import { NgTemplateOutlet } from '@angular/common';\nimport {\n booleanAttribute,\n Component,\n DestroyRef,\n ElementRef,\n TemplateRef,\n afterNextRender,\n afterRenderEffect,\n computed,\n inject,\n input,\n model,\n output,\n signal,\n untracked,\n viewChild,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport {\n Button,\n ContentState,\n ContentStateKind,\n DataTable,\n DataTableColumn,\n EmptyState,\n FilterChipOption,\n FilterChips,\n Icon,\n IconName,\n Input,\n Modal,\n Pagination,\n Select,\n SelectOption,\n Skeleton,\n Text,\n} from '@kaufmann-lab/ui/core';\nimport { matchMediaSignal, normalizeForSearch } from '@kaufmann-lab/ui/shared';\n\n/** Reexportado tal cual — el picker no inventa un concepto de columna propio,\n * usa el mismo `DataTableColumn` que ya consume `kf-data-table`. */\nexport type { DataTableColumn };\n\n/**\n * Alias del mismo `DataTableColumn`, para leer la API del picker sin ir a la\n * tabla. En `modalLayout=\"list\"` usa: `cardRole` (`title` → primera columna\n * en mono; el primer campo sin rol → columna flexible con elipsis; `status`\n * → última columna, hasta 13.75rem salvo `maxWidth`), `width` (ancho fijo de\n * la pista), `maxWidth`, `align`/`right` y `truncate` (elipsis + `title`).\n */\nexport type QuotePickerColumn = DataTableColumn;\n\n/** Sustantivo de los ítems para el conteo del encabezado (\"86 cotizaciones\"). */\nexport interface QuotePickerItemLabels {\n singular: string;\n plural: string;\n}\n\n/** Chip de filtro genérico con contador — nunca hardcodeado a un dominio\n * concreto (ej. estado de una cotización); el consumidor decide qué\n * representa cada `value` y cómo mapea sus items contra él vía `predicate`.\n *\n * Bug real corregido: la primera versión leía `item.status`/`item.chip` por\n * nombre de campo mágico en vez de un `predicate` — colisionaba con\n * dominios donde `status` ya significa otra cosa (ej. `Quote.status` en\n * `web-otd-frontend` es 'ok'|'error'|'warn' de aprobación, no \"tiene saldo\n * pendiente\"). Un chip \"Con saldo pendiente\" sobre cotizaciones terminaba\n * filtrando por un campo que no tenía nada que ver, mostrando 0 resultados\n * siempre. `predicate` es explícito y no depende de convenciones de nombre. */\nexport interface QuotePickerChip<T = unknown> {\n value: string;\n label: string;\n count: number;\n predicate: (item: T) => boolean;\n}\n\n/** Una opción del dropdown \"Ordenar por\", visible solo en `variant=\"modal\"`. */\nexport interface QuotePickerSortOption {\n value: string;\n label: string;\n}\n\n/** Filas visibles en el preview acotado (modo `inline`, volumen alto) antes del fade + CTA. */\nconst PREVIEW_ROWS = 5;\n/** Filas por página en la tabla del modo `modal`. */\nconst PAGE_SIZE = 10;\n\n/**\n * Selector de un ítem \"rico\" de una lista buscable/filtrable — generalización\n * del patrón \"elegir una cotización\" de Pagos y Facturas de OTD, pero sin\n * ningún acoplamiento a `Quote`: todo el contenido de cada fila/card llega\n * por `columns` (mismo `DataTableColumn` de `kf-data-table`, reexportado acá\n * en vez de duplicar el concepto) + `cellTemplates` para contenido custom\n * (thumbnail, monto formateado, etc. — mismo mecanismo `TemplateRef` +\n * `ngTemplateOutlet` que ya usa `kf-data-table`).\n *\n * Un solo componente, dos contenedores (`variant: 'inline' | 'modal'`), UNA\n * sola lógica de búsqueda/filtro/orden interna. Nunca dos implementaciones\n * paralelas: el riesgo real de eso es que un fix de filtro se aplique en un\n * modo y se olvide en el otro. Los `computed()` de más abajo\n * (`filteredItems`, `sortedItems`) son la ÚNICA fuente de verdad para ambos\n * `variant`; lo que cambia entre inline y modal es solo qué contenedor\n * envuelve esos datos ya resueltos.\n *\n * ## Modo `inline` (default)\n * Trigger a ANCHO COMPLETO (nunca una caja angosta de ancho fijo) que\n * muestra el ítem activo colapsado — thumbnail, id + modelo, unidades +\n * fecha + monto, CTA \"Cambiar cotización\" con chevron-down. Al click, el\n * panel se expande INLINE (empuja el contenido de abajo, nunca flota\n * encima) con buscador propio + chips de filtro + un grid de 2 columnas (1\n * en mobile, breakpoint `max-width: 900px` vía `matchMediaSignal` — mismo\n * mecanismo que ya usa el resto de la librería para decisiones de layout en\n * TypeScript, no solo CSS). Por encima de `expandThreshold` resultados\n * visibles, el panel recorta a un preview de `PREVIEW_ROWS` filas con un\n * fade inferior y un botón dashed \"Ver las N en pantalla completa\" que\n * emite `expandToModal` — el picker no decide qué pasa después (típicamente\n * el consumidor pone `variant` en `'modal'` y `open` en `true`).\n *\n * ## Modo `modal`\n * Mismo buscador, mismos chips, misma lógica de filtrado — compone\n * `kf-modal` (proyectando el contenido) en vez de reimplementar un\n * `<dialog>` a mano: la API de `Modal` (`[(open)]`, cierre con\n * Escape/backdrop/botón vía `<dialog>` nativo) ya cubre exactamente lo que\n * este modo necesita. Compone también `kf-data-table` para la tabla\n * completa (columnas configurables, fade de overflow horizontal ya\n * resuelto ahí) y `kf-pagination` para paginar — ninguno de los tres se\n * reimplementa, igual que el buscador (`kf-input`), el orden (`kf-select`)\n * y los chips (`kf-filter-chips`).\n *\n * En mobile, `kf-data-table[cardable]` con `defaultView` forzado a\n * `'cards'` decide la vista (mismo criterio que `matchMediaSignal` ya\n * resolvió en otros consumidores): dentro de un modal a pantalla completa\n * no tiene sentido ofrecer un toggle tabla/cards que en mobile daría una\n * tabla angosta con scroll horizontal.\n *\n * El modal mide `min(modalWidth, 100vw - 32px)` (default 1040px) con alto\n * máximo de 85vh: encabezado (título + conteo \"12 de 86 cotizaciones\" en\n * región `aria-live`) y filtros FIJOS arriba, solo la lista se desplaza. En\n * ≤640px de viewport ocupa toda la pantalla (`fullscreenOnMobile` de\n * `kf-modal`). Filtros: fila 1 = buscador (`kf-input`, crece, mínimo 240px)\n * + orden (`kf-select` estándar); fila 2 = `kf-filter-chips` con contador y\n * un chip \"Todas\" (`allChipLabel`) — en varias líneas en escritorio, una\n * sola línea con scroll horizontal en mobile. Elegir un ítem (o el actual)\n * cierra el modal.\n *\n * ## Trigger (variante `inline`)\n * - `triggerSize=\"default\"` (histórico): tarjeta a ancho completo con\n * miniatura y resumen.\n * - `triggerSize=\"compact\"`: control de barra de herramientas de alto FIJO\n * (`--kf-quote-picker-trigger-height`, 48px), sin miniatura: línea 1 =\n * título en mono + estado (columnas `status`), línea 2 = primer campo con\n * elipsis, y caret. Ancho flexible (`min-width: 0`). Su nombre accesible\n * es el texto visible con un prefijo: \"Cambiar cotización. Actual: <id>,\n * <estado>, <modelo>\".\n * - `inlinePanel` (default `true`): con `false`, el trigger abre DIRECTO el\n * modal del picker (`aria-haspopup=\"dialog\"`), sin panel inline — el mismo\n * modal que la variante `modal`, así todas las pantallas comparten un\n * único selector.\n *\n * Con `loading` el trigger compacto muestra un esqueleto del MISMO alto\n * (región `role=\"status\"` con `loadingLabel`), así la barra no salta.\n *\n * <kf-quote-picker [items]=\"quotes()\" [columns]=\"columns\" [idKey]=\"idKey\"\n * triggerSize=\"compact\" [inlinePanel]=\"false\" modalLayout=\"list\"\n * [selectedId]=\"id()\" [chips]=\"chips()\" [sortOptions]=\"sortOptions\"\n * [itemLabels]=\"{ singular: 'cotización', plural: 'cotizaciones' }\"\n * (selectedIdChange)=\"go($event)\" />\n *\n * ## `modalLayout` (modal de la variante `modal` y el de `inlinePanel` en false)\n * - `'table'` (default, comportamiento histórico): `kf-data-table` paginada\n * con toggle Tabla/Tarjetas. La fila/tarjeta de `selectedId` lleva\n * `aria-current=\"true\"` y fondo `primary-soft` (`currentRowKey`).\n * - `'list'`: lista de una línea por ítem con COLUMNAS ALINEADAS (CSS grid\n * + `subgrid`: cada pista mide lo mismo en todas las filas), sin paginar\n * ni toggle; se desplaza el cuerpo del modal. Orden de columnas: título\n * (`cardRole: 'title'`, mono) | primer campo (flexible, una línea con\n * elipsis y `title`) | resto de campos (`width` o su ancho de contenido;\n * `align: 'end'` para montos, cifras tabulares) | `status` (hasta\n * 13.75rem; el consumidor pasa `kf-badge truncate` con `title`) | check\n * de la fila actual. Cabecera de columnas discreta y fija al desplazar\n * (`listHeader`). Filas de 52px como mínimo; la de `selectedId` lleva\n * `aria-current=\"true\"`, fondo `primary-soft` y un check, y al abrir se\n * desplaza a la vista. Con la lista de hasta 560px de ancho (container\n * query, no viewport): 2 líneas (título + estado / campos), con el primer\n * campo en hasta 2 líneas.\n *\n * Límite conocido: sin virtualización. Cada fila es un `<button>` en el\n * DOM (búsqueda, foco y `aria-current` funcionan sin trucos); se probó\n * fluido con 120 filas y sigue usable con unos cientos. Para miles,\n * filtrar en el servidor antes de pasar `items`.\n *\n * En la variante modal, además: orden con `kf-select` estándar (ícono\n * `sort`, \"Ordenar por\"), chips con `aria-pressed`, buscador con\n * `searchAriaLabel` y foco inicial (`initialFocus` de `kf-modal`), conteo\n * en una región `aria-live=\"polite\"` (`itemLabels`), y estados\n * `loading` (spinner con `loadingLabel`) y `error` (mensaje + botón\n * \"Reintentar\" que emite `retry`) vía `kf-content-state`. El vacío \"Sin\n * resultados para esta búsqueda\" solo aparece sin carga ni error. Escape\n * con el panel del `kf-select` abierto cierra solo el select.\n *\n * <kf-quote-picker\n * [items]=\"quotes()\"\n * [columns]=\"columns\"\n * [selectedId]=\"selectedQuoteId()\"\n * [idKey]=\"(q) => q.id\"\n * [chips]=\"statusChips()\"\n * [cellTemplates]=\"{ photo: photoCell(), amount: amountCell() }\"\n * (selectedIdChange)=\"selectedQuoteId.set($event)\"\n * (expandToModal)=\"variant.set('modal'); open.set(true)\"\n * />\n */\n@Component({\n selector: 'kf-quote-picker',\n imports: [\n NgTemplateOutlet,\n FormsModule,\n Button,\n ContentState,\n FilterChips,\n Icon,\n Input,\n Modal,\n DataTable,\n EmptyState,\n Pagination,\n Select,\n Skeleton,\n Text,\n ],\n templateUrl: './QuotePicker.html',\n styleUrl: './QuotePicker.css',\n})\nexport class QuotePicker<T = unknown> {\n readonly items = input.required<T[]>();\n readonly columns = input.required<DataTableColumn[]>();\n readonly selectedId = input<string | null>(null);\n readonly idKey = input.required<(item: T) => string>();\n\n /**\n * Mapa `columnKey -> TemplateRef`, mismo mecanismo que `kf-data-table`\n * (`ngTemplateOutlet` + contexto `{ $implicit: item, index }`) — se\n * reenvía tal cual a la tabla interna del modo `modal`, y se usa\n * directamente en el grid de cards del modo `inline`. Un solo mapa para\n * ambos modos, consistente con la regla de \"una sola lógica interna\".\n */\n readonly cellTemplates = input<\n Record<string, TemplateRef<{ $implicit: T; index: number }>> | undefined\n >();\n\n readonly chips = input<QuotePickerChip<T>[]>([]);\n readonly sortOptions = input<QuotePickerSortOption[]>([]);\n readonly sort = model<string | null>(null);\n\n /**\n * Umbral de volumen alto — el consumidor decide el número exacto, nunca\n * hardcodeado a \"cotizaciones\" ni a ningún caso de uso puntual. Default\n * 15 según el diseño validado con mockups.\n */\n readonly expandThreshold = input(15);\n\n readonly variant = input<'inline' | 'modal'>('inline');\n /** Visibilidad del modo `modal`, two-way — mismo patrón que `[(open)]` de `kf-modal`. */\n readonly open = model(false);\n\n readonly title = input('Cambiar cotización');\n readonly searchPlaceholder = input('Buscar…');\n /** Ícono de placeholder cuando ninguna columna `cardRole: 'media'` resuelve\n * un thumbnail real vía `cellTemplates` — el picker no asume qué dominio\n * consume (cotización, vehículo, cliente...), así que no hardcodea un\n * ícono fijo. Default `'file'` solo por no dejar el input sin valor. */\n readonly placeholderIcon = input<IconName>('file');\n\n /** Disposición de la variante `modal`. Ver JSDoc de la clase. */\n readonly modalLayout = input<'table' | 'list'>('table');\n /** Nombre accesible del buscador. Default: `searchPlaceholder`. */\n readonly searchAriaLabel = input<string>();\n /** Estado de carga: spinner con `loadingLabel` en el modal y, con\n * `triggerSize=\"compact\"`, un esqueleto del trigger del mismo alto. */\n readonly loading = input(false);\n /** Texto del estado de carga. */\n readonly loadingLabel = input('Cargando…');\n /** Mensaje de error de la variante `modal`; con valor muestra el estado de error y \"Reintentar\". */\n readonly error = input<string | null>(null);\n\n /** Tamaño del trigger de la variante `inline`. Ver JSDoc de la clase. */\n readonly triggerSize = input<'default' | 'compact'>('default');\n /** Con `false`, el trigger abre directo el modal (sin panel inline). */\n readonly inlinePanel = input(true, { transform: booleanAttribute });\n /** Ancho máximo del modal (se topa con el viewport menos 32px). */\n readonly modalWidth = input('1040px');\n /** Sustantivo del conteo del encabezado. Default \"resultado/resultados\". */\n readonly itemLabels = input<QuotePickerItemLabels>({\n singular: 'resultado',\n plural: 'resultados',\n });\n /** Chip inicial \"sin filtro\" con el total. Vacío (`''`) lo oculta. */\n readonly allChipLabel = input('Todas');\n /** Nombre accesible del grupo de chips del modal. */\n readonly chipsAriaLabel = input('Filtrar resultados');\n /** Cabecera de columnas en `modalLayout=\"list\"` (solo visual). */\n readonly listHeader = input(true, { transform: booleanAttribute });\n\n readonly selectedIdChange = output<string>();\n /** \"Reintentar\" del estado de error. */\n readonly retry = output<void>();\n /** Disparado al superar `expandThreshold` en modo inline; el consumidor decide pasar a `modal`. */\n readonly expandToModal = output<void>();\n\n protected readonly searchQuery = signal('');\n protected readonly activeChip = signal<string | null>(null);\n protected readonly expanded = signal(false);\n protected readonly page = signal(1);\n protected readonly sortOpen = signal(false);\n\n /**\n * Mismo breakpoint (`max-width: 900px`) que el resto de la librería usa\n * para decisiones de layout en TypeScript (no solo CSS) — ver\n * `matchMediaSignal`. Decide 1 vs. 2 columnas en el grid inline, y tabla\n * vs. cards apiladas dentro del modal.\n */\n protected readonly isMobile = matchMediaSignal('(max-width: 900px)');\n /** Mismo corte que el modal a pantalla completa: chips en una sola línea. */\n protected readonly isNarrowViewport = matchMediaSignal('(max-width: 640px)');\n\n private readonly destroyRef = inject(DestroyRef);\n private readonly previewScrollEl = viewChild<ElementRef<HTMLElement>>('previewScroll');\n private readonly modalListEl = viewChild<ElementRef<HTMLElement>>('modalList');\n /** Para desplazar la fila actual a la vista UNA vez por apertura, no en cada render. */\n private scrolledToCurrent = false;\n\n /** Mismo mecanismo de fade que `kf-data-table` — ver comentario en QuotePicker.css. */\n protected readonly canFadeBottom = signal(false);\n\n readonly selectedItem = computed(() =>\n this.items().find((item) => this.idKey()(item) === this.selectedId()),\n );\n\n /** Filtro por texto (buscador propio) + filtro por chip activo, en ese orden. */\n protected readonly filteredItems = computed<T[]>(() => {\n const query = normalizeForSearch(this.searchQuery().trim());\n const chipValue = this.activeChip();\n const chip = chipValue ? this.chips().find((c) => c.value === chipValue) : undefined;\n const idKeyFn = this.idKey();\n const cols = this.columns();\n\n return this.items().filter((item) => {\n if (chip && !chip.predicate(item)) {\n return false;\n }\n if (!query) {\n return true;\n }\n const haystack = cols\n .map((column) => this.cellText(item, column))\n .concat(idKeyFn(item))\n .join(' ');\n return normalizeForSearch(haystack).includes(query);\n });\n });\n\n /**\n * Orden solo tiene efecto visible en modo `modal` (el diseño validado no\n * pide dropdown de orden en inline) — se calcula igual en ambos casos\n * porque es la MISMA lógica interna; en inline `sort()` simplemente se\n * queda en `null` salvo que el consumidor lo setee explícitamente.\n */\n protected readonly sortedItems = computed<T[]>(() => {\n const sortValue = this.sort();\n const items = this.filteredItems();\n if (!sortValue) {\n return items;\n }\n const [key, direction] = sortValue.split(':') as [string, 'asc' | 'desc' | undefined];\n const sorted = [...items].sort((a, b) => {\n const va = (a as Record<string, unknown>)[key];\n const vb = (b as Record<string, unknown>)[key];\n if (va === vb) {\n return 0;\n }\n return (va as string | number) > (vb as string | number) ? 1 : -1;\n });\n return direction === 'desc' ? sorted.reverse() : sorted;\n });\n\n /** Por encima del umbral, el preview inline se recorta salvo que el usuario ya haya expandido. */\n protected readonly isHighVolume = computed(\n () => this.sortedItems().length > this.expandThreshold(),\n );\n\n protected readonly previewItems = computed<T[]>(() => {\n const all = this.sortedItems();\n if (!this.isHighVolume() || this.expanded()) {\n return all;\n }\n return all.slice(0, PREVIEW_ROWS);\n });\n\n protected readonly pages = computed(() =>\n Math.max(Math.ceil(this.sortedItems().length / PAGE_SIZE), 1),\n );\n\n protected readonly pagedItems = computed<T[]>(() => {\n const start = (this.page() - 1) * PAGE_SIZE;\n return this.sortedItems().slice(start, start + PAGE_SIZE);\n });\n\n protected readonly resolvedSearchAriaLabel = computed(\n () => this.searchAriaLabel() ?? this.searchPlaceholder(),\n );\n\n /** Estado del cuerpo del modal para `kf-content-state`. */\n protected readonly modalState = computed<ContentStateKind>(() =>\n this.loading() ? 'loading' : this.error() ? 'error' : 'ready',\n );\n\n /**\n * Conteo del encabezado, en región `aria-live`: \"86 cotizaciones\" sin\n * filtros, \"12 de 86 cotizaciones\" con búsqueda o chip. Vacío mientras\n * carga o con error.\n */\n protected readonly resultsLabel = computed(() => {\n if (this.modalState() !== 'ready') {\n return '';\n }\n const total = this.items().length;\n const shown = this.sortedItems().length;\n const { singular, plural } = this.itemLabels();\n const noun = total === 1 ? singular : plural;\n return shown === total ? `${total} ${noun}` : `${shown} de ${total} ${noun}`;\n });\n\n /** Chips del modal en el formato de `kf-filter-chips`, con \"Todas\" al inicio. */\n protected readonly chipOptions = computed<FilterChipOption[]>(() => {\n const chips = this.chips().map((chip) => ({\n value: chip.value,\n label: chip.label,\n count: chip.count,\n }));\n const allLabel = this.allChipLabel();\n return allLabel\n ? [{ value: '', label: allLabel, count: this.items().length }, ...chips]\n : chips;\n });\n\n /**\n * Pistas de la grilla de `modalLayout=\"list\"`, en el orden visual: título,\n * primer campo (flexible), resto, estados y el check. Todas las filas\n * comparten estas pistas vía `subgrid`, por eso las columnas alinean.\n */\n protected readonly listGridColumns = computed(() => {\n const tracks: string[] = [];\n const titleCol = this.titleColumn();\n const primary = this.primaryFieldColumn();\n if (titleCol) {\n tracks.push(titleCol.width ?? 'max-content');\n }\n if (primary) {\n tracks.push(primary.width ?? 'minmax(0, 1fr)');\n }\n for (const col of this.restFieldColumns()) {\n tracks.push(\n col.width ?? (col.truncate ? `minmax(0, ${col.maxWidth ?? 'max-content'})` : 'max-content'),\n );\n }\n for (const col of this.statusColumns()) {\n tracks.push(col.width ?? `fit-content(${col.maxWidth ?? '13.75rem'})`);\n }\n tracks.push('1.25rem');\n return tracks.join(' ');\n });\n\n protected readonly sortSelectOptions = computed<SelectOption[]>(() =>\n this.sortOptions().map((option) => ({ value: option.value, label: option.label })),\n );\n\n protected readonly statusColumns = computed(() =>\n this.columns().filter((c) => c.cardRole === 'status'),\n );\n /** Primer campo (ej. modelo): ocupa el espacio libre de la fila en `modalLayout=\"list\"`. */\n protected readonly primaryFieldColumn = computed(() => this.fieldColumns()[0]);\n protected readonly restFieldColumns = computed(() => this.fieldColumns().slice(1));\n\n /** Alineada al final: `align: 'end'` o el histórico `right: true`. */\n protected isEndAligned(column: DataTableColumn): boolean {\n return column.align === 'end' || !!column.right;\n }\n\n /** `title` con el valor completo de una celda que puede cortarse con elipsis. */\n protected cellTitle(item: T, column: DataTableColumn): string | null {\n return this.cellText(item, column) || null;\n }\n\n protected isSelected(item: T): boolean {\n return this.idKey()(item) === this.selectedId();\n }\n\n protected readonly sortLabel = computed(() => {\n const current = this.sortOptions().find((option) => option.value === this.sort());\n return current?.label ?? 'Ordenar por';\n });\n\n constructor() {\n afterRenderEffect(() => {\n const list = this.modalListEl()?.nativeElement;\n if (!this.open() || !list) {\n this.scrolledToCurrent = false;\n return;\n }\n untracked(() => {\n if (this.scrolledToCurrent) {\n return;\n }\n this.scrolledToCurrent = true;\n list\n .querySelector<HTMLElement>('.kf-quote-picker__row--current')\n ?.scrollIntoView?.({ block: 'nearest' });\n });\n });\n\n afterNextRender(() => {\n const el = this.previewScrollEl()?.nativeElement;\n if (!el) {\n return;\n }\n const update = () => this.updateFadeState(el);\n update();\n el.addEventListener('scroll', update, { passive: true });\n const observer = new ResizeObserver(update);\n observer.observe(el);\n this.destroyRef.onDestroy(() => {\n el.removeEventListener('scroll', update);\n observer.disconnect();\n });\n });\n }\n\n private updateFadeState(el: HTMLElement): void {\n // 1px de margen por el mismo motivo que en DataTable: subpíxeles de\n // scroll dejarían el fade \"prendido\" en un preview que ya llegó al final.\n this.canFadeBottom.set(el.scrollHeight - el.clientHeight - el.scrollTop > 1);\n }\n\n private cellText(item: T, column: DataTableColumn): string {\n const value = (item as Record<string, unknown>)[column.key];\n return value === null || value === undefined ? '' : String(value);\n }\n\n toggleExpandedPanel(): void {\n this.expanded.set(!this.expanded());\n }\n\n /** Click en el trigger: alterna el panel inline o, sin él, abre el modal. */\n protected onTriggerClick(): void {\n if (this.inlinePanel()) {\n this.toggleExpandedPanel();\n } else {\n this.open.set(true);\n }\n }\n\n onSearchInput(event: Event): void {\n this.onSearchChange((event.target as HTMLInputElement).value);\n }\n\n /** Buscador del modal (`kf-input` con `ngModel`), incluido el botón \"×\". */\n protected onSearchChange(value: string): void {\n this.searchQuery.set(value ?? '');\n this.page.set(1);\n }\n\n selectChip(value: string): void {\n this.activeChip.set(this.activeChip() === value ? null : value);\n this.page.set(1);\n }\n\n /** Chips del modal: `''` es \"Todas\" (sin filtro). */\n protected onChipChange(value: string): void {\n this.activeChip.set(value || null);\n this.page.set(1);\n }\n\n select(item: T): void {\n const id = this.idKey()(item);\n // El panel se cierra siempre al elegir (haya cambiado el id o no) —\n // mismo comportamiento esperado de cualquier selector, ej. `kf-select`\n // cierra su panel al elegir opción; dejarle esa responsabilidad al\n // consumidor sería una carga que ningún otro componente de la\n // librería le pide.\n this.expanded.set(false);\n // El modal también se cierra al elegir: el consumidor ya no necesita\n // cerrarlo a mano en `selectedIdChange` (hacerlo igual es inocuo).\n this.open.set(false);\n if (id === this.selectedId()) {\n return;\n }\n this.selectedIdChange.emit(id);\n }\n\n onItemKeydown(event: KeyboardEvent, item: T): void {\n if (event.key === 'Enter') {\n event.preventDefault();\n this.select(item);\n }\n }\n\n onSeeAll(): void {\n this.expandToModal.emit();\n }\n\n onTableRowClick(event: { row: T; index: number }): void {\n this.select(event.row);\n }\n\n /** @deprecated El orden de la variante modal ahora es un `kf-select`; este método ya no lo usa la plantilla. */\n toggleSort(): void {\n this.sortOpen.update((open) => !open);\n }\n\n protected onSortChange(value: string): void {\n this.sort.set(value);\n }\n\n /** Alterna el orden (elegir el vigente lo quita). Se conserva por compatibilidad. */\n setSort(value: string): void {\n this.sort.set(this.sort() === value ? null : value);\n this.sortOpen.set(false);\n }\n\n trackItem(item: T, index: number): string | number {\n const idKeyFn = this.idKey();\n return idKeyFn ? idKeyFn(item) : index;\n }\n\n /** Arrow function como campo (no un método) para que `[rowKey]` reciba\n * una referencia ESTABLE entre change detections — `trackItem.bind(this)`\n * en el template recrearía una función nueva en cada ciclo, invalidando\n * cualquier optimización de `kf-data-table` que dependa de identidad. */\n protected readonly rowKeyFn = (item: T, index: number): string | number =>\n this.trackItem(item, index);\n\n protected cellValue(item: T, column: DataTableColumn): string {\n return this.cellText(item, column);\n }\n\n protected readonly mediaColumn = computed(() =>\n this.columns().find((c) => c.cardRole === 'media'),\n );\n protected readonly titleColumn = computed(() =>\n this.columns().find((c) => c.cardRole === 'title'),\n );\n protected readonly fieldColumns = computed(() =>\n this.columns().filter((c) => !c.cardRole || c.cardRole === 'field'),\n );\n}\n","@if (variant() === 'inline') {\n <div class=\"kf-quote-picker__inline\">\n <!-- Trigger colapsado. `default`: tarjeta a ancho completo con miniatura\n (histórico). `compact`: control de barra de herramientas de alto fijo,\n sin miniatura. Con `inlinePanel` en false abre directo el modal. -->\n @if (triggerSize() === 'compact' && loading()) {\n <!-- Mismo alto que el trigger real: la barra no salta al llegar los datos. -->\n <div\n class=\"kf-quote-picker__trigger kf-quote-picker__trigger--compact kf-quote-picker__trigger--loading\"\n role=\"status\"\n aria-busy=\"true\"\n >\n <span class=\"kf-quote-picker__sr-only\">{{ loadingLabel() }}</span>\n <span class=\"kf-quote-picker__compact\" aria-hidden=\"true\">\n <kf-skeleton width=\"35%\" height=\"12px\" />\n <kf-skeleton width=\"65%\" height=\"12px\" />\n </span>\n </div>\n } @else {\n <button\n type=\"button\"\n class=\"kf-quote-picker__trigger\"\n [class.kf-quote-picker__trigger--compact]=\"triggerSize() === 'compact'\"\n [attr.aria-expanded]=\"inlinePanel() ? expanded() : open()\"\n [attr.aria-haspopup]=\"inlinePanel() ? null : 'dialog'\"\n (click)=\"onTriggerClick()\"\n >\n @if (triggerSize() === 'compact') {\n <!-- Nombre accesible = texto visible con un prefijo y comas solo\n para lectores de pantalla: \"Cambiar cotización. Actual: <id>,\n <estado>, <modelo>\". -->\n <span class=\"kf-quote-picker__sr-only\">{{ title() }}. Actual: </span>\n @if (selectedItem(); as item) {\n <span class=\"kf-quote-picker__compact\">\n <span class=\"kf-quote-picker__compact-line\">\n @if (titleColumn(); as titleCol) {\n <span class=\"kf-quote-picker__compact-id\">{{ cellValue(item, titleCol) }}</span>\n }\n @for (col of statusColumns(); track col.key) {\n <span class=\"kf-quote-picker__sr-only\">, </span>\n <span class=\"kf-quote-picker__compact-status\">\n <ng-container\n *ngTemplateOutlet=\"cell; context: { $implicit: item, column: col, index: 0 }\"\n />\n </span>\n }\n </span>\n @if (primaryFieldColumn(); as primary) {\n <span class=\"kf-quote-picker__compact-line\">\n <span class=\"kf-quote-picker__sr-only\">, </span>\n <span class=\"kf-quote-picker__compact-primary\">{{\n cellValue(item, primary)\n }}</span>\n </span>\n }\n </span>\n } @else {\n <span class=\"kf-quote-picker__compact kf-quote-picker__trigger-summary--empty\"\n >Sin selección</span\n >\n }\n <kf-icon\n name=\"chevron-down\"\n size=\"sm\"\n class=\"kf-quote-picker__chevron\"\n [class.kf-quote-picker__chevron--open]=\"inlinePanel() && expanded()\"\n />\n } @else {\n <span class=\"kf-quote-picker__thumb\">\n @if (mediaColumn(); as media) {\n @if (cellTemplates()?.[media.key]; as template) {\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"{ $implicit: selectedItem(), index: 0 }\"\n />\n }\n } @else {\n <kf-icon [name]=\"placeholderIcon()\" size=\"md\" />\n }\n </span>\n @if (selectedItem(); as item) {\n <span class=\"kf-quote-picker__trigger-summary\">\n @if (titleColumn(); as title) {\n <span\n class=\"kf-quote-picker__trigger-field kf-quote-picker__trigger-field--title\"\n >{{ cellValue(item, title) }}</span\n >\n }\n <!--\n En mobile solo se muestra el título (ID) — mostrar los 5 campos\n en una sola línea de ~90px de ancho real corta el texto sin\n elipsis a mitad del segundo campo (bug real medido:\n scrollWidth=519 vs. clientWidth=87 en 390px). El resto de los\n campos siguen disponibles en el panel expandido y en el modal,\n donde sí hay espacio horizontal.\n -->\n @if (!isMobile()) {\n @for (col of fieldColumns(); track col.key) {\n <span class=\"kf-quote-picker__trigger-sep\" aria-hidden=\"true\">·</span>\n <span class=\"kf-quote-picker__trigger-field\">{{ cellValue(item, col) }}</span>\n }\n }\n </span>\n } @else {\n <span class=\"kf-quote-picker__trigger-summary kf-quote-picker__trigger-summary--empty\"\n >Sin selección</span\n >\n }\n <span class=\"kf-quote-picker__trigger-action\">\n {{ inlinePanel() && expanded() ? 'Cerrar' : title() }}\n <kf-icon\n name=\"chevron-down\"\n size=\"sm\"\n class=\"kf-quote-picker__chevron\"\n [class.kf-quote-picker__chevron--open]=\"inlinePanel() && expanded()\"\n />\n </span>\n }\n </button>\n }\n\n @if (inlinePanel() && expanded()) {\n <div class=\"kf-quote-picker__panel\">\n <div class=\"kf-quote-picker__toolbar\">\n <div class=\"kf-quote-picker__search\">\n <kf-icon name=\"search\" size=\"sm\" />\n <input\n type=\"text\"\n class=\"kf-quote-picker__search-input\"\n [placeholder]=\"searchPlaceholder()\"\n [attr.aria-label]=\"resolvedSearchAriaLabel()\"\n [value]=\"searchQuery()\"\n (input)=\"onSearchInput($event)\"\n />\n </div>\n @for (chip of chips(); track chip.value) {\n <button\n type=\"button\"\n class=\"kf-quote-picker__chip\"\n [class.kf-quote-picker__chip--active]=\"activeChip() === chip.value\"\n [attr.aria-pressed]=\"activeChip() === chip.value\"\n (click)=\"selectChip(chip.value)\"\n >\n {{ chip.label }} ({{ chip.count }})\n </button>\n }\n </div>\n\n <div class=\"kf-quote-picker__results-wrap\">\n <div #previewScroll class=\"kf-quote-picker__results\" role=\"listbox\">\n @for (item of previewItems(); track trackItem(item, $index)) {\n <button\n type=\"button\"\n class=\"kf-quote-picker__result\"\n [class.kf-quote-picker__result--active]=\"idKey()(item) === selectedId()\"\n role=\"option\"\n [attr.aria-selected]=\"idKey()(item) === selectedId()\"\n (click)=\"select(item)\"\n (keydown)=\"onItemKeydown($event, item)\"\n >\n <span class=\"kf-quote-picker__thumb kf-quote-picker__thumb--sm\">\n @if (mediaColumn(); as media) {\n @if (cellTemplates()?.[media.key]; as template) {\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"{ $implicit: item, index: $index }\"\n />\n }\n } @else {\n <kf-icon [name]=\"placeholderIcon()\" size=\"sm\" />\n }\n </span>\n @if (titleColumn(); as title) {\n <span\n class=\"kf-quote-picker__result-field kf-quote-picker__result-field--title\"\n >{{ cellValue(item, title) }}</span\n >\n }\n <!--\n Wrapper propio (no los spans sueltos) para los campos\n secundarios: en mobile necesita saltar de línea COMPLETO\n (mismo criterio que \"unidades\" no debe competir con\n \"modelo\" en la primera línea) — `flex-basis: 100%` en un\n solo elemento fuerza ese salto sin tener que asumir cuál\n de los N campos genéricos es el más corto o el más largo.\n -->\n <span class=\"kf-quote-picker__result-fields\">\n @for (col of fieldColumns(); track col.key; let first = $first) {\n <span\n class=\"kf-quote-picker__result-field\"\n [class.kf-quote-picker__result-field--primary]=\"first\"\n >{{ cellValue(item, col) }}</span\n >\n }\n </span>\n </button>\n } @empty {\n <p class=\"kf-quote-picker__empty\">Sin resultados para esta búsqueda.</p>\n }\n </div>\n @if (canFadeBottom()) {\n <div class=\"kf-quote-picker__fade\" aria-hidden=\"true\"></div>\n }\n </div>\n\n @if (isHighVolume()) {\n <button type=\"button\" class=\"kf-quote-picker__see-all\" (click)=\"onSeeAll()\">\n Ver las {{ sortedItems().length }} en pantalla completa\n </button>\n }\n </div>\n }\n </div>\n}\n\n<!-- Modal: la variante `modal` y el que abre el trigger con `inlinePanel` en\n false. Zona de filtros FIJA (slot `kf-modal-toolbar`) y lista\n desplazable (cuerpo del modal). -->\n@if (variant() === 'modal' || !inlinePanel()) {\n <kf-modal\n class=\"kf-quote-picker__modal\"\n [(open)]=\"open\"\n [title]=\"title()\"\n [dismissible]=\"true\"\n [width]=\"modalWidth()\"\n maxHeight=\"85vh\"\n fullscreenOnMobile\n initialFocus=\".kf-quote-picker__modal-search\"\n >\n <p kf-modal-meta class=\"kf-quote-picker__count\" aria-live=\"polite\">{{ resultsLabel() }}</p>\n\n <div kf-modal-toolbar class=\"kf-quote-picker__filters\">\n <div class=\"kf-quote-picker__filters-row\">\n <kf-input\n class=\"kf-quote-picker__modal-search\"\n type=\"search\"\n icon=\"search\"\n clearable\n [placeholder]=\"searchPlaceholder()\"\n [ariaLabel]=\"resolvedSearchAriaLabel()\"\n [ngModel]=\"searchQuery()\"\n (ngModelChange)=\"onSearchChange($event)\"\n />\n @if (sortOptions().length > 0) {\n <kf-select\n class=\"kf-quote-picker__sort\"\n icon=\"sort\"\n ariaLabel=\"Ordenar por\"\n panelTitle=\"Ordenar por\"\n placeholder=\"Ordenar por\"\n [options]=\"sortSelectOptions()\"\n [value]=\"sort() ?? undefined\"\n (valueChange)=\"onSortChange($event)\"\n />\n }\n </div>\n @if (chips().length > 0) {\n <kf-filter-chips\n class=\"kf-quote-picker__chips\"\n deselectable\n [ariaLabel]=\"chipsAriaLabel()\"\n [options]=\"chipOptions()\"\n [value]=\"activeChip() ?? ''\"\n [layout]=\"isNarrowViewport() ? 'scroll' : 'wrap'\"\n (valueChange)=\"onChipChange($event)\"\n />\n }\n </div>\n\n <kf-content-state\n [state]=\"modalState()\"\n load=\"spinner\"\n [loadingLabel]=\"loadingLabel()\"\n [title]=\"error() ?? ''\"\n >\n <kf-button actions type=\"button\" variant=\"outline\" icon=\"refresh\" (click)=\"retry.emit()\">\n Reintentar\n </kf-button>\n @if (modalLayout() === 'list') {\n @if (sortedItems().length > 0) {\n <div class=\"kf-quote-picker__list-wrap\">\n <ul\n #modalList\n class=\"kf-quote-picker__list\"\n [style.grid-template-columns]=\"listGridColumns()\"\n >\n @if (listHeader()) {\n <!-- Cabecera visual de columnas: cada fila (botón) ya se anuncia\n completa, así que para lectores de pantalla sería ruido. -->\n <li class=\"kf-quote-picker__list-head\" aria-hidden=\"true\">\n @if (titleColumn(); as titleCol) {\n <span class=\"kf-quote-picker__head-cell kf-quote-picker__cell--title\">\n <kf-text as=\"span\" variant=\"overline\">{{ titleCol.label }}</kf-text>\n </span>\n }\n @if (primaryFieldColumn(); as primary) {\n <span class=\"kf-quote-picker__head-cell kf-quote-picker__cell--primary\">\n <kf-text as=\"span\" variant=\"overline\">{{ primary.label }}</kf-text>\n </span>\n }\n @for (col of restFieldColumns(); track col.key) {\n <span\n class=\"kf-quote-picker__head-cell kf-quote-picker__cell--field\"\n [class.kf-quote-picker__cell--end]=\"isEndAligned(col)\"\n [class.kf-quote-picker__cell--center]=\"col.align === 'center'\"\n >\n <kf-text as=\"span\" variant=\"overline\">{{ col.label }}</kf-text>\n </span>\n }\n @for (col of statusColumns(); track col.key) {\n <span class=\"kf-quote-picker__head-cell kf-quote-picker__cell--status\">\n <kf-text as=\"span\" variant=\"overline\">{{ col.label }}</kf-text>\n </span>\n }\n <span class=\"kf-quote-picker__head-cell kf-quote-picker__cell--check\"></span>\n </li>\n }\n @for (item of sortedItems(); track trackItem(item, $index); let i = $index) {\n <li class=\"kf-quote-picker__list-item\">\n <button\n type=\"button\"\n class=\"kf-quote-picker__row\"\n [class.kf-quote-picker__row--current]=\"isSelected(item)\"\n [attr.aria-current]=\"isSelected(item) ? 'true' : null\"\n (click)=\"select(item)\"\n >\n <span class=\"kf-quote-picker__row-head\">\n @if (titleColumn(); as titleCol) {\n <span class=\"kf-quote-picker__row-title kf-quote-picker__cell--title\">\n <ng-container\n *ngTemplateOutlet=\"\n cell;\n context: { $implicit: item, column: titleCol, index: i }\n \"\n />\n </span>\n }\n @for (col of statusColumns(); track col.key) {\n <span class=\"kf-quote-picker__row-status kf-quote-picker__cell--status\">\n <ng-container\n *ngTemplateOutlet=\"\n cell;\n context: { $implicit: item, column: col, index: i }\n \"\n />\n </span>\n }\n </span>\n <span class=\"kf-quote-picker__row-body\">\n @if (primaryFieldColumn(); as primary) {\n <span\n class=\"kf-quote-picker__row-primary kf-quote-picker__cell--primary\"\n [attr.title]=\"cellTitle(item, primary)\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n cell;\n context: { $implicit: item, column: primary, index: i }\n \"\n />\n </span>\n }\n @for (col of restFieldColumns(); track col.key) {\n <span\n class=\"kf-quote-picker__row-field kf-quote-picker__cell--field\"\n [class.kf-quote-picker__row-field--right]=\"isEndAligned(col)\"\n [class.kf-quote-picker__cell--end]=\"isEndAligned(col)\"\n [class.kf-quote-picker__cell--center]=\"col.align === 'center'\"\n [class.kf-quote-picker__cell--truncate]=\"col.truncate\"\n [attr.title]=\"col.truncate ? cellTitle(item, col) : null\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n cell;\n context: { $implicit: item, column: col, index: i }\n \"\n />\n </span>\n }\n </span>\n <span class=\"kf-quote-picker__row-check kf-quote-picker__cell--check\">\n @if (isSelected(item)) {\n <kf-icon name=\"check\" size=\"sm\" />\n }\n </span>\n </button>\n </li>\n }\n </ul>\n </div>\n } @else {\n <kf-empty-state icon=\"file\">Sin resultados para esta búsqueda.</kf-empty-state>\n }\n } @else {\n <kf-data-table\n [columns]=\"columns()\"\n [rows]=\"pagedItems()\"\n [cardable]=\"true\"\n [defaultView]=\"isMobile() ? 'cards' : 'table'\"\n [cellTemplates]=\"cellTemplates()\"\n [rowKey]=\"rowKeyFn\"\n [currentRowKey]=\"selectedId()\"\n (rowClick)=\"onTableRowClick($event)\"\n >\n <kf-empty-state empty icon=\"file\">Sin resultados para esta búsqueda.</kf-empty-state>\n @if (sortedItems().length > 0) {\n <kf-pagination footer [page]=\"page()\" [pages]=\"pages()\" (pageChange)=\"page.set($event)\">\n {{ sortedItems().length }} resultados\n </kf-pagination>\n }\n </kf-data-table>\n }\n </kf-content-state>\n </kf-modal>\n}\n\n<!-- Celda de la lista compacta: el template del consumidor si existe (badge,\n monto formateado), si no el valor como texto. -->\n<ng-template #cell let-item let-column=\"column\" let-index=\"index\">\n @if (cellTemplates()?.[column.key]; as template) {\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"{ $implicit: item, index: index }\"\n />\n } @else {\n {{ cellValue(item, column) }}\n }\n</ng-template>\n","import { booleanAttribute, Component, input, output } from '@angular/core';\nimport { Icon, Link } from '@kaufmann-lab/ui/core';\n\n/**\n * Estado vacío de reservas en taller con llamada a agendar (página 36):\n * barra de estado vacío arriba (\"No tienes reservas de taller\"), panel de\n * invitación al medio (ícono en círculo azul, título, descripción, link) y\n * una fila de dos acciones al pie — un slot `[actions]` proyectado, para no\n * acoplar el componente a botones fijos.\n *\n * Distinto de `kf-empty-state` genérico: este combina la barra + la\n * invitación + las acciones como un bloque compuesto propio del dominio\n * \"taller\", no un placeholder de una sola pieza.\n *\n * `grow` estira el panel de invitación para llenar el espacio vertical\n * disponible — solo cuando el consumidor comparte fila con una tarjeta más\n * alta (ej. junto a \"Total de vehículos\"); en un lugar sin esa presión\n * (home, debajo del carousel) se deja en su alto natural.\n *\n * <kf-reserve-block emptyLabel=\"No tienes reservas de taller\" grow\n * title=\"¿Necesitas mantención?\" description=\"Tenemos la mejor red de talleres.\"\n * actionLabel=\"Agenda tu reserva aquí\" actionHref=\"/taller/agendar\">\n * <kf-button actions icon=\"calendar\">Reservar hora</kf-button>\n * <kf-button actions variant=\"outline\" icon=\"list\">Ver agenda</kf-button>\n * </kf-reserve-block>\n *\n * Para apps con router: escuchar `actionClick` y llamar\n * `event.preventDefault()` antes de `router.navigateByUrl(...)`. El\n * `actionHref` se mantiene igual para que click-medio, \"abrir en pestaña\n * nueva\" y el hover de la barra de estado sigan funcionando.\n *\n * <kf-reserve-block title=\"¿Necesitas mantención?\" actionLabel=\"Agenda tu reserva aquí\"\n * actionHref=\"/taller/agendar\"\n * (actionClick)=\"$event.preventDefault(); router.navigateByUrl('/taller/agendar')\" />\n */\n@Component({\n selector: 'kf-reserve-block',\n imports: [Icon, Link],\n templateUrl: './ReserveBlock.html',\n styleUrl: './ReserveBlock.css',\n})\nexport class ReserveBlock {\n readonly emptyLabel = input('No tienes reservas de taller');\n readonly title = input.required<string>();\n readonly description = input<string>();\n readonly actionLabel = input<string>();\n readonly actionHref = input<string>();\n /** La invitación se estira para llenar la tarjeta (ej. junto a \"Total de vehículos\"). */\n readonly grow = input(false, { transform: booleanAttribute });\n\n /**\n * Click en el link de la invitación. Incluye el `MouseEvent` para que un\n * consumidor con router pueda cortar la navegación nativa — mismo patrón\n * que `itemClick` de `kf-breadcrumb`, sin depender de `@angular/router`.\n */\n readonly actionClick = output<MouseEvent>();\n}\n","<div class=\"kf-reserve-block__empty\">\n <kf-icon name=\"calendar\" size=\"sm\" />\n <span>{{ emptyLabel() }}</span>\n</div>\n<div class=\"kf-reserve-block__invite\" [class.kf-reserve-block__invite--grow]=\"grow()\">\n <span class=\"kf-reserve-block__invite-icon\">\n <kf-icon name=\"tool\" size=\"md\" />\n </span>\n <div class=\"kf-reserve-block__invite-text\">\n <span class=\"kf-reserve-block__invite-title\">{{ title() }}</span>\n @if (description()) {\n <span class=\"kf-reserve-block__invite-description\">{{ description() }}</span>\n }\n @if (actionLabel()) {\n <kf-link\n class=\"kf-reserve-block__invite-action\"\n [href]=\"actionHref() || '#'\"\n showArrow\n (click)=\"actionClick.emit($event)\"\n >\n {{ actionLabel() }}\n </kf-link>\n }\n </div>\n</div>\n<div class=\"kf-reserve-block__actions\">\n <ng-content select=\"[actions]\" />\n</div>\n","import { Component, input } from '@angular/core';\nimport { Icon, IconName, Text } from '@kaufmann-lab/ui/core';\n\n/**\n * Estado puntual mostrado junto a la identidad del vehículo (ej. \"En ruta\",\n * \"Mantenimiento\", \"Fuera de servicio\"). `tone` define el color semántico:\n * \"crit\" no tiene token propio en base.css, se mapea a var(--kf-color-error).\n */\nexport interface VehicleHeaderStatus {\n label: string;\n tone?: 'ok' | 'warn' | 'crit';\n icon?: IconName;\n}\n\n/**\n * Header de identidad de un vehículo de flota: unidad (patente/id), modelo\n * (como badge, no texto plano — página 24: \"ABC-123\" junto a un badge\n * \"TITAN 4X2\"), VIN en fuente mono y un estado opcional. Un área de acciones\n * opcional se proyecta vía `<ng-content select=\"[actions]\">` para no acoplar\n * el componente a un set fijo de botones — el patrón real de la spec es\n * `kf-button variant=\"outline\"` (ej. \"Llamar\", con ícono) + un `primary`\n * (ej. \"Crear Ticket\", con ícono \"+\"):\n *\n * <kf-vehicle-header unit=\"AB123CD\" model=\"Sprinter 415\" vin=\"9BW...\"\n * [status]=\"{ label: 'En ruta', tone: 'ok' }\">\n * <kf-button actions variant=\"outline\" icon=\"phone\">Llamar</kf-button>\n * <kf-button actions icon=\"plus\">Crear Ticket</kf-button>\n * </kf-vehicle-header>\n */\n@Component({\n selector: 'kf-vehicle-header',\n imports: [Icon, Text],\n templateUrl: './VehicleHeader.html',\n styleUrl: './VehicleHeader.css',\n})\nexport class VehicleHeader {\n readonly unit = input.required<string>();\n readonly model = input<string>();\n readonly vin = input<string>();\n readonly status = input<VehicleHeaderStatus>();\n}\n","<div class=\"kf-vehicle-header__identity\">\n <span class=\"kf-vehicle-header__unit\">{{ unit() }}</span>\n @if (model()) {\n <span class=\"kf-vehicle-header__model\">\n <kf-text as=\"span\" variant=\"overline-strong\">{{ model() }}</kf-text>\n </span>\n }\n @if (vin()) {\n <span class=\"kf-vehicle-header__vin\">VIN: {{ vin() }}</span>\n }\n</div>\n\n@if (status(); as currentStatus) {\n <span\n class=\"kf-vehicle-header__status\"\n [class]=\"'kf-vehicle-header__status--' + (currentStatus.tone ?? 'ok')\"\n >\n @if (currentStatus.icon; as iconName) {\n <kf-icon [name]=\"iconName\" size=\"sm\" />\n }\n {{ currentStatus.label }}\n </span>\n}\n\n<div class=\"kf-vehicle-header__actions\">\n <ng-content select=\"[actions]\" />\n</div>\n","/*\n * Public API Surface of ui/business — entry point secundario, `@kaufmann-lab/ui/business`.\n *\n * Componentes que modelan un concepto de negocio real de Kaufmann (una\n * cotización, una reserva de taller, un vehículo de flota, la empresa activa\n * de una sesión), no una preocupación de UI transversal — ver\n * `ENTRY-POINTS.md` en la raíz del repo para el criterio.\n *\n * Consume sus piezas base (`Icon`, `Text`, `Select`, `DataTable`, etc.) desde\n * `'@kaufmann-lab/ui/core'` y los helpers desde `'@kaufmann-lab/ui/shared'`,\n * nunca desde la raíz `'@kaufmann-lab/ui'` (agregador que depende de todos\n * los entry points — importarla desde acá cerraría un ciclo) ni por ruta\n * relativa cruzando la frontera entre entry points (ng-packagr calcula un\n * `rootDir` propio por entry point y rechaza archivos fuente fuera de él).\n *\n * La raíz `'@kaufmann-lab/ui'` los reexporta, así que\n * `import { QuotePicker } from '@kaufmann-lab/ui'` sigue funcionando igual.\n */\n\nexport * from './lib/company-selector/CompanySelector';\nexport * from './lib/quote-picker/QuotePicker';\nexport * from './lib/reserve-block/ReserveBlock';\nexport * from './lib/vehicle-header/VehicleHeader';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|