@kaufmann-lab/ui 0.1.21 → 0.1.22
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.
|
@@ -580,7 +580,7 @@ class QuotePicker {
|
|
|
580
580
|
fieldColumns = computed(() => this.columns().filter((c) => !c.cardRole || c.cardRole === 'field'), /* @ts-ignore */
|
|
581
581
|
...(ngDevMode ? [{ debugName: "fieldColumns" }] : /* istanbul ignore next */ []));
|
|
582
582
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: QuotePicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
583
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: QuotePicker, isStandalone: true, selector: "kf-quote-picker", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, selectedId: { classPropertyName: "selectedId", publicName: "selectedId", isSignal: true, isRequired: false, transformFunction: null }, idKey: { classPropertyName: "idKey", publicName: "idKey", isSignal: true, isRequired: true, transformFunction: null }, cellTemplates: { classPropertyName: "cellTemplates", publicName: "cellTemplates", isSignal: true, isRequired: false, transformFunction: null }, chips: { classPropertyName: "chips", publicName: "chips", isSignal: true, isRequired: false, transformFunction: null }, sortOptions: { classPropertyName: "sortOptions", publicName: "sortOptions", isSignal: true, isRequired: false, transformFunction: null }, sort: { classPropertyName: "sort", publicName: "sort", isSignal: true, isRequired: false, transformFunction: null }, expandThreshold: { classPropertyName: "expandThreshold", publicName: "expandThreshold", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, placeholderIcon: { classPropertyName: "placeholderIcon", publicName: "placeholderIcon", isSignal: true, isRequired: false, transformFunction: null }, modalLayout: { classPropertyName: "modalLayout", publicName: "modalLayout", isSignal: true, isRequired: false, transformFunction: null }, searchAriaLabel: { classPropertyName: "searchAriaLabel", publicName: "searchAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, loadingLabel: { classPropertyName: "loadingLabel", publicName: "loadingLabel", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, triggerSize: { classPropertyName: "triggerSize", publicName: "triggerSize", isSignal: true, isRequired: false, transformFunction: null }, inlinePanel: { classPropertyName: "inlinePanel", publicName: "inlinePanel", isSignal: true, isRequired: false, transformFunction: null }, modalWidth: { classPropertyName: "modalWidth", publicName: "modalWidth", isSignal: true, isRequired: false, transformFunction: null }, itemLabels: { classPropertyName: "itemLabels", publicName: "itemLabels", isSignal: true, isRequired: false, transformFunction: null }, allChipLabel: { classPropertyName: "allChipLabel", publicName: "allChipLabel", isSignal: true, isRequired: false, transformFunction: null }, chipsAriaLabel: { classPropertyName: "chipsAriaLabel", publicName: "chipsAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, listHeader: { classPropertyName: "listHeader", publicName: "listHeader", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sort: "sortChange", open: "openChange", selectedIdChange: "selectedIdChange", retry: "retry", expandToModal: "expandToModal" }, viewQueries: [{ propertyName: "previewScrollEl", first: true, predicate: ["previewScroll"], descendants: true, isSignal: true }, { propertyName: "modalListEl", first: true, predicate: ["modalList"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (variant() === 'inline') {\n <div class=\"kf-quote-picker__inline\">\n <!-- Trigger colapsado. `default`: tarjeta a ancho completo con miniatura\n (hist\u00F3rico). `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\u00F3n. 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\u00F3n</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\u00EDtulo (ID) \u2014 mostrar los 5 campos\n en una sola l\u00EDnea 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\u00ED 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\">\u00B7</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\u00F3n</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\u00EDnea COMPLETO\n (mismo criterio que \"unidades\" no debe competir con\n \"modelo\" en la primera l\u00EDnea) \u2014 `flex-basis: 100%` en un\n solo elemento fuerza ese salto sin tener que asumir cu\u00E1l\n de los N campos gen\u00E9ricos es el m\u00E1s corto o el m\u00E1s 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\u00FAsqueda.</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\u00F3n) ya se anuncia\n completa, as\u00ED que para lectores de pantalla ser\u00EDa 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\u00FAsqueda.</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\u00FAsqueda.</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", styles: [":host{display:block;min-width:0;font-family:var(--kf-font-body)}.kf-quote-picker__sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.kf-quote-picker__trigger{box-sizing:border-box;display:flex;align-items:center;gap:var(--kf-space-md);width:100%;padding:var(--kf-space-sm) var(--kf-space-md);background:var(--kf-color-white);border:1.5px solid var(--kf-color-primary);border-radius:var(--kf-radius-md);box-shadow:var(--kf-shadow-sm);cursor:pointer;font:inherit;text-align:left}.kf-quote-picker__trigger:hover{box-shadow:var(--kf-shadow-md)}.kf-quote-picker__trigger:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus)}.kf-quote-picker__thumb{display:flex;align-items:center;justify-content:center;width:40px;height:40px;flex:none;border-radius:var(--kf-radius-sm);background:var(--kf-color-surface);color:var(--kf-color-gray-400)}.kf-quote-picker__thumb--sm{width:36px;height:36px}.kf-quote-picker__result--active .kf-quote-picker__thumb{background:var(--kf-color-white);color:var(--kf-color-primary)}.kf-quote-picker__trigger-summary{flex:1;min-width:0;display:flex;align-items:baseline;gap:var(--kf-space-xs);overflow:hidden;white-space:nowrap;color:var(--kf-color-ink)}.kf-quote-picker__trigger-summary--empty{color:var(--kf-color-text-muted)}.kf-quote-picker__trigger-field--title{font-family:var(--kf-font-title);font-weight:700;font-size:1.05rem;color:var(--kf-color-ink)}.kf-quote-picker__trigger-field{font-size:.85rem;color:var(--kf-color-text)}.kf-quote-picker__trigger-sep{color:var(--kf-color-border-strong)}.kf-quote-picker__trigger-action{flex:none;display:flex;align-items:center;gap:6px;color:var(--kf-color-primary);font-size:.85rem;font-weight:600}.kf-quote-picker__chevron{transition:transform .14s}.kf-quote-picker__chevron--open{transform:rotate(180deg)}.kf-quote-picker__panel{display:flex;flex-direction:column;gap:var(--kf-space-md);margin-top:var(--kf-space-sm);padding:var(--kf-space-md) var(--kf-space-lg);background:var(--kf-color-surface);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-md)}.kf-quote-picker__toolbar{display:flex;flex-wrap:wrap;gap:var(--kf-space-sm)}.kf-quote-picker__search{flex:1;min-width:200px;display:flex;align-items:center;gap:var(--kf-space-sm);padding:var(--kf-space-sm) var(--kf-space-md);background:var(--kf-color-white);border:1.5px solid var(--kf-color-border);border-radius:var(--kf-radius-sm);color:var(--kf-color-text-muted)}.kf-quote-picker__search:focus-within{border-color:var(--kf-color-primary);box-shadow:var(--kf-shadow-focus)}.kf-quote-picker__search-input{flex:1;border:none;outline:none;background:transparent;font:inherit;color:var(--kf-color-ink)}.kf-quote-picker__search-input::placeholder{color:var(--kf-color-text-muted)}.kf-quote-picker__chip{flex:none;padding:var(--kf-space-sm) var(--kf-space-md);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-sm);background:var(--kf-color-white);color:var(--kf-color-text);font:inherit;font-size:.8rem;font-weight:600;cursor:pointer}.kf-quote-picker__chip--active{background:var(--kf-color-primary);border-color:var(--kf-color-primary);color:var(--kf-color-white)}.kf-quote-picker__results-wrap{position:relative}.kf-quote-picker__results{display:grid;grid-template-columns:repeat(2,1fr);gap:var(--kf-space-sm);max-height:340px;overflow-y:auto}@media(max-width:900px){.kf-quote-picker__results{grid-template-columns:1fr}}.kf-quote-picker__result{box-sizing:border-box;display:flex;align-items:center;gap:var(--kf-space-sm);padding:var(--kf-space-sm) var(--kf-space-md);border:1px solid transparent;border-radius:var(--kf-radius-sm);background:var(--kf-color-white);cursor:pointer;text-align:left;font:inherit;min-width:0;flex-wrap:wrap;row-gap:2px}.kf-quote-picker__result-fields{display:flex;align-items:center;gap:var(--kf-space-sm);min-width:0;flex:1}.kf-quote-picker__result:hover{border-color:var(--kf-color-border)}.kf-quote-picker__result--active{border-color:var(--kf-color-primary);background:var(--kf-color-primary-soft)}.kf-quote-picker__result-field{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.85rem;color:var(--kf-color-text)}.kf-quote-picker__result-field--title{flex:none;min-width:92px;font-weight:700;color:var(--kf-color-ink)}.kf-quote-picker__result-field--primary{flex:1;min-width:0}@media(max-width:900px){.kf-quote-picker__result-fields{flex-basis:100%;flex-wrap:wrap;row-gap:2px;padding-left:calc(36px + var(--kf-space-sm))}.kf-quote-picker__result-field--primary{flex:none;min-width:0;max-width:100%}}.kf-quote-picker__fade{position:absolute;left:0;right:0;bottom:0;height:36px;background:linear-gradient(to top,var(--kf-color-surface),transparent);pointer-events:none}.kf-quote-picker__see-all{box-sizing:border-box;display:flex;align-items:center;justify-content:center;gap:var(--kf-space-sm);width:100%;margin-top:var(--kf-space-sm);padding:var(--kf-space-sm);border:1.5px dashed var(--kf-color-primary);border-radius:var(--kf-radius-sm);background:var(--kf-color-white);color:var(--kf-color-primary);font:inherit;font-size:.85rem;font-weight:600;cursor:pointer}.kf-quote-picker__see-all:hover{background:var(--kf-color-primary-soft)}.kf-quote-picker__empty{grid-column:1 / -1;padding:var(--kf-space-md);text-align:center;color:var(--kf-color-text-muted);font-size:.85rem;margin:0}.kf-quote-picker__trigger--compact{position:relative;height:var(--kf-quote-picker-trigger-height, 48px);min-width:0;gap:var(--kf-space-sm);padding:0 var(--kf-space-sm) 0 var(--kf-space-md);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-sm);box-shadow:none;transition:border-color .14s,box-shadow .14s}.kf-quote-picker__trigger--compact:hover{border-color:var(--kf-color-border-strong);box-shadow:none}.kf-quote-picker__trigger--compact:focus-visible{border-color:var(--kf-color-primary);box-shadow:var(--kf-shadow-focus)}.kf-quote-picker__compact{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center;gap:2px;line-height:1.25}.kf-quote-picker__compact-line{display:flex;align-items:center;gap:var(--kf-space-sm);min-width:0}.kf-quote-picker__compact-id{flex:none;font-family:var(--kf-font-mono);font-size:var(--kf-font-size-body-sm);font-weight:700;color:var(--kf-color-ink)}.kf-quote-picker__compact-status{display:flex;min-width:0;overflow:hidden}.kf-quote-picker__compact-primary{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--kf-font-size-body-sm);color:var(--kf-color-text)}.kf-quote-picker__trigger--loading{display:flex;align-items:center;cursor:progress}.kf-quote-picker__trigger--compact .kf-quote-picker__chevron{flex:none;color:var(--kf-color-text)}@media(prefers-reduced-motion:reduce){.kf-quote-picker__trigger--compact{transition:none}}.kf-quote-picker__count{margin:0;font-size:var(--kf-font-size-body-sm);font-variant-numeric:tabular-nums;color:var(--kf-color-text)}.kf-quote-picker__count:empty{display:none}.kf-quote-picker__filters{container:kf-quote-picker-filters / inline-size;display:flex;flex-direction:column;gap:var(--kf-space-sm)}.kf-quote-picker__filters-row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--kf-space-sm)}.kf-quote-picker__modal-search{flex:1 1 240px;min-width:240px}.kf-quote-picker__sort{flex:none}@container kf-quote-picker-filters (max-width: 520px){.kf-quote-picker__modal-search{flex-basis:100%;min-width:0}.kf-quote-picker__sort{width:100%}}.kf-quote-picker__list-wrap{container:kf-quote-picker-list / inline-size}.kf-quote-picker__list{display:grid;column-gap:var(--kf-space-md);row-gap:2px;margin:0;padding:0 0 2px;list-style:none}.kf-quote-picker__list-head,.kf-quote-picker__list-item{display:grid;grid-column:1 / -1;grid-template-columns:subgrid}.kf-quote-picker__list-head{position:sticky;top:0;z-index:1;align-items:end;padding:var(--kf-space-xs) var(--kf-space-md) var(--kf-space-sm);border-bottom:1px solid var(--kf-color-border);background:var(--kf-color-white)}.kf-quote-picker__row{grid-column:1 / -1;display:grid;grid-template-columns:subgrid;align-items:center;box-sizing:border-box;width:100%;min-height:52px;padding:var(--kf-space-sm) var(--kf-space-md);border:1px solid transparent;border-radius:var(--kf-radius-sm);background:var(--kf-color-white);color:var(--kf-color-text);font:inherit;font-size:var(--kf-font-size-body-sm);text-align:start;cursor:pointer;scroll-margin-top:48px;scroll-margin-bottom:var(--kf-space-sm)}.kf-quote-picker__row:hover{border-color:var(--kf-color-border);background:var(--kf-color-surface)}.kf-quote-picker__row:focus-visible{outline:2px solid var(--kf-color-primary);outline-offset:-2px}.kf-quote-picker__row--current,.kf-quote-picker__row--current:hover{border-color:var(--kf-color-primary);background:var(--kf-color-primary-soft)}.kf-quote-picker__row-head,.kf-quote-picker__row-body{display:contents}.kf-quote-picker__head-cell{min-width:0;white-space:nowrap}.kf-quote-picker__cell--title{order:0;white-space:nowrap}.kf-quote-picker__row-title{font-family:var(--kf-font-mono);font-weight:700;color:var(--kf-color-ink)}.kf-quote-picker__cell--primary{order:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kf-quote-picker__row-primary{color:var(--kf-color-ink)}.kf-quote-picker__cell--field{order:2;min-width:0;white-space:nowrap;font-variant-numeric:tabular-nums}.kf-quote-picker__cell--truncate{overflow:hidden;text-overflow:ellipsis}.kf-quote-picker__cell--end{justify-self:end;text-align:end}.kf-quote-picker__cell--center{justify-self:center;text-align:center}.kf-quote-picker__row-field--right{font-weight:600;color:var(--kf-color-ink)}.kf-quote-picker__cell--status{order:3;display:flex;min-width:0;overflow:hidden}.kf-quote-picker__cell--check{order:4;display:flex;justify-content:center;color:var(--kf-color-primary)}@container kf-quote-picker-list (max-width: 560px){.kf-quote-picker__list{display:flex;flex-direction:column}.kf-quote-picker__list-head{display:none}.kf-quote-picker__list-item{display:block}.kf-quote-picker__row{grid-template-columns:minmax(0,1fr) 1.25rem;grid-template-areas:\"head check\" \"body check\";column-gap:var(--kf-space-sm);row-gap:var(--kf-space-xs);padding:var(--kf-space-sm);scroll-margin-top:var(--kf-space-sm)}.kf-quote-picker__row-head,.kf-quote-picker__row-body{display:flex;align-items:center;gap:var(--kf-space-sm);min-width:0}.kf-quote-picker__row-head{grid-area:head;justify-content:space-between}.kf-quote-picker__row-body{grid-area:body;flex-wrap:wrap;row-gap:var(--kf-space-xs)}.kf-quote-picker__row-body .kf-quote-picker__cell--end{margin-left:auto}.kf-quote-picker__row-check{grid-area:check}.kf-quote-picker__cell--status{flex:0 1 auto;justify-content:flex-end;max-width:65%}.kf-quote-picker__cell--primary{flex:1 1 100%;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;white-space:normal;overflow-wrap:anywhere}.kf-quote-picker__cell--field{flex:none}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Button, selector: "kf-button", inputs: ["variant", "size", "shape", "disabled", "type", "icon", "block", "loading", "ariaLabel", "ariaExpanded", "ariaPressed", "ariaHaspopup"] }, { kind: "component", type: ContentState, selector: "kf-content-state", inputs: ["state", "load", "title", "subtitle", "loadingLabel"] }, { kind: "component", type: FilterChips, selector: "kf-filter-chips", inputs: ["options", "value", "ariaLabel", "layout", "deselectable"], outputs: ["valueChange"] }, { kind: "component", type: Icon, selector: "kf-icon", inputs: ["name", "size", "rotate", "filled"] }, { kind: "component", type: Input, selector: "kf-input", inputs: ["label", "required", "icon", "suffix", "hint", "invalid", "errorMessage", "disabled", "readonly", "type", "placeholder", "autocomplete", "name", "inputmode", "toggleable", "ariaLabel", "clearable", "clearLabel"], outputs: ["cleared"] }, { kind: "component", type: Modal, selector: "kf-modal", inputs: ["title", "open", "dismissible", "width", "maxHeight", "fullscreenOnMobile", "initialFocus"], outputs: ["openChange"] }, { kind: "component", type: DataTable, selector: "kf-data-table", inputs: ["columns", "rows", "loading", "rowKey", "flush", "cardable", "defaultView", "showViewToggle", "cardMinWidth", "render", "cellTemplates", "density", "rowClickable", "ariaLabel", "currentRowKey", "pageSize", "pageSizeOptions", "page", "keepPageOnRowsChange", "itemLabel", "sort", "view"], outputs: ["rowClick", "pageChange", "pageSizeChange", "sortChange", "viewChange"] }, { kind: "component", type: EmptyState, selector: "kf-empty-state", inputs: ["icon", "tone", "variant", "title"] }, { kind: "component", type: Pagination, selector: "kf-pagination", inputs: ["page", "pages", "pageSizeOptions", "pageSize"], outputs: ["pageChange", "pageSizeChange"] }, { kind: "component", type: Select, selector: "kf-select", inputs: ["label", "options", "value", "placeholder", "disabled", "invalid", "errorMessage", "variant", "width", "searchable", "searchThreshold", "ariaLabel", "icon", "panelTitle", "panelWidth"], outputs: ["valueChange"] }, { kind: "component", type: Skeleton, selector: "kf-skeleton", inputs: ["variant", "width", "height"] }, { kind: "component", type: Text, selector: "kf-text", inputs: ["as", "variant", "tone"] }] });
|
|
583
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: QuotePicker, isStandalone: true, selector: "kf-quote-picker", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, selectedId: { classPropertyName: "selectedId", publicName: "selectedId", isSignal: true, isRequired: false, transformFunction: null }, idKey: { classPropertyName: "idKey", publicName: "idKey", isSignal: true, isRequired: true, transformFunction: null }, cellTemplates: { classPropertyName: "cellTemplates", publicName: "cellTemplates", isSignal: true, isRequired: false, transformFunction: null }, chips: { classPropertyName: "chips", publicName: "chips", isSignal: true, isRequired: false, transformFunction: null }, sortOptions: { classPropertyName: "sortOptions", publicName: "sortOptions", isSignal: true, isRequired: false, transformFunction: null }, sort: { classPropertyName: "sort", publicName: "sort", isSignal: true, isRequired: false, transformFunction: null }, expandThreshold: { classPropertyName: "expandThreshold", publicName: "expandThreshold", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, placeholderIcon: { classPropertyName: "placeholderIcon", publicName: "placeholderIcon", isSignal: true, isRequired: false, transformFunction: null }, modalLayout: { classPropertyName: "modalLayout", publicName: "modalLayout", isSignal: true, isRequired: false, transformFunction: null }, searchAriaLabel: { classPropertyName: "searchAriaLabel", publicName: "searchAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, loadingLabel: { classPropertyName: "loadingLabel", publicName: "loadingLabel", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, triggerSize: { classPropertyName: "triggerSize", publicName: "triggerSize", isSignal: true, isRequired: false, transformFunction: null }, inlinePanel: { classPropertyName: "inlinePanel", publicName: "inlinePanel", isSignal: true, isRequired: false, transformFunction: null }, modalWidth: { classPropertyName: "modalWidth", publicName: "modalWidth", isSignal: true, isRequired: false, transformFunction: null }, itemLabels: { classPropertyName: "itemLabels", publicName: "itemLabels", isSignal: true, isRequired: false, transformFunction: null }, allChipLabel: { classPropertyName: "allChipLabel", publicName: "allChipLabel", isSignal: true, isRequired: false, transformFunction: null }, chipsAriaLabel: { classPropertyName: "chipsAriaLabel", publicName: "chipsAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, listHeader: { classPropertyName: "listHeader", publicName: "listHeader", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sort: "sortChange", open: "openChange", selectedIdChange: "selectedIdChange", retry: "retry", expandToModal: "expandToModal" }, viewQueries: [{ propertyName: "previewScrollEl", first: true, predicate: ["previewScroll"], descendants: true, isSignal: true }, { propertyName: "modalListEl", first: true, predicate: ["modalList"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (variant() === 'inline') {\n <div class=\"kf-quote-picker__inline\">\n <!-- Trigger colapsado. `default`: tarjeta a ancho completo con miniatura\n (hist\u00F3rico). `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\u00F3n. 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\u00F3n</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\u00EDtulo (ID) \u2014 mostrar los 5 campos\n en una sola l\u00EDnea 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\u00ED 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\">\u00B7</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\u00F3n</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\u00EDnea COMPLETO\n (mismo criterio que \"unidades\" no debe competir con\n \"modelo\" en la primera l\u00EDnea) \u2014 `flex-basis: 100%` en un\n solo elemento fuerza ese salto sin tener que asumir cu\u00E1l\n de los N campos gen\u00E9ricos es el m\u00E1s corto o el m\u00E1s 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\u00FAsqueda.</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\u00F3n) ya se anuncia\n completa, as\u00ED que para lectores de pantalla ser\u00EDa 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\u00FAsqueda.</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\u00FAsqueda.</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", styles: [":host{display:block;min-width:0;font-family:var(--kf-font-body)}.kf-quote-picker__sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.kf-quote-picker__trigger{box-sizing:border-box;display:flex;align-items:center;gap:var(--kf-space-md);width:100%;padding:var(--kf-space-sm) var(--kf-space-md);background:var(--kf-color-white);border:1.5px solid var(--kf-color-primary);border-radius:var(--kf-radius-md);box-shadow:var(--kf-shadow-sm);cursor:pointer;font:inherit;text-align:left}.kf-quote-picker__trigger:hover{box-shadow:var(--kf-shadow-md)}.kf-quote-picker__trigger:focus-visible{outline:none;box-shadow:var(--kf-shadow-focus)}.kf-quote-picker__thumb{display:flex;align-items:center;justify-content:center;width:40px;height:40px;flex:none;border-radius:var(--kf-radius-sm);background:var(--kf-color-surface);color:var(--kf-color-gray-400)}.kf-quote-picker__thumb--sm{width:36px;height:36px}.kf-quote-picker__result--active .kf-quote-picker__thumb{background:var(--kf-color-white);color:var(--kf-color-primary)}.kf-quote-picker__trigger-summary{flex:1;min-width:0;display:flex;align-items:baseline;gap:var(--kf-space-xs);overflow:hidden;white-space:nowrap;color:var(--kf-color-ink)}.kf-quote-picker__trigger-summary--empty{color:var(--kf-color-text-muted)}.kf-quote-picker__trigger-field--title{font-family:var(--kf-font-title);font-weight:700;font-size:1.05rem;color:var(--kf-color-ink)}.kf-quote-picker__trigger-field{font-size:.85rem;color:var(--kf-color-text)}.kf-quote-picker__trigger-sep{color:var(--kf-color-border-strong)}.kf-quote-picker__trigger-action{flex:none;display:flex;align-items:center;gap:6px;color:var(--kf-color-primary);font-size:.85rem;font-weight:600}.kf-quote-picker__chevron{transition:transform .14s}.kf-quote-picker__chevron--open{transform:rotate(180deg)}.kf-quote-picker__panel{display:flex;flex-direction:column;gap:var(--kf-space-md);margin-top:var(--kf-space-sm);padding:var(--kf-space-md) var(--kf-space-lg);background:var(--kf-color-surface);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-md)}.kf-quote-picker__toolbar{display:flex;flex-wrap:wrap;gap:var(--kf-space-sm)}.kf-quote-picker__search{flex:1;min-width:200px;display:flex;align-items:center;gap:var(--kf-space-sm);padding:var(--kf-space-sm) var(--kf-space-md);background:var(--kf-color-white);border:1.5px solid var(--kf-color-border);border-radius:var(--kf-radius-sm);color:var(--kf-color-text-muted)}.kf-quote-picker__search:focus-within{border-color:var(--kf-color-primary);box-shadow:var(--kf-shadow-focus)}.kf-quote-picker__search-input{flex:1;border:none;outline:none;background:transparent;font:inherit;color:var(--kf-color-ink)}.kf-quote-picker__search-input::placeholder{color:var(--kf-color-text-muted)}.kf-quote-picker__chip{flex:none;padding:var(--kf-space-sm) var(--kf-space-md);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-sm);background:var(--kf-color-white);color:var(--kf-color-text);font:inherit;font-size:.8rem;font-weight:600;cursor:pointer}.kf-quote-picker__chip--active{background:var(--kf-color-primary);border-color:var(--kf-color-primary);color:var(--kf-color-white)}.kf-quote-picker__results-wrap{position:relative}.kf-quote-picker__results{display:grid;grid-template-columns:repeat(2,1fr);gap:var(--kf-space-sm);max-height:340px;overflow-y:auto}@media(max-width:900px){.kf-quote-picker__results{grid-template-columns:1fr}}.kf-quote-picker__result{box-sizing:border-box;display:flex;align-items:center;gap:var(--kf-space-sm);padding:var(--kf-space-sm) var(--kf-space-md);border:1px solid transparent;border-radius:var(--kf-radius-sm);background:var(--kf-color-white);cursor:pointer;text-align:left;font:inherit;min-width:0;flex-wrap:wrap;row-gap:2px}.kf-quote-picker__result-fields{display:flex;align-items:center;gap:var(--kf-space-sm);min-width:0;flex:1}.kf-quote-picker__result:hover{border-color:var(--kf-color-border)}.kf-quote-picker__result--active{border-color:var(--kf-color-primary);background:var(--kf-color-primary-soft)}.kf-quote-picker__result-field{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.85rem;color:var(--kf-color-text)}.kf-quote-picker__result-field--title{flex:none;min-width:92px;font-weight:700;color:var(--kf-color-ink)}.kf-quote-picker__result-field--primary{flex:1;min-width:0}@media(max-width:900px){.kf-quote-picker__result-fields{flex-basis:100%;flex-wrap:wrap;row-gap:2px;padding-left:calc(36px + var(--kf-space-sm))}.kf-quote-picker__result-field--primary{flex:none;min-width:0;max-width:100%}}.kf-quote-picker__fade{position:absolute;left:0;right:0;bottom:0;height:36px;background:linear-gradient(to top,var(--kf-color-surface),transparent);pointer-events:none}.kf-quote-picker__see-all{box-sizing:border-box;display:flex;align-items:center;justify-content:center;gap:var(--kf-space-sm);width:100%;margin-top:var(--kf-space-sm);padding:var(--kf-space-sm);border:1.5px dashed var(--kf-color-primary);border-radius:var(--kf-radius-sm);background:var(--kf-color-white);color:var(--kf-color-primary);font:inherit;font-size:.85rem;font-weight:600;cursor:pointer}.kf-quote-picker__see-all:hover{background:var(--kf-color-primary-soft)}.kf-quote-picker__empty{grid-column:1 / -1;padding:var(--kf-space-md);text-align:center;color:var(--kf-color-text-muted);font-size:.85rem;margin:0}.kf-quote-picker__trigger--compact{position:relative;height:var(--kf-quote-picker-trigger-height, 48px);min-width:0;gap:var(--kf-space-sm);padding:0 var(--kf-space-sm) 0 var(--kf-space-md);border:1px solid var(--kf-color-border);border-radius:var(--kf-radius-sm);box-shadow:none;transition:border-color .14s,box-shadow .14s}.kf-quote-picker__trigger--compact:hover{border-color:var(--kf-color-border-strong);box-shadow:none}.kf-quote-picker__trigger--compact:focus-visible{border-color:var(--kf-color-primary);box-shadow:var(--kf-shadow-focus)}.kf-quote-picker__compact{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center;gap:2px;line-height:1.25}.kf-quote-picker__compact-line{display:flex;align-items:center;gap:var(--kf-space-sm);min-width:0}.kf-quote-picker__compact-id{flex:none;font-family:var(--kf-font-mono);font-size:var(--kf-font-size-body-sm);font-weight:700;color:var(--kf-color-ink)}.kf-quote-picker__compact-status{display:flex;min-width:0;overflow:hidden}.kf-quote-picker__compact-primary{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--kf-font-size-body-sm);color:var(--kf-color-text)}.kf-quote-picker__trigger--loading{display:flex;align-items:center;cursor:progress}.kf-quote-picker__trigger--compact .kf-quote-picker__chevron{flex:none;color:var(--kf-color-text)}@media(prefers-reduced-motion:reduce){.kf-quote-picker__trigger--compact{transition:none}}.kf-quote-picker__count{margin:0;font-size:var(--kf-font-size-body-sm);font-variant-numeric:tabular-nums;color:var(--kf-color-text)}.kf-quote-picker__count:empty{display:none}.kf-quote-picker__filters{container:kf-quote-picker-filters / inline-size;display:flex;flex-direction:column;gap:var(--kf-space-sm)}.kf-quote-picker__filters-row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--kf-space-sm)}.kf-quote-picker__modal-search{flex:1 1 240px;min-width:240px}.kf-quote-picker__sort{flex:none}@container kf-quote-picker-filters (max-width: 520px){.kf-quote-picker__modal-search{flex-basis:100%;min-width:0}.kf-quote-picker__sort{width:100%}}.kf-quote-picker__list-wrap{container:kf-quote-picker-list / inline-size}.kf-quote-picker__list{display:grid;column-gap:var(--kf-space-md);row-gap:2px;margin:0;padding:0 0 2px;list-style:none}.kf-quote-picker__list-head,.kf-quote-picker__list-item{display:grid;grid-column:1 / -1;grid-template-columns:subgrid}.kf-quote-picker__list-head{position:sticky;top:0;z-index:1;align-items:end;padding:var(--kf-space-xs) var(--kf-space-md) var(--kf-space-sm);border-bottom:1px solid var(--kf-color-border);background:var(--kf-color-white)}.kf-quote-picker__row{grid-column:1 / -1;display:grid;grid-template-columns:subgrid;align-items:center;box-sizing:border-box;width:100%;min-height:52px;padding:var(--kf-space-sm) var(--kf-space-md);border:1px solid transparent;border-radius:var(--kf-radius-sm);background:var(--kf-color-white);color:var(--kf-color-text);font:inherit;font-size:var(--kf-font-size-body-sm);text-align:start;cursor:pointer;scroll-margin-top:48px;scroll-margin-bottom:var(--kf-space-sm)}.kf-quote-picker__row:hover{border-color:var(--kf-color-border);background:var(--kf-color-surface)}.kf-quote-picker__row:focus-visible{outline:2px solid var(--kf-color-primary);outline-offset:-2px}.kf-quote-picker__row--current,.kf-quote-picker__row--current:hover{border-color:var(--kf-color-primary);background:var(--kf-color-primary-soft)}.kf-quote-picker__row-head,.kf-quote-picker__row-body{display:contents}.kf-quote-picker__head-cell{min-width:0;white-space:nowrap}.kf-quote-picker__cell--title{order:0;white-space:nowrap}.kf-quote-picker__row-title{font-family:var(--kf-font-mono);font-weight:700;color:var(--kf-color-ink)}.kf-quote-picker__cell--primary{order:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kf-quote-picker__row-primary{color:var(--kf-color-ink)}.kf-quote-picker__cell--field{order:2;min-width:0;white-space:nowrap;font-variant-numeric:tabular-nums}.kf-quote-picker__cell--truncate{overflow:hidden;text-overflow:ellipsis}.kf-quote-picker__cell--end{justify-self:end;text-align:end}.kf-quote-picker__cell--center{justify-self:center;text-align:center}.kf-quote-picker__row-field--right{font-weight:600;color:var(--kf-color-ink)}.kf-quote-picker__cell--status{order:3;display:flex;min-width:0;overflow:hidden}.kf-quote-picker__cell--check{order:4;display:flex;justify-content:center;color:var(--kf-color-primary)}@container kf-quote-picker-list (max-width: 560px){.kf-quote-picker__list{display:flex;flex-direction:column}.kf-quote-picker__list-head{display:none}.kf-quote-picker__list-item{display:block}.kf-quote-picker__row{grid-template-columns:minmax(0,1fr) 1.25rem;grid-template-areas:\"head check\" \"body check\";column-gap:var(--kf-space-sm);row-gap:var(--kf-space-xs);padding:var(--kf-space-sm);scroll-margin-top:var(--kf-space-sm)}.kf-quote-picker__row-head,.kf-quote-picker__row-body{display:flex;align-items:center;gap:var(--kf-space-sm);min-width:0}.kf-quote-picker__row-head{grid-area:head;justify-content:space-between}.kf-quote-picker__row-body{grid-area:body;flex-wrap:wrap;row-gap:var(--kf-space-xs)}.kf-quote-picker__row-body .kf-quote-picker__cell--end{margin-left:auto}.kf-quote-picker__row-check{grid-area:check}.kf-quote-picker__cell--status{flex:0 1 auto;justify-content:flex-end;max-width:65%}.kf-quote-picker__cell--primary{flex:1 1 100%;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;white-space:normal;overflow-wrap:anywhere}.kf-quote-picker__cell--field{flex:none}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Button, selector: "kf-button", inputs: ["variant", "size", "shape", "disabled", "type", "icon", "block", "loading", "ariaLabel", "ariaExpanded", "ariaPressed", "ariaHaspopup"] }, { kind: "component", type: ContentState, selector: "kf-content-state", inputs: ["state", "load", "title", "subtitle", "loadingLabel", "loadingTemplate", "loadingPreset"] }, { kind: "component", type: FilterChips, selector: "kf-filter-chips", inputs: ["options", "value", "ariaLabel", "layout", "deselectable"], outputs: ["valueChange"] }, { kind: "component", type: Icon, selector: "kf-icon", inputs: ["name", "size", "rotate", "filled"] }, { kind: "component", type: Input, selector: "kf-input", inputs: ["label", "required", "icon", "suffix", "hint", "invalid", "errorMessage", "disabled", "readonly", "type", "placeholder", "autocomplete", "name", "inputmode", "min", "max", "step", "maxlength", "toggleable", "ariaLabel", "clearable", "clearLabel"], outputs: ["cleared"] }, { kind: "component", type: Modal, selector: "kf-modal", inputs: ["title", "open", "dismissible", "width", "maxHeight", "fullscreenOnMobile", "initialFocus"], outputs: ["openChange"] }, { kind: "component", type: DataTable, selector: "kf-data-table", inputs: ["columns", "rows", "loading", "skeletonRows", "rowKey", "flush", "cardable", "defaultView", "showViewToggle", "cardMinWidth", "render", "cellTemplates", "density", "rowClickable", "cellAriaLabel", "ariaLabel", "currentRowKey", "pageSize", "pageSizeOptions", "page", "keepPageOnRowsChange", "itemLabel", "sort", "view"], outputs: ["rowClick", "cellClick", "pageChange", "pageSizeChange", "sortChange", "viewChange"] }, { kind: "component", type: EmptyState, selector: "kf-empty-state", inputs: ["icon", "tone", "variant", "title"] }, { kind: "component", type: Pagination, selector: "kf-pagination", inputs: ["page", "pages", "pageSizeOptions", "pageSize"], outputs: ["pageChange", "pageSizeChange"] }, { kind: "component", type: Select, selector: "kf-select", inputs: ["label", "options", "value", "placeholder", "disabled", "invalid", "errorMessage", "variant", "width", "searchable", "searchThreshold", "ariaLabel", "icon", "panelTitle", "panelWidth"], outputs: ["valueChange"] }, { kind: "component", type: Skeleton, selector: "kf-skeleton", inputs: ["variant", "width", "height"] }, { kind: "component", type: Text, selector: "kf-text", inputs: ["as", "variant", "tone"] }] });
|
|
584
584
|
}
|
|
585
585
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: QuotePicker, decorators: [{
|
|
586
586
|
type: Component,
|