VOOZH about

URL: https://www.nuget.org/packages/Cayaqui.Components/

⇱ NuGet Gallery | Cayaqui.Components 0.3.8




Cayaqui.Components 0.3.8

dotnet add package Cayaqui.Components --version 0.3.8
 
 
NuGet\Install-Package Cayaqui.Components -Version 0.3.8
 
 
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Cayaqui.Components" Version="0.3.8" />
 
 
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Cayaqui.Components" Version="0.3.8" />
 
Directory.Packages.props
<PackageReference Include="Cayaqui.Components" />
 
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Cayaqui.Components --version 0.3.8
 
 
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Cayaqui.Components, 0.3.8"
 
 
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Cayaqui.Components@0.3.8
 
 
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Cayaqui.Components&version=0.3.8
 
Install as a Cake Addin
#tool nuget:?package=Cayaqui.Components&version=0.3.8
 
Install as a Cake Tool
The NuGet Team does not provide support for this client. Please contact its maintainers for support.

Cayaqui.Components

Design system + componentes EVM/EPC reutilizables para .NET 10 Blazor WebApp (Interactive Server) construidos sobre Syncfusion.Blazor 33.x y Blazor-ApexCharts.

0.3.7 — CompanyThemes.Ynex

Nuevo tema canónico para el look YNEX estándar:

builder.Services.AddCayaquiComponents(opts =>
{
 opts.DefaultCompanyThemeId = CompanyThemes.Ynex.Id;
});
Propiedad Valor
Accent Violet (#845BDF)
SidebarTone Default (sidebar neutro)
HeaderStyle Default (header blanco)
Direction A
Density Comfort

0.3.6 — YNEX KPI card fidelity

.kpi-card con data-cayaqui-preset="ynex" alineado al estilo KPI del template YNEX original:

Propiedad Antes Ahora
Border base 1px solid var(--color-border) transparent (solo shadow)
Shadow ninguna 0 2px 6px rgba(56, 65, 74, 0.15)
Badge shape border-radius: var(--radius-md) cuadrado var(--radius-pill) circular · 40×40 px
Value font-size var(--text-4xl) (30 px) var(--text-3xl) (24 px)
Dark mode heredaba shadow genérica 0 0.125rem 0 rgba(0,0,0,0.30) explícito

Status variants (kpi-card--success/warning/danger) conservan su border-color semántico (selector :not() excluye el override). Sin breaking changes.

0.3.4 — Tables YNEX fidelity

.cayaqui-table, .e-grid y .e-treegrid alineados visualmente a YNEX:

Propiedad Antes Ahora
Header text-transform uppercase normal (sin transform)
Header letter-spacing 0.04em none
Header font-size var(--text-xs) var(--text-sm)
Header font-weight 500 600
Header color var(--color-text-tertiary) var(--color-text)
Header background var(--color-surface-alt) var(--color-surface)
Row cell color var(--color-text-secondary) var(--color-text)
Border-radius var(--radius-xl) = 12px var(--radius-md) = 8px
Sticky first-col bg var(--color-surface-alt) var(--color-surface)

Preset Untitled reintroduce su estilo original vía [data-cayaqui-theme="untitled"] overrides: border-radius: var(--radius-xl), uppercase + letter-spacing: 0.04em, font-size: var(--text-xs), font-weight: 500, color: var(--color-text-tertiary), background: var(--color-surface-alt).

0.65.7 — Cards YNEX fidelity: margen + footer transparente

.cayaqui-card ahora tiene margin-block: 1.5rem por defecto (espaciado vertical entre cards, igual que YNEX). El footer elimina el background var(--color-surface-alt) — footer ahora transparente como YNEX.

.cayaqui-card-group > * y .cayaqui-kpi-tile .cayaqui-card zerean el margen — cuando el spacing lo maneja el contenedor (grid gap), el margen no se duplica.

0.65.6 — Forms YNEX-fidelity global

Inputs, labels, checkboxes, radios y botones alineados al estilo YNEX:

Elemento Antes Ahora
Input border 1px solid var(--color-border-strong) 1px solid var(--color-border) (más ligero)
Input radius var(--radius-md) = 8px var(--radius-sm) = 6px
Input shadow var(--shadow-xs) none
Input hover border-color: var(--color-text-tertiary) border-color: var(--color-border-strong)
Input focus border-color + shadow-focus (ring 4px) solo border-color: var(--color-accent-500)
Label font var(--text-sm) / weight 500 0.8rem / weight 600
Placeholder default font-weight: 500
Checkbox/radio border 1.5px solid var(--color-border-strong) 1px solid var(--color-border)
Btn radius var(--radius-md) = 8px var(--radius-sm) = 6px

Preset Untitled preserva estilo original: border-radius: var(--radius-md) + box-shadow: var(--shadow-xs) en inputs, label var(--text-sm) / 500, btn var(--radius-md).

0.65.4 — Cards YNEX-fidelity global

Base card ahora coincide con YNEX en todos los presets:

Propiedad Antes (default) Ahora (YNEX-global)
border 1px solid var(--color-border) none
border-radius var(--radius-xl) = 12px var(--radius-md) = 8px
box-shadow var(--shadow-sm) 0 0.125rem 0 rgba(10,10,10,.06)
Header padding 20px 24px 16px 20px
Body padding 20px 24px 20px
Footer padding 16px 24px 16px 20px
Title var(--text-lg) / 600 0.9375rem / 700

Preset Untitled preserva su estilo propio vía [data-cayaqui-theme="untitled"] (borde, radius-xl, shadow-sm, padding original).

0.65.3 — CayaquiPageHeader full-bleed con --cayaqui-ph-bleed-x

CayaquiPageHeader implementa el patrón full-bleed: el fondo y sombra se extienden de borde a borde del contenedor padre, mientras el contenido interno alinea con el resto de la página.

El consumer establece --cayaqui-ph-bleed-x en el contenedor padre igual a su padding horizontal:

/* app.css del consumidor */
.app-main {
 padding: 24px 32px;
 --cayaqui-ph-bleed-x: 32px; /* igual al padding horizontal */
}
  • Con --cayaqui-ph-bleed-x: 32pxmargin-inline: -32px, padding-inline: 32px → borde a borde, título alineado con contenido
  • Sin --cayaqui-ph-bleed-x (default 0px) → sin bleed, sin márgenes negativos (comportamiento neutro)

0.65.1 — CayaquiPageHeader: sin padding horizontal

CayaquiPageHeader ahora ocupa el 100% del ancho con padding-left: 0 y padding-right: 0. El layout del consumidor es responsable del padding horizontal (e.g., el <main> o contenedor padre). Sin breaking changes de API.

0.65.0 — YNEX Behavior completo en CayaquiSidebar

CayaquiSidebar — sidebar fixed full-height + mobile off-canvas

@* Layout del consumidor *@
<div class="app-shell">
 <CayaquiSidebar @ref="_sidebar"
 Sticky="true"
 Collapsible="true"
 CollapseStorageKey="myapp.sidebar.collapsed"
 ... />
 <div class="app-content">
 <CayaquiAppHeader Sidebar="_sidebar" ShowHamburger="true" ... />
 <main>@Body</main>
 </div>
</div>
/* site.css del consumidor */
.app-content { transition: margin-left 0.05s ease; }
.app-shell:has(.cayaqui-sidebar.is-sticky.is-app:not(.is-collapsed)) .app-content { margin-left: 280px; }
.app-shell:has(.cayaqui-sidebar.is-sticky.is-app.is-collapsed) .app-content,
.app-shell:has(.cayaqui-sidebar.is-sticky.is-slim) .app-content { margin-left: 72px; }
@media (max-width: 1023px) { .app-shell .app-content { margin-left: 0; } }

El hamburguer de CayaquiAppHeader detecta el viewport automáticamente:

  • Desktop (≥ 1024px): colapsa/expande el sidebar (icon-only ↔ full)
  • Mobile (< 1024px): abre/cierra el drawer off-canvas con backdrop

0.64.0 — CayaquiPageHeader YNEX Redesign

⚠ Breaking: eliminados Card, Tinted, CardBackground, CardBorderColor.

Nuevo look: banda full-width blanca, shadow borrosa inferior, breadcrumbs bajo subtítulo, acciones a la derecha del título.

v0.63.0 — Responsive móvil por defecto

Todos los componentes renderizan correctamente en un teléfono (390px) sin configuración del consumidor.

Mecanismo híbrido:

  • @container queries para componentes embebibles (tablas, charts, cards, forms) — se adaptan al ancho de su celda, no solo del teléfono. Convención de breakpoints: sm=640px, lg=1024px.
  • @media viewport solo para layout global: modals full-screen bajo 640px, drawers a 100%, sidebar off-canvas bajo 1024px.
  • @media (pointer: coarse) para targets táctiles: 44px (WCAG 2.5.8) en botones/inputs/rows, 40px en items densos (menús, crumbs).

Tablas: wrapper .cayaqui-table-scroll — scroll horizontal dentro del card (la página nunca scrollea), primera columna sticky en contenedores angostos, hint visual de scroll. Ajustable por tabla vía --cayaqui-table-min-width. Composición manual de filas R9C: envolver en .cayaqui-table-scroll.

Charts: CayaquiChartResponsive centraliza la config móvil de ApexCharts (leyenda abajo, menos labels, toolbar oculto bajo 640px). Gantt/Timeline conservan ancho mínimo legible con scroll.

Sidebar off-canvas (nuevo API aditivo):

<CayaquiSidebar @bind-MobileOpen="_menuAbierto" ... />

<button class="ah-icon-btn" aria-label="Abrir menú"
 @onclick="() => _menuAbierto = !_menuAbierto">☰</button>

Bajo 1024px la sidebar se oculta off-canvas; MobileOpen=true la desliza sobre un backdrop clickeable que dispara MobileOpenChanged(false). El rail collapse de desktop (Collapsible/IsCollapsed) no cambia.

Forms: el EditForm de CayaquiAutoForm lleva la clase .cayaqui-autoform (query container) — submit a ancho completo en contenedores angostos.

Sin breaking changes. Auditoría componente a componente: docs/components/2026-06-11-mobile-audit.md del repo.

v0.62.1 — Fix CayaquiBarChart: etiquetas NaN en barras horizontales

Bug: CayaquiBarChart con orientación por defecto (Vertical = barras horizontales) mostraba NaN en todas las etiquetas del eje Y. Causa: Yaxis.Labels.Formatter aplicaba Intl.NumberFormat().format(v) a las strings de categoría (eje Y = labels en barras horizontales), retornando NaN. Adicionalmente, Xaxis.Type estaba en Category cuando debería ser Numeric para el eje de valores.

Fix: Xaxis.Type es ahora Numeric para Orientation=Vertical (barras horizontales) y Category para Orientation=Horizontal (columnas). Yaxis.Labels.Formatter usa función identidad (function(v){return v}) para barras horizontales (eje Y = strings) y el formateador numérico para columnas (eje Y = números). Sin breaking changes.

v0.62.0 — Badge i18n en columnas manuales (issue #3)

CayaquiGridColumn Kind="CayaquiColumnKind.AutoBadge" usado en columnas manuales (con slot <Columns>, sin DtoType/PropertyName) ahora resuelve el texto del badge desde [Display(Name)] del miembro del enum y el color desde [BadgeColor] del miembro — antes mostraba enum.ToString() (inglés) y color gris. CayaquiAutoBadge standalone también lee [Display(Name)] para el texto.

Fallback a ToString() cuando el miembro no tiene [Display]. El modo AUTO (sin <Columns>, resolver-driven) ya resolvía [Display] y queda igual. Aditivo, sin breaking.

El consumidor sólo anota el enum:

public enum Severity
{
 [Display(Name = "Información")] [BadgeColor(BadgeKind.Neutral)] Info,
 [Display(Name = "Advertencia")] [BadgeColor(BadgeKind.Warning)] Warning,
 [Display(Name = "Crítica")] [BadgeColor(BadgeKind.Error)] Critical,
}
<CayaquiGrid TItem="AlertDto" DataSource="_alerts">
 <Columns>
 <CayaquiGridColumn TItem="AlertDto" Field="Level" Header="Severidad"
 Kind="CayaquiColumnKind.AutoBadge" Width="120px" />
 </Columns>
</CayaquiGrid>
@* Badge: texto "Crítica" (no "Critical"), color error — sin DtoType/PropertyName. *@

v0.61.0 — CayaquiAppHeader: action items estilo YNEX

Cuatro action items opt-in en el lado derecho del header, más estado unificado de dropdown (un solo menú abierto a la vez + backdrop click-outside, que ahora también cubre el user-menu).

  • NotificacionesShowNotifications, Notifications (lista de CayaquiHeaderNotification), badge de no-leídos derivado o explícito (NotificationBadge, cap 9+), PulseBadge, OnNotificationClick, footer "Ver todas" (OnViewAllNotifications), NotificationsTitle/NotificationsEmptyText.
  • Pantalla completaShowFullscreen (reusa CayaquiFullscreenToggle).
  • Apps-gridShowAppsGrid, AppShortcuts (lista de CayaquiHeaderAppShortcut), OnAppShortcutClick (fallback: navega al Url), AppsGridTitle.
  • Selector de idiomaShowLanguageSelector, Languages (lista de CayaquiHeaderLanguage), CurrentLanguageCode, OnLanguageChanged.

Nuevos records: CayaquiHeaderNotification, CayaquiHeaderAppShortcut, CayaquiHeaderLanguage.

<CayaquiAppHeader Sidebar="_sidebar" ShowHamburger="true"
 ShowNotifications="true" Notifications="_notifs" PulseBadge="true"
 ShowFullscreen="true"
 ShowAppsGrid="true" AppShortcuts="_apps"
 ShowLanguageSelector="true" Languages="_langs" CurrentLanguageCode="es"
 UserName="Demo User" UserSubtitle="demo@cayaqui.com">
 <Right><CayaquiColorModeToggle /></Right>
</CayaquiAppHeader>

Aditivo, sin breaking changes.

v0.60.3 — Accent de marca: Andes Iron

Nuevo valor ThemeAccent.AndesIron (minera Andes Iron SpA): rust óxido de hierro #ED6F51, escala completa 50–800 en light y dark. Aparece automáticamente en CayaquiThemeSwitcher.

builder.Services.AddCayaquiComponents(opts => opts.DefaultAccent = ThemeAccent.AndesIron);
// o en runtime:
await ThemeService.SetAsync(accent: ThemeAccent.AndesIron);

Aditivo, sin breaking changes.

v0.60.0 — Charts: 3 nuevos + interactividad (Donut/Scatter)

Cierra la migración de gráficos fuera de Syncfusion. API pública sin dependencia de ApexCharts.

Nuevos componentes (Design.Charts / Design.DataDisplay):

  • CayaquiLineChart<T> — curva de línea genérica. Serie única (YField) o multi-serie vía Series (CayaquiChartSeries<T>(Name, YField, Color?)). Marcador de fecha de control (ControlDate + XAxis="CayaquiAxisType.DateTime").
  • CayaquiColumnChart<T> — columnas verticales. Multi-serie agrupada (default) o apilada (Stacked). Caso Cayaqui: Plan / Real / EAT por categoría.
  • CayaquiPieChart — composición sólida; reutiliza el motor de CayaquiDonutChart (InnerRadius="0%") y hereda toda la interactividad.

Interactividad (mejora) — CayaquiDonutChart / CayaquiPieChart:

  • OnItemClick : EventCallback<DonutItem> — click en slice (cross-filter / toggle en el consumidor).
  • SelectedLabel : string? + DimUnselected (default true) — atenúa los slices no seleccionados.
  • Color semántico por item: DonutItem(Label, Value, Color?).

Interactividad (mejora) — CayaquiScatterChart<T>:

  • OnPointClick : EventCallback<T> — devuelve el item (drill-down).
  • Ejes fijos XMin/XMax/XInterval + YMin/YMax/YInterval (CPI×SPI encuadrado en 1.0).
  • Plotlines XPlotLine/YPlotLine. Bubble vía SizeField/ColorField.
@* Multi-serie EVM *@
<CayaquiLineChart TItem="EvmPoint" Data="@evm" Series="@series"
 XField="@(x => (object)x.Date)" XAxis="CayaquiAxisType.DateTime" />

@* Pie cross-filter *@
<CayaquiPieChart Items="@status" SelectedLabel="@selected" OnItemClick="OnSliceClick" />

@* Scatter CPI×SPI con drill-down y ejes fijos *@
<CayaquiScatterChart TItem="Proj" Data="@perf"
 XField="@(x => (decimal?)x.Cpi)" YField="@(x => (decimal?)x.Spi)"
 XMin="0.5m" XMax="1.5m" XInterval="0.1m"
 YMin="0.5m" YMax="1.5m" YInterval="0.1m"
 XPlotLine="1.0m" YPlotLine="1.0m" DecimalPlaces="2"
 OnPointClick="@(p => Nav.NavigateTo($"/proyectos/{p.Id}"))" />

⚠️ BREAKING menor: DonutItem pasó a record (Label, Value, Color?). La construcción de 2 args sigue válida; sólo se rompe la deconstrucción posicional de 2 elementos (is DonutItem(var l, var v)) — poco usada.

v0.59.0 — CayaquiAutoGrid fusionado en CayaquiGrid ⚠️ BREAKING

CayaquiAutoGrid fue eliminado. Su funcionalidad (columnas auto-generadas desde Cayaqui.Metadata) ahora vive dentro de CayaquiGrid como modo AUTO:

  • Modo MANUAL (sin cambios) — provee <Columns> con <CayaquiGridColumn> explícitos.
  • Modo AUTO (nuevo en CayaquiGrid) — omití <Columns> y las columnas se infieren desde los atributos del DTO. Acotá con Include / Exclude.

CayaquiGrid absorbió todos los parámetros del viejo CayaquiAutoGrid: Include, Exclude, RowActions, RowActionsHeader, RowActionsWidth.

Migración

Renombrá la etiqueta. Los parámetros son idénticos — no requiere otros cambios:

- <CayaquiAutoGrid TItem="InvoiceDto" DataSource="@rows"
- Exclude="@(new[] { nameof(InvoiceDto.Id) })">
- <RowActions Context="row">
- <CayaquiIconButton Icon="e-icons e-edit" OnClick="@(() => Edit(row))" />
- </RowActions>
- </CayaquiAutoGrid>
+ <CayaquiGrid TItem="InvoiceDto" DataSource="@rows"
+ Exclude="@(new[] { nameof(InvoiceDto.Id) })">
+ <RowActions Context="row">
+ <CayaquiIconButton Icon="e-icons e-edit" OnClick="@(() => Edit(row))" />
+ </RowActions>
+ </CayaquiGrid>

Regla rápida: CayaquiGrid sin <Columns> = lo que antes hacía CayaquiAutoGrid. CayaquiGrid con <Columns> = modo manual de siempre. Búsqueda-reemplazo global CayaquiAutoGridCayaquiGrid resuelve la migración completa.

v0.58.1 — Dark-Mode Theme Engine Fixes

Five bugs in cayaqui-theme.js and cayaqui-components.css affecting dark-mode accent rendering:

  • opts.mode mismatch fixedundefined/null now treated as 'system' in apply(), consistent with applyMode(). Previously resolved to 'light' while applyMode set dark attribute → dark UI with light accent palette.
  • OS toggle re-applies paletteinit() matchMedia listener now calls apply(_lastOpts) on OS dark/light switch (was calling only applyMode()). Inline accent palette no longer stale after system preference change.
  • Custom accent dark-mode awaregenerateCustomPalette generates inverted lightness scale when isDark=true (50=12%L → 800=93%L). Previously always generated light-mode values.
  • Unknown accent dark fallback — falls back to ACCENT_PALETTES_DARK.cobalt (not light ACCENT_PALETTES.cobalt) when accent key is unrecognized in dark mode.
  • CSS specificity comment corrected: branded/gradient dark override is 0,6,0 not 0,5,0.

v0.58.0 — YNEX Fidelity + Violet Accent

YNEX preset now matches the original YNEX admin template visual language:

  • Background #F0F1F7 (warm light gray), card no-border, 8px radius, bottom shadow
  • Sidebar 240px width, Montserrat font, z-index: 103, slim/collapsed → 72px
  • Header 60px height, z-index: 100
  • New accent: Violet (ThemeAccent.Violet, #845BDF) — matches YNEX primary

Fixes:

  • Accent="Bar" cards now work under YNEX (border:none shorthand was overriding border-inline-start)
  • Dark YNEX sidebar hover corrected to rgba(255,255,255,0.08) (was near-white, jarring on dark surface)
  • Dark Direction B text tokens (--color-text, --color-text-secondary, etc.) now defined — were falling through to dark-blue light-mode value, rendering illegible
@* Enable YNEX preset with Violet accent *@
await ThemeService.SetAsync(new ThemeOptions
{
 Preset = ThemePreset.Ynex,
 Direction = ThemeDirection.A,
 Accent = ThemeAccent.Violet,
 Mode = ColorMode.System
});

v0.57.0 — Mixed Mode for DetailList + AutoForm · Grid Metadata Attributes

BREAKING CHANGES
  • CayaquiBadgeVariantString parameter removed (was [Obsolete] since v0.40.0). Use Variant (enum CayaquiBadgeVariant) instead.
  • CayaquiAlertVariantString parameter removed (was [Obsolete] since v0.40.0). Use Variant (enum CayaquiAlertVariant) instead.

Migration:

@* Before (broken in 0.57.0) *@
<CayaquiBadge VariantString="success">Activo</CayaquiBadge>
<CayaquiAlert VariantString="warning" Title="Atención">...</CayaquiAlert>

@* After *@
<CayaquiBadge Variant="CayaquiBadgeVariant.Success">Activo</CayaquiBadge>
<CayaquiAlert Variant="CayaquiAlertVariant.Warning" Title="Atención">...</CayaquiAlert>
CayaquiDetailList — Mixed Mode (Source= + child overrides)

Source= auto-generates all items; CayaquiDetailItem For= children replace individual properties; CayaquiDetailItem without For= append at end.

<CayaquiDetailList Source="@dto" Columns="3">
 @* Override Status with custom badge *@
 <CayaquiDetailItem For="@(() => dto.Status)">
 <CayaquiBadge Variant="CayaquiBadgeVariant.Success">Activo (custom)</CayaquiBadge>
 </CayaquiDetailItem>

 @* Manual item appended after auto-generated ones *@
 <CayaquiDetailItem Label="Días desde inicio">
 @((DateTime.Today - (dto.StartDate ?? DateTime.Today)).Days) días
 </CayaquiDetailItem>
</CayaquiDetailList>
CayaquiAutoForm — Mixed Mode (ChildContent field overrides)

CayaquiAutoForm<TModel> auto-generates fields from DTO metadata; CayaquiAutoFormField<T> For= with ChildContent replaces auto-generated field; CayaquiAutoFormField<T> without For= adds a manual field.

<CayaquiAutoForm Model="@dto" OnValidSubmit="HandleSubmit">
 @* Override Status field with custom select *@
 <CayaquiAutoFormField For="@(() => dto.Status)" @bind-Value="dto.Status">
 <select ...>...</select>
 </CayaquiAutoFormField>

 @* Manual field appended at end *@
 <CayaquiAutoFormField Label="Notas internas">
 <CayaquiTextBox @bind-Value="_notes" />
 </CayaquiAutoFormField>
</CayaquiAutoForm>
Grid Metadata Attributes (Cayaqui.Metadata 0.5.0 required)

New [GridWidth(string)] and [GridFormat(string)] attributes for CayaquiAutoGrid column control:

public class BudgetDto
{
 [Label("Código WBS"), GridWidth("120")] public string WbsCode { get; set; }
 [Label("CPI"), GridWidth("80"), GridFormat("N2")] public decimal Cpi { get; set; }
 [Label("Descripción"), GridWidth("25%")] public string? Name { get; set; }
}

v0.56.0 — Metadata-Driven Detail Components

CayaquiDetailItem and CayaquiDetailList now auto-derive labels, formatting, and badges from DTO attributes via IExtendedPropertyResolver.

CayaquiDetailItem — For= parameter
@* Auto label + format from [Label], [Currency], [Date], [Badge] *@
<CayaquiDetailItem For="@(() => dto.Amount)" />

@* Explicit label override *@
<CayaquiDetailItem For="@(() => dto.Amount)" Label="Monto Total" />

@* Manual ChildContent override *@
<CayaquiDetailItem For="@(() => dto.Status)">
 <CayaquiBadge Variant="CayaquiBadgeVariant.Success">Activo</CayaquiBadge>
</CayaquiDetailItem>
CayaquiDetailList — Source= parameter
@* Auto-generate all visible properties from DTO *@
<CayaquiDetailList Source="@dto" Columns="3" />

DTO example:

public class ContractDto
{
 [Label("Código"), Display(Order = 1)] public string? Code { get; set; }
 [Label("Monto"), Display(Order = 2), Currency("USD", 0)] public decimal Amount { get; set; }
 [Label("Estado"), Display(Order = 3), Badge] public ContractStatus Status { get; set; }
 [Label("Inicio"), Display(Order = 4), Date("dd-MMM-yy")] public DateTime? StartDate { get; set; }
 [Hidden] public string? InternalId { get; set; }
}

public enum ContractStatus
{
 [BadgeColor(BadgeKind.Success)] Active,
 [BadgeColor(BadgeKind.Warning)] OnHold,
 [BadgeColor(BadgeKind.Error)] Closed
}

Requires DTO attributes from Cayaqui.Metadata: [Label], [Currency], [Date], [Badge], [BadgeColor], [Display(Order=n, GroupName="X")], [Hidden].


v0.55.0 — Preset Auto-Defaults + 4 New Components

Preset auto-defaults

ThemeService.SetAsync(preset: ...) now auto-applies canonical accent/density/radius when switching presets. Explicit parameters always override defaults.

Preset Accent Density RadiusScale
ThemePreset.Ynex Emerald Comfort 1.0
ThemePreset.Untitled Cobalt Comfort 1.0
await Theme.SetAsync(preset: ThemePreset.Untitled);
// → Accent=Cobalt, Density=Comfort, RadiusScale=1.0

await Theme.SetAsync(preset: ThemePreset.Untitled, accent: ThemeAccent.Indigo);
// → Accent=Indigo (caller wins), Density=Comfort, RadiusScale=1.0
New components
Component Namespace Description
CayaquiDivider DataDisplay Horizontal/vertical separator with optional label
CayaquiFeatureCard DataDisplay Clickeable card: icon + title + description
CayaquiDetailList + CayaquiDetailItem DataDisplay Grid label→value ficha with RenderFragment values
CayaquiStepIndicator + CayaquiStep Navigation Clickeable multi-step progress indicator
<CayaquiDivider Label="Información del contrato" />

<CayaquiFeatureCard Title="EVM" Icon="@CayaquiIcons.ChartBar" OnClick="@Navigate" />

<CayaquiDetailList Columns="2">
 <CayaquiDetailItem Label="Contrato">CNT-001</CayaquiDetailItem>
 <CayaquiDetailItem Label="Estado"><CayaquiBadge Variant="CayaquiBadgeVariant.Success">Activo</CayaquiBadge></CayaquiDetailItem>
</CayaquiDetailList>

<CayaquiStepIndicator @bind-ActiveStep="_step">
 <CayaquiStep Label="Datos" />
 <CayaquiStep Label="Revisión" />
 <CayaquiStep Label="Confirmar" />
</CayaquiStepIndicator>

v0.53.0 — YNEX Accent System

4 nuevas paletas de acento (Navy · Teal · Rose · Orange) + Custom accent picker con generador HSL en JS. ThemeSidebarTone global (Default/Tinted/Branded/Gradient/Transparent) vía data-cayaqui-sidebar. ThemeHeaderStyle global (Default/Color/Gradient) vía data-cayaqui-header. CayaquiSidebar.SidebarTone ampliado con Gradient + Transparent. CayaquiThemeSwitcher renovado con secciones de Sidebar Tone, Header Style y Custom Color Picker.

// Custom accent — genera rampa HSL completa desde cualquier hex
await Theme.SetAsync(accent: ThemeAccent.Custom, customAccentHex: "#7c3aed");

// Sidebar branded + header gradient en una sola llamada
await Theme.SetAsync(
 accent: ThemeAccent.Navy,
 sidebarTone: ThemeSidebarTone.Branded,
 headerStyle: ThemeHeaderStyle.Gradient);

v0.54.0 — UntitledUI v8-Inspired Theme

Nuevo tema visual paralelo al sistema YNEX, inspirado en UntitledUI v8. Se activa con data-cayaqui-theme="untitled" en <html> y coexiste con todos los acentos y el dark mode existentes.

Temas disponibles
ThemePreset ThemeGray data-cayaqui-theme data-cayaqui-gray Visual
Ynex (default) Direction A/B tradicional
Untitled Neutral (default) untitled Gray puro sin tinte (#FCFCFD bg)
Untitled Cool untitled cool Gray con tinte azul-frío (#F5F6FA bg)
Uso programático
// Activar tema Untitled neutral
await Theme.SetAsync(preset: ThemePreset.Untitled, gray: ThemeGray.Neutral);

// Activar tema Untitled cool + acento cobalt
await Theme.SetAsync(preset: ThemePreset.Untitled, gray: ThemeGray.Cool, accent: ThemeAccent.Cobalt);

// Volver al sistema YNEX direction A
await Theme.SetAsync(preset: ThemePreset.Ynex, direction: ThemeDirection.A);
ThemeOptions — nuevas propiedades
builder.Services.AddCayaquiComponents(o =>
{
 o.DefaultPreset = ThemePreset.Untitled; // nuevo: default al iniciar
 o.DefaultGray = ThemeGray.Cool; // nuevo: variante de gray para Untitled
 // ... resto de opciones sin cambios
});
Anti-FOUC para Untitled en App.razor
<script>
(function () {
 try {
 var s = localStorage.getItem('cayaqui-color-mode');
 if (s) {
 var t = JSON.parse(s);
 if (t.Mode === 1) document.documentElement.setAttribute('data-cayaqui-mode', 'dark');
 if (t.Preset === 1) { // 1 = ThemePreset.Untitled
 document.documentElement.setAttribute('data-cayaqui-theme', 'untitled');
 if (t.Gray === 1) // 1 = ThemeGray.Cool
 document.documentElement.setAttribute('data-cayaqui-gray', 'cool');
 }
 }
 } catch (_) {}
})();
</script>
ThemeState — campos añadidos (backwards-compat)

Preset y Gray se agregaron como parámetros opcionales con defaults al final del record. Implementaciones existentes de IThemePersistence que construyen ThemeState posicionalmente no requieren cambios — los nuevos campos usan sus defaults (Ynex / Neutral).


v0.52.6 — Fix: accordion sidebar CSS parse bug

Removes a stray } that caused the browser CSS parser to discard the CayaquiSidebar accordion base rule (max-height: 0; overflow: hidden). Submenus now correctly collapse/expand.


v0.52.5 — CayaquiSidebar accordion multinivel (YNEX-style)

CayaquiSidebarItem ahora soporta submenús declarativos y data-driven con transición CSS max-height.

@* Declarativo *@
<CayaquiSidebarItem Text="Control de Proyecto" Icon="@_icon">
 <CayaquiSidebarItem Text="Dashboard EVM" Href="/evm" />
 <CayaquiSidebarItem Text="Curva S" Href="/scurve" />
 <CayaquiSidebarItem Text="Flujo de Caja" Href="/cashflow" />
</CayaquiSidebarItem>

@* Data-driven *@
<CayaquiSidebarItem Text="Contratos"
 Icon="@_icon"
 Children="@_contractItems" />

En modo Slim / collapsed, los submenús aparecen como flyout popovers al hover. El sidebar aplica acordeón exclusivo (abrir uno cierra los demás al mismo nivel).


v0.52.0 — CayaquiChat · CayaquiTimeline (Layouts Premium) · CayaquiTaskCard · CayaquiTeamSparklineList · CayaquiThemeSwitcher

Esta versión incorpora componentes y layouts avanzados basados en el framework de diseño YNEX para la suite de controles interactivos corporativos de Cayaqui.

CayaquiChat — Centro de colaboración y mensajería interna (Design.DataDisplay)

Estructura de chat interactiva de dos paneles (sidebar de contactos con filtros/búsqueda y área de mensajes). Incluye un script JS aislado para auto-scroll dinámico.

<CayaquiChat Contacts="@_contacts"
 Messages="@_messages"
 CurrentUserId="@_myId"
 ActiveContactId="@_activeContactId"
 OnSendMessage="HandleSendMessage"
 OnActiveContactChanged="HandleContactChanged" />

CayaquiTimeline — Layouts avanzados (Design.DataDisplay)

Se expande el componente existente para soportar layouts Simple, Detailed (con avatares, sub-badges semánticos y detalles en cascada) y TwoColumns de alta densidad. Incluye botón diferido "Cargar más".

<CayaquiTimeline Items="@_detailedItems" Layout="CayaquiTimelineLayout.Detailed" EnableLoadMore="true" OnLoadMore="HandleLoadMore" />

CayaquiTaskCard — Tarjetas de tareas y entregables (Design.DataDisplay)

Tarjeta semáforo configurable por prioridad (Low, Medium, High, Critical), con soporte de estrella de favorito interactiva y responsables apilados (CayaquiAvatarGroup).

<CayaquiTaskCard Task="@_task" OnStarredChanged="HandleStarred" />

CayaquiTeamSparklineList — Lista de rendimiento con Sparklines (Design.DataDisplay)

Lista vertical compacta de colaboradores que muestra su rol, estado de conexión y tendencia de desempeño utilizando mini-gráficos Sparklines de ApexCharts.

<CayaquiTeamSparklineList Members="@_members" />

CayaquiThemeSwitcher — Panel lateral de configuración offcanvas (Design.Navigation)

Panel lateral offcanvas que expone selectores interactivos para personalizar el tema (Modo de color claro/oscuro, densidad de espaciado, radio de bordes y acento de color) en tiempo real con ThemeService. Incluye un botón flotante de engranaje autocontenido.

<CayaquiThemeSwitcher />

v0.51.0 — CayaquiWorkflowEditor · CayaquiWorkflowMini · CayaquiFullscreenToggle · CayaquiReconnectModal

CayaquiWorkflowEditor + CayaquiWorkflowMini — Pipeline de aprobación genérico (Engineering.Workflow)

Visualización y edición de pipelines de aprobación. Nodos configurables vía parámetros — no hay roles hardcodeados. CayaquiWorkflowEditor es interactivo (toggle por click + presets); CayaquiWorkflowMini es compacto y read-only.

Tipos: CayaquiWorkflowEditor.NodeDef(Key, Label, Title, IsFixed, IsTerminal) · CayaquiWorkflowEditor.Preset(Label, ActiveKeys)

@* Define nodos y presets específicos de la app *@
@code {
 private static readonly IReadOnlyList<CayaquiWorkflowEditor.NodeDef> _nodes =
 [
 new("start", "Ini", "Inicio", IsFixed: true),
 new("review", "Rev", "Revisión", IsFixed: false),
 new("approval", "Apr", "Aprobación", IsFixed: false),
 new("end", "✓", "Completado", IsFixed: true, IsTerminal: true),
 ];

 private static readonly IReadOnlyList<CayaquiWorkflowEditor.Preset> _presets =
 [
 new("Mínimo", []),
 new("Completo", ["review", "approval"]),
 ];

 private IReadOnlyList<string> _activeKeys = ["review", "approval"];
}

@* Editor interactivo *@
<CayaquiWorkflowEditor Nodes="_nodes"
 Presets="_presets"
 @bind-ActiveKeys="_activeKeys" />

@* Vista compacta (ej. en una tabla) *@
<CayaquiWorkflowMini Nodes="_nodes" ActiveKeys="_activeKeys" />

Namespace: @using Cayaqui.Components.Engineering.Workflow (incluido en _Imports.razor global de 0.51.0+).


CayaquiFullscreenToggle — Botón fullscreen browser (Design.Navigation)

Botón que alterna document.documentElement.requestFullscreen() / document.exitFullscreen(). Sincroniza estado con el evento fullscreenchange.

Setup requerido — agregar en App.razor antes de </body>:

<script src="_content/Cayaqui.Components/js/cayaqui-fullscreen.js"></script>
@* Uso básico — colocar donde quieras el botón (ej. AppHeader) *@
<CayaquiFullscreenToggle />

@* Con labels en inglés *@
<CayaquiFullscreenToggle EnterLabel="Full screen"
 ExitLabel="Exit full screen"
 Class="my-fullscreen-btn" />

El JS expone window.mpsFullscreen (distinto de cualquier fullscreenToggle legacy). Si el browser bloquea la API (ej. iframe sin allow-fullscreen), el botón es silencioso — no rompe la UI.


CayaquiReconnectModal — Diálogo de reconexión Blazor Server (Design.Feedback)

Diálogo <dialog> nativo que gestiona los estados de reconexión del circuito SignalR de Blazor Server. Todos los textos son [Parameter] para i18n.

Setup requerido — en App.razor, DESPUÉS de blazor.web.js:

<script src="@Assets["_framework/blazor.web.js"]"></script>
<script type="module" src="_content/Cayaqui.Components/js/cayaqui-reconnect.js"></script>

Uso en App.razor (reemplaza <ReconnectModal /> custom):

<body>
 <Routes @rendermode="InteractiveServer" />
 <CayaquiReconnectModal /> @* ← aquí *@

 <script src="_content/Syncfusion.Blazor.Core/scripts/syncfusion-blazor.min.js"></script>
 <script src="_content/Cayaqui.Components/js/cayaqui-theme.js"></script>
 <script src="_content/Cayaqui.Components/js/cayaqui-fullscreen.js"></script> @* si usas CayaquiFullscreenToggle *@
 <script src="@Assets["_framework/blazor.web.js"]"></script>
 <script type="module" src="_content/Cayaqui.Components/js/cayaqui-reconnect.js"></script>
</body>
@* Textos personalizados (todos tienen defaults en español) *@
<CayaquiReconnectModal FirstAttemptText="Reconnecting to server…"
 FailedText="Connection lost. Please reload."
 RetryLabel="Retry"
 ResumeLabel="Resume" />

v0.49.6 — CayaquiCardGroup: MaxCardWidth

  • CayaquiCardGroup gana parámetro MaxCardWidth (default "1fr"). Permite MinCardWidth="280px" MaxCardWidth="400px" para grids con ancho acotado.

v0.49.5 — CayaquiGauge absorbe CpiGauge/SpiGauge · CayaquiDeltaChip absorbe VariancePill/TrendDelta

  • CayaquiGauge gana parámetro Preset = GaugePreset.Cpi | Spi | None. Elimina necesidad de CayaquiCpiGauge y CayaquiSpiGauge.
  • CayaquiDeltaChip nuevo componente unificado (Variant = DeltaVariant.Variance | Trend). Elimina CayaquiVariancePill y CayaquiTrendDelta.
  • Migración: <CayaquiCpiGauge><CayaquiGauge Preset="CayaquiGauge.GaugePreset.Cpi">. <CayaquiTrendDelta Period="WoW"><CayaquiDeltaChip Variant="CayaquiDeltaChip.DeltaVariant.Trend" Period="WoW">.

v0.49.4 — Fix: CayaquiGrid Number columns respetan cultura del sistema

  • CayaquiGridColumn kind Number usaba CultureInfo.InvariantCulture → separadores incorrectos en es-CL y otros locales.
  • Corregido a CultureInfo.CurrentCulture — valores numéricos ahora usan los separadores del sistema (ej. es-CL: 1.234.567).

v0.49.3 — CayaquiProgressSCurve absorbe CayaquiPhysicalProgressCurve

  • CayaquiPhysicalProgressCurve eliminado — su funcionalidad (curva S clásica, solo líneas) vive ahora en CayaquiProgressSCurve con ShowPartialBars="false".
  • ProgressSCurvePoint gana BaselineCumulative? (antes BaselinePct? del componente eliminado).
  • Migración: reemplazar <CayaquiPhysicalProgressCurve><CayaquiProgressSCurve ShowPartialBars="false"> y renombrar propiedades: BaselinePct→BaselineCumulative, PlanPct→PlanCumulative, ActualPct→ActualCumulative, ForecastPct→ForecastCumulative.

v0.49.2 — IntelliSense XML docs para todos los componentes

  • GenerateDocumentationFile habilitado — el .xml de IntelliSense se empaqueta junto al DLL.
  • 876 parámetros [Parameter] ahora tienen /// <summary> en los 181 componentes (Design, Evm, Engineering).
  • Sin cambios de API ni binarios.

v0.49.1 — CayaquiCardGroup

  • CayaquiCardGroup: contenedor grid que iguala la altura de todos los cards de cada fila. Auto-fill responsive por defecto; parámetro Columns para columnas fijas.

v0.48.3 — ConfirmDialog: X-button OnCancel, CloseOnOverlayClick=false, CSS

  • ConfirmDialog: cerrar con X button o overlay ahora dispara OnCancel (antes se ignoraba).
  • CloseOnOverlayClick default cambiado a false (evita dismiss accidental en acciones destructivas).
  • CSS movido de cayaqui-indicators.csscayaqui-syncfusion-overrides.css (sección dialog).
  • Variant Warning: color ámbar aplicado en estado normal + hover; eliminados fallback hex.

v0.48.2 — CashflowChart: eje Y sin sufijo (es-CL), Curve.Straight

  • Etiquetas eje Y: Intl.NumberFormat('es-CL') sin sufijo kUSD (el título del eje ya lo indica). Ej. "25.000" en vez de "25000.0 kUSD".
  • Curve.Straight reemplaza Curve.Smooth — elimina el overshoot visual que extendía la línea "Real acum." más allá del mes de control.

v0.48.1 — CashflowChart: ejes Y en kUSD con 1 decimal

  • CashflowChart: ambos ejes Y usan (v/1000).toFixed(1) + ' kUSD' — etiquetas y títulos muestran "Acumulado (kUSD)" / "Mensual (kUSD)".
  • GanttChart: columnas Real% y Plan% con Format="N1".

v0.48.0 — Design audit: CSS quality, dark mode, accesibilidad

Breaking changes — ver BREAKING_CHANGES_v0.48.md.

  • Eliminados selectores WbsKanban legacy (display:grid en .cayaqui-kanban, .cayaqui-kanban-body, .phase-*) que nunca matcheaban el DOM real.
  • KpiCard: inline styles → clases CSS; nuevo parámetro Size (KpiSize.Md/Sm).
  • GaugeTile: corregido token --color-text-primary (no existía) → --color-text; marker visible en dark mode.
  • RiskHeatmap level-critical: contraste 3.3:1 → 6.1:1 (WCAG AA) con error-700 + texto blanco.
  • --color-hover definido en tokens (causaba hover invisible en ChangeOrderLog).
  • prefers-reduced-motion activo en toda la librería.
  • CayaquiDomainHeader dark mode adaptativo.

v0.44.2–0.44.3 — Fix: ArgumentException en 6 componentes de chart

EvmCashflowCurve, PhysicalProgressCurve, CayaquiProgressSCurve, ContingencyDrawdown, CashflowChart y CayaquiTimelineChart lanzaban ArgumentException en DateTimeOffset..ctor(DateTime, TimeSpan.Zero) cuando el parámetro de fecha (p.ej. ControlDate, StartField, EndField) tenía DateTimeKind.Local — que es el Kind que devuelve DateTime.Today y DateTime.Now. Todos los componentes ahora usan DateTime.SpecifyKind(x.Date, DateTimeKind.Utc) internamente: acepta cualquier Kind sin excepción. Sin breaking changes.


v0.44.0 — CayaquiListGroup + CayaquiFileManager + Migración ApexCharts

Nuevos componentes:

  • CayaquiListGroup — Lista estilizada model-driven con items accionables. Soporte para icono leading, subtítulo, badge trailing (CayaquiBadgeVariant), selección (@bind-SelectedItemId), estado Disabled, variante Flush e ItemTemplate custom.
<CayaquiListGroup Items="_items" @bind-SelectedItemId="_selectedId" />

@code {
 private readonly CayaquiListGroupItem[] _items =
 [
 new("1", "Planos estructurales", Subtitle: "Ingeniería Civil",
 Icon: "e-icons e-folder", BadgeText: "12", BadgeVariant: CayaquiBadgeVariant.Brand),
 new("2", "Especificaciones técnicas"),
 new("3", "Bloqueado", Disabled: true),
 ];
 private string? _selectedId;
}
  • CayaquiFileManager — Browser de archivos/documentos con vista Grid (tarjetas) y Lista (tabla). Toggle de vista integrado (@bind-ViewMode). Auto-detección de icono por extensión (.pdf, .dwg, .docx, .xlsx, imágenes, .zip). Callbacks OnOpen y OnDelete. El consumer provee IReadOnlyList<CayaquiFileItem> — sin dependencia de sistema de archivos.
<CayaquiFileManager Items="_files"
 Title="Documentos del Proyecto"
 @bind-ViewMode="_view"
 OnOpen="f => NavigateTo(f.Id)"
 OnDelete="f => RemoveFile(f.Id)" />

@code {
 private CayaquiFileItem[] _files =
 [
 new("f1", "Plano-Estructura.pdf", Category: "Planos",
 SizeBytes: 1_420_000, UpdatedAt: DateTime.UtcNow.AddDays(-3)),
 new("f2", "Especificaciones.docx", Category: "Specs", SizeBytes: 85_000),
 new("d1", "Carpeta Ingeniería", IsFolder: true),
 ];
 private CayaquiFileViewMode _view = CayaquiFileViewMode.Grid;
}

Migración Syncfusion Charts → ApexCharts completada:

Todos los componentes de chart han sido migrados a ApexCharts. Los paquetes Syncfusion.Blazor.Charts y Syncfusion.Blazor.Sparkline han sido eliminados de las dependencias del paquete. CayaquiSparkline reescrito como SVG puro (sin dependencia JS).

Componentes migrados (17 total): BarChart, StackedBarChart, DonutChart, MonteCarloHistogram, BurndownChart, Waterfall, CommodityPriceChart, ManagementReserveTracker, ProductionCurve, ResourceHistogram, ContingencyDrawdown, EvmCashflowCurve, PhysicalProgressCurve, EvmControlChart, CashflowChart, CpiIndicator, SpiIndicator.

Sin breaking changes en la API pública.

Acción requerida para consumers: Si en tu propio .csproj tenías una referencia a Syncfusion.Blazor.Charts o Syncfusion.Blazor.Sparkline únicamente porque era dependencia transitiva de este paquete, puedes eliminarla con seguridad. Si la usas directamente, consérvala.

EvmCashflowCurve — Curva S EVM monetaria

4 series EVM sobre un gráfico ApexCharts: Plan (PV) azul, Earned Value (EV) área púrpura, Actual Cost (AC) rojo, Forecast (EAC) verde dashed. Anotación horizontal BAC + anotación vertical de fecha de control con etiqueta rotada −90°. Pie con título y fecha.

<EvmCashflowCurve Points="@_points"
 Bac="10_000_000m"
 ControlDate="@_controlDate"
 Title="Talara U3"
 Currency="USD" />

@code {
 private readonly DateTime _controlDate = new DateTime(2026, 4, 1);

 private readonly EvmCashflowCurve.EvmCashflowPoint[] _points =
 [
 new() { Date = new DateTime(2026,1,1), Pv = 1_200_000m },
 new() { Date = new DateTime(2026,2,1), Pv = 2_800_000m, Ev = 2_600_000m, Ac = 2_750_000m },
 new() { Date = new DateTime(2026,3,1), Pv = 4_500_000m, Ev = 4_100_000m, Ac = 4_300_000m },
 new() { Date = new DateTime(2026,4,1), Pv = 6_200_000m, Ev = 5_600_000m, Ac = 5_900_000m },
 new() { Date = new DateTime(2026,5,1), Pv = 7_800_000m, Forecast = 8_400_000m },
 new() { Date = new DateTime(2026,6,1), Pv = 9_100_000m, Forecast = 9_800_000m },
 new() { Date = new DateTime(2026,7,1), Pv = 10_000_000m, Forecast = 10_800_000m },
 ];
}
Parámetro Tipo Default Descripción
Points ⚠️ IList<EvmCashflowPoint> Requerido.
Bac decimal? null Budget At Completion — línea horizontal de referencia.
ControlDate DateTime? null Data date — línea vertical dashed + etiqueta. Acepta cualquier DateTimeKind.
Title string "" Título en el pie del chart.
ControlDateLabel string "Control al" Prefijo de la etiqueta de fecha de control.
Currency string "USD" Código ISO 4217 — se incluye en los nombres de serie.
Height string "360" Alto en px.
YAxisTitle string "" Título del eje Y.
Class string? null Clase CSS adicional para el contenedor raíz.

EvmCashflowPoint (clase anidada pública):

Propiedad Tipo Descripción
Date DateTime Fecha del punto (eje X).
Pv decimal? Planned Value.
Ev decimal? Earned Value. null para meses futuros.
Ac decimal? Actual Cost. null para meses futuros.
Forecast decimal? EAC proyectado. Solo en meses > ControlDate.

PhysicalProgressCurve — Curva S de avance físico (%)

4 series en porcentaje: Baseline (gris dashed, opcional), Plan (azul), Real (rojo con markers) y Forecast (verde dashed). Meta al 100% como línea horizontal. Anotación vertical de fecha de control.

<PhysicalProgressCurve Points="@_curve"
 ControlDate="@_controlDate"
 Title="Avance Físico · Talara U3" />

@code {
 private readonly DateTime _controlDate = new DateTime(2026, 4, 1);

 private readonly PhysicalProgressCurve.ProgressCurvePoint[] _curve =
 [
 new() { Date = new DateTime(2026,1,1), PlanPct=8m, ActualPct=7m },
 new() { Date = new DateTime(2026,2,1), PlanPct=18m, ActualPct=17m },
 new() { Date = new DateTime(2026,3,1), PlanPct=30m, ActualPct=27m },
 new() { Date = new DateTime(2026,4,1), PlanPct=43m, ActualPct=38m },
 new() { Date = new DateTime(2026,5,1), PlanPct=57m, ForecastPct=52m },
 new() { Date = new DateTime(2026,6,1), PlanPct=72m, ForecastPct=68m },
 new() { Date = new DateTime(2026,7,1), PlanPct=85m, ForecastPct=82m },
 new() { Date = new DateTime(2026,8,1), PlanPct=100m, ForecastPct=100m },
 ];
}
Parámetro Tipo Default Descripción
Points ⚠️ IList<ProgressCurvePoint> Requerido.
ControlDate DateTime? null Data date — línea vertical dashed + etiqueta. Acepta cualquier DateTimeKind.
Title string "" Título en el pie del chart.
ControlDateLabel string "Control al" Prefijo de la etiqueta de fecha de control.
YMax decimal 100 Máximo del eje Y. Cambiar si la escala no es 0–100.
ShowGoalLine bool true Muestra/oculta la línea horizontal al 100% (o YMax).
Height string "360" Alto en px.
YAxisTitle string "" Título del eje Y.
Class string? null Clase CSS adicional para el contenedor raíz.

ProgressCurvePoint (clase anidada pública):

Propiedad Tipo Descripción
Date DateTime Fecha del punto (eje X).
BaselinePct decimal? Baseline original (gris dashed). Omitir si no aplica.
PlanPct decimal? Plan vigente.
ActualPct decimal? Avance real. Solo para puntos ≤ ControlDate.
ForecastPct decimal? Pronóstico. Solo para puntos > ControlDate.

v0.43.0 — CayaquiProgressSCurve (Curva S ApexCharts)

Curva S de avance físico con barras periódicas + líneas acumuladas:

  • CayaquiProgressSCurve — Gráfico mixto ApexCharts (Bar + Line) para Plan, Real y Forecast. Paleta EVM canónica. Anotaciones de ControlDate y meta 100%. El consumer provee parciales y acumulados de forma explícita.
<CayaquiProgressSCurve Points="@_scurve"
 ControlDate="@_controlDate"
 Title="Avance Físico · Talara U3" />

@code {
 private static readonly DateTime _controlDate = new DateTime(2025, 5, 1);

 private CayaquiProgressSCurve.ProgressSCurvePoint[] _scurve =
 [
 new() { Date = new DateTime(2025,1,1), PlanPartial=8m, PlanCumulative=8m, ActualPartial=7m, ActualCumulative=7m },
 new() { Date = new DateTime(2025,5,1), PlanPartial=14m, PlanCumulative=59m, ActualPartial=12m, ActualCumulative=52m },
 new() { Date = new DateTime(2025,6,1), PlanPartial=13m, PlanCumulative=72m, ForecastPartial=14m, ForecastCumulative=66m },
 new() { Date = new DateTime(2025,8,1), PlanPartial=13m, PlanCumulative=100m, ForecastPartial=18m, ForecastCumulative=100m },
 ];
}

v0.42.0 — Engineering Progress Control Table

Tabla de control de avance para ingeniería de proyectos EPC:

  • CayaquiEngProgressTable — Tabla Plan/Forecast/Actual/Var por documento con columnas de hitos configurables. Cálculo automático de avance ponderado y reglas de color por fecha de control.
<CayaquiEngProgressTable Documents="@_docs"
 Milestones="@_milestones"
 ControlDate="@_controlDate"
 Title="Control de Avance de Ingeniería" />

v0.41.0 — Engineering Document Control

Tres componentes atómicos para gestión de entregables de ingeniería:

  • CayaquiDocStatusBadge — Badge de estado libre. El consumer mapea sus códigos (IFC, IFA, IFR…) a 5 variantes de color.
  • CayaquiDocRevisionList — Lista de revisiones con activa destacada, fecha, razón de emisión y link de descarga.
  • CayaquiDocCard — Card completa: número, disciplina, tipo, revisión activa, HH presupuestado vs real, revisiones colapsables, upload drag & drop opcional.
<CayaquiDocCard Document="@_doc"
 StatusVariantResolver="@(s => s switch {
 "IFC" => CayaquiDocStatusBadge.BadgeVariant.Success,
 "IFA" => CayaquiDocStatusBadge.BadgeVariant.Warning,
 "IFR" => CayaquiDocStatusBadge.BadgeVariant.Info,
 _ => CayaquiDocStatusBadge.BadgeVariant.Neutral })"
 ShowUploader="true"
 OnFilesSelected="@HandleFiles" />

v0.40.0 — CayaquiCalendar (FullCalendar 6)

Calendario interactivo completo basado en FullCalendar 6.x (bundle incluido en el paquete):

  • CayaquiCalendar — Calendario con vistas Mes, Semana, Día y Agenda. Soporte drag-drop, resize, click en eventos y click en fechas.
  • CayaquiCalendarEvent — DTO para eventos (Id, Title, Start, End, AllDay, Color, Category).
  • CayaquiCalendarEventMoveArgs — DTO para callbacks de drag/resize (EventId, NewStart, NewEnd).
@* Registro del script en App.razor *@
<script src="_content/Cayaqui.Components/js/cayaqui-calendar.js"></script>

@* Uso básico en la página *@
<CayaquiCalendar Events="@_events"
 View="CayaquiCalendar.CalendarView.Month"
 Editable="true"
 OnEventClick="@HandleEventClick"
 OnDateClick="@HandleDateClick"
 OnEventDrop="@HandleEventDrop" />

@code {
 private List<CayaquiCalendarEvent> _events = new()
 {
 new CayaquiCalendarEvent { Id = "1", Title = "Reunión", Start = DateTime.Today.AddDays(1), AllDay = true },
 new CayaquiCalendarEvent { Id = "2", Title = "Visita", Start = DateTime.Today.AddHours(10), End = DateTime.Today.AddHours(12) },
 };

 private void HandleEventClick(CayaquiCalendarEvent ev) => Console.WriteLine($"Click: {ev.Title}");
 private void HandleDateClick(DateTime date) => Console.WriteLine($"Fecha: {date:dd-MMM-yy}");
 private void HandleEventDrop(CayaquiCalendarEventMoveArgs a) => Console.WriteLine($"Movido a: {a.NewStart:dd-MMM-yy}");
}

Demo vivo: /catalog/calendar.


v0.39.0 — Track 2: CayaquiHeatmapChart + CayaquiTimelineChart (ApexCharts)

Dos nuevos componentes de gráficos basados en Blazor-ApexCharts 6.1.0:

  • CayaquiHeatmapChart<TItem> — Agrupa datos planos por RowField en series y renderiza un heatmap. Params: Data, RowField, ColField, ValueField, Title, Height.
  • CayaquiTimelineChart<TItem> — Gráfico de barras horizontales tipo Gantt (range-bar). Agrupa por GroupField en series y convierte DateTime a Unix ms. Params: Data, NameField, GroupField, StartField, EndField, Title, Height.
@* Heatmap: avance % por disciplina y semana *@
<CayaquiHeatmapChart TItem="HeatCell"
 Data="@_heatmap"
 RowField="@(x => x.Discipline)"
 ColField="@(x => x.Week)"
 ValueField="@(x => (decimal?)x.Progress)" />

@* Timeline (Gantt-style): fases de proyecto *@
<CayaquiTimelineChart TItem="Phase"
 Data="@_timeline"
 NameField="@(x => x.Name)"
 GroupField="@(x => x.Discipline)"
 StartField="@(x => x.Start)"
 EndField="@(x => x.End)" />

Demo vivo: /catalog/charts (incluye los 6 chart components: Area, Scatter, Funnel, Treemap, Heatmap, Timeline).


v0.38.0 — Track 1: 6 nuevos componentes CSS sin dependencias adicionales

CayaquiSpinner, CayaquiAvatar, CayaquiAvatarGroup, CayaquiInputGroup, CayaquiFloatingLabel, CayaquiFormWizard.

@* Spinner de carga — 4 tamaños, 6 colores *@
<CayaquiSpinner Size="CayaquiSpinner.SpinnerSize.Md" Color="CayaquiSpinner.SpinnerColor.Primary" />

@* Avatar con iniciales determinísticas o imagen *@
<CayaquiAvatar Name="Pedro Vera" Size="CayaquiAvatar.AvatarSize.Md" />
<CayaquiAvatar Name="María López" Src="@user.AvatarUrl" Shape="CayaquiAvatar.AvatarShape.Circle" />

@* Stack de avatares con badge de overflow *@
<CayaquiAvatarGroup Avatars="@_equipo" Max="4" />

@* Input con addons de texto *@
<CayaquiInputGroup Prefix="$" Suffix="USD">
 <CayaquiTextBox Placeholder="Costo estimado" />
</CayaquiInputGroup>

@* Floating label — el input DEBE tener Placeholder=" " (espacio) *@
<CayaquiFloatingLabel Label="Nombre del proyecto" InputId="fl-nombre">
 <CayaquiTextBox Placeholder=" " @bind-Value="@_nombre" />
</CayaquiFloatingLabel>

@* Wizard multi-paso con validación async por step *@
<CayaquiFormWizard OnFinish="HandleFinish" FinishLabel="Crear Proyecto">
 <CayaquiFormWizardStep Title="Datos generales">
 
 </CayaquiFormWizardStep>
 <CayaquiFormWizardStep Title="Presupuesto" OnValidate="ValidarPresupuesto">
 
 </CayaquiFormWizardStep>
</CayaquiFormWizard>

CayaquiSpinner: tamaños Xs/Sm/Md/Lg, colores Primary/Muted/White/Success/Warning/Danger. Respeta prefers-reduced-motion. CayaquiAvatar: tamaños Xs/Sm/Md/Lg/Xl, formas Circle/Square. Color de iniciales determinístico (paleta de 8 colores semánticos). CayaquiAvatarGroup: parámetros Avatars (IReadOnlyList<CayaquiAvatarSpec>) y Max (default 4). CayaquiInputGroup: clase raíz cayaqui-input-addon-group. Props Prefix, Suffix, PrefixIcon, SuffixIcon. CayaquiFloatingLabel: requiere Placeholder=" " en el input hijo. InputId para asociación accesible. CayaquiFormWizardStep: parámetros Title, OnValidate (Func<Task<bool>>?). Sin parámetro Icon.


v0.37.0 — Gestión de imágenes y fotos: CayaquiPhotoCard · CayaquiPhotoGallery · CayaquiPhotoUploader · CayaquiAvatarUploader

4 componentes nuevos para el flujo EPC de fotos de campo (iPhone → procesado → galería + lightbox). Integración callback-based — Cayaqui.Components no depende de Cayaqui.Images ni Cayaqui.Storage.

@* Galería con lightbox EXIF — pure Blazor, sin JS *@
<CayaquiPhotoGallery Items="_fotos" MaxVisible="5" OnDelete="HandleDelete" />

@* Uploader con preview inmediato y progreso por foto *@
<CayaquiPhotoUploader OnUpload="HandleUpload" OnUploaded="HandleUploaded"
 MaxPhotos="10" MaxParallel="3" />

@* Avatar circular con spinner y rollback en error *@
<CayaquiAvatarUploader OnUpload="HandleUpload" CurrentName="@_user.FullName"
 Size="CayaquiAvatarUploaderSize.Lg" />

AttachmentList actualizado: nuevo parámetro ShowImagePreview (default false) — muestra thumbnail 40×40 inline para extensiones de imagen.


v0.36.0 — CayaquiSegmented: Variants, Sizes, FullWidth y Disabled por ítem

CayaquiSegmented<TValue> rediseñado con estilo Pill/Float y API completa. Corrige el CSS class mismatch que impedía que el componente tuviera estilos visuales.

<CayaquiSegmented TValue="string"
 Value="@_view"
 ValueChanged="v => _view = v"
 Options="@_opts"
 Variant="CayaquiSegmentedVariant.Accent"
 Size="CayaquiSegmentedSize.Sm"
 FullWidth="true" />

@code {
 private string _view = "kanban";
 private static readonly IReadOnlyList<CayaquiSegmented<string>.Option> _opts =
 [
 new("lista", "Lista", "e-icons e-list"),
 new("kanban", "Kanban", "e-icons e-kanban"),
 new("gantt", "Gantt", "e-icons e-gantt", Disabled: true),
 ];
}

Variantes: Default · Accent · Success · Warning · Danger Tamaños: Sm · Md (default) · Lg FullWidth: false por default — true estira al 100% del contenedor Disabled por ítem: new Option(value, label, icon, Disabled: true) — grisado, no clickeable


v0.35.0 — KpiCard variants, CayaquiDomainHeader, CayaquiKpiTile, CayaquiGaugeTile


v0.34.0 — Skeleton composites para arquetipos de loading-state

Cinco composites nuevos sobre CayaquiSkeleton cubren los arquetipos comunes de loading-state — eligen el correcto y reducís layout shift sin reinventar el primitivo:

<CayaquiSkeletonStack /> @* N líneas (forms, sidebars, párrafos) *@
<CayaquiSkeletonCard Height="280px" /> @* header + rect (chart placeholder) *@
<CayaquiSkeletonRow /> @* avatar + título + subtítulo *@
<CayaquiSkeletonGrid /> @* 1×4 KPI strip por default *@
<CayaquiSkeletonTable Rows="15" /> @* toolbar + 15 filas *@

Composición típica de dashboard:

@if (_loading)
{
 <CayaquiSkeletonGrid Rows="1" Columns="4" /> @* KPI strip *@
 <CayaquiSkeletonCard Height="280px" /> @* chart *@
 <CayaquiSkeletonTable Rows="6" ShowToolbar="false" /> @* tabla resumen *@
}

Todos consumen internamente <CayaquiSkeleton/> (heredan shimmer + prefers-reduced-motion). +37 tests bUnit (798 total). Sin breaking changes — son aditivos sobre la v0.33.0. Ver scripts/migrate-to-components-0.34.0.md para recetas por arquetipo.


v0.33.0 — CayaquiSkeleton runtime fix

Bug crítico runtime (presente desde la primera versión): CayaquiSkeleton.razor rendereaba <div class="cayaqui-skeleton ..."> pero la regla CSS empacada era solo .skeleton. El componente nunca aplicó shimmer ni estilos en consumidores. En 0.33.0 la clase y el markup quedan alineados (.cayaqui-skeleton), @keyframes shimmer se namespacea como cayaqui-skeleton-shimmer, y se agregan defaults dimensionales por shape:

<CayaquiSkeleton /> @* line · 100% × 0.875rem *@
<CayaquiSkeleton Shape="rect" /> @* rect · 100% × 6rem *@
<CayaquiSkeleton Shape="circle" /> @* circle · 2.5rem × 2.5rem *@

<CayaquiSkeleton /> sin parámetros ahora es visible. Cualquier llamada que ya pasaba Width/Height mantiene el override. Soporte prefers-reduced-motion: reduce (WCAG 2.3.3). +7 tests bUnit (761 total).

Acción opcional para consumers: si tu app aplicó el hotfix consumer-side (regla .cayaqui-skeleton en wwwroot/app.css), podés removerlo — el paquete ya la incluye. Ver scripts/migrate-to-components-0.33.0.md. Sin breaking changes.


v0.32.0 — CayaquiPageHeader browser tab + Double/TripleProgress 90% opacidad

Fix bug: la versión anterior tenía <PageTitle>@Title - MOVES</PageTitle> hardcodeado en CayaquiPageHeader — toda app no-MOVES recibía "MOVES" en sus pestañas. Ahora el sufijo es configurable vía ThemeOptions.AppName:

// Program.cs
builder.Services.AddCayaquiComponents(o => o.AppName = "Mi App");

CayaquiPageHeader emite automáticamente <PageTitle>{Title} · {AppName}</PageTitle>. Overrides:

  • SetBrowserTab="false" → no emite (tu page maneja su propio <PageTitle>).
  • BrowserTabTitle="Corto" → título distinto al del header visual.
  • BrowserTabSuffix="Demo" → sufijo por instancia (override de AppName).
  • BrowserTabSuffix="" → fuerza sin sufijo.

DoubleProgress / TripleProgress: barras a 90% opacidad (antes 50%) para mejor legibilidad EVM.


v0.31.0 — CashflowChart leyenda en CutOffDate

La leyenda del chart ahora se renderiza como HTML propio debajo del gráfico, con dos grupos:

  • Mes de cutoff · valor del mes de control para Plan / Real / Forecast (columnas). Forecast muestra el total restante.
  • Acumulado al cutoff · cumulativos al cierre de la fecha de control. Forecast acum. = EAC (Real cum + Forecast restante).

Si CutOffDate es null, la leyenda muestra los totales del rango. Cada entrada usa MoneyDisplay (formato consistente con el resto del design system) y un swatch que replica el estilo visual del chart (columnas 65% opacidad, líneas sólidas, Forecast acum. dashed verde).

Sin cambios de API. Helper estático CashflowChart.ComputeLegendValues(raw, cutOff) para tests. Migración: si testeás contra .cf-summary (header anterior), migrá a .cf-legend.


v0.30.0 — CashflowChart con acumulados

CashflowChart ahora muestra columnas mensuales + líneas acumuladas en el mismo gráfico (eje Y secundario):

  • Columnas (eje primario, monto mensual): Plan en todos los meses, Real ≤ CutOffDate, Forecast > CutOffDate (filtrado automático).
  • Líneas acumuladas (eje secundario): Plan acum., Real acum., Forecast acum. — esta última arranca en el Real acum. del cutoff para continuidad visual con la línea Real.
<CashflowChart Points="@cashflow"
 Currency="USD"
 CutOffDate="@DateTime.Today"
 Title="Cashflow mensual · Talara U3" />

ShowCumulative="false" para volver al aspecto 0.29.x (sólo columnas). El parámetro ControlDate queda como alias retro-compat de CutOffDate. Sin breaking de API; +10 tests; demo en /catalogo/evm#CashflowChart.


v0.29.0 — Tipografía dual Cayaqui (Inter + Roboto Condensed)

Convención:

  • Inter → cuerpo, labels, títulos, botones — "el resto del contenido".
  • Roboto Condensed → charts, tablas, valores numéricos, KPIs, paginadores, códigos tabulares.
  • JetBrains Mono (reservado para --font-mono / .kbd) → atajos de teclado, snippets de código.

Tokens nuevos:

:root {
 --font-sans: 'Inter', system-ui, -apple-system, sans-serif;
 --font-numeric: 'Roboto Condensed', 'Inter', system-ui, sans-serif;
 --font-table: var(--font-numeric);
 --font-chart: var(--font-numeric);
 --font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
}

Recomendación de loading (LCP óptimo). cayaqui-tokens.css ya trae un @import con las fuentes/pesos, pero @import bloquea el render. Para tu host page preferí <link> en App.razor:

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet"
 href="https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@300;400;500;700&family=Inter:wght@300;400;500;600;700&display=swap">

Aplicado automáticamente a:

  • Charts: SfChart, AccumulationChart, StockChart, RangeNavigator, Sparkline, Gauges, Gantt, PivotView (vía selector text SVG).
  • Grids: SfGrid, SfTreeGrid, SfGantt + tablas custom (.cayaqui-table, .cayaqui-po-table, .cayaqui-deliv-table, .cayaqui-risk-table, .cayaqui-svt-table).
  • Componentes con valores numéricos: MoneyDisplay, CayaquiCounter, CayaquiRangeSlider, CurrencyInput, KpiCard, CpiIndicator, EarnedScheduleIndicator, VarianceIndicator, ResourceHistogram, StockpileLevel, R9cTable, PurchaseOrderRegister, AttachmentList, DonutChart, CayaquiGauge, CayaquiBulletGauge.

Override por consumer (mantener apariencia 0.28.x con JetBrains Mono en valores numéricos):

:root { --font-numeric: var(--font-mono); }

Sin breaking changes.


v0.28.0 — Theme SSR (elimina FOUC)

Si tu app usa un DefaultAccent distinto a Emerald, el cold load mostraba un flash visible de Emerald → tu accent (~300ms). Causa: la paleta vivía como CSS estático Emerald + JS interop que la reescribía post-paint. Fix: nuevos selectors :root[data-cayaqui-accent="..."] + helper CayaquiThemeAttributes para SSR.

Patrón canónico (sin más workarounds inline). Dos piezas en App.razor:

  1. Accent / direction / density / sidebar / headerCayaquiThemeAttributes.For(...) en el <html> (emite los data-cayaqui-* en el HTML SSR desde tus defaults de AddCayaquiComponents):
@* App.razor *@
@inject IOptions<ThemeOptions> ThemeOpts
<!DOCTYPE html>
<html lang="es" @attributes="CayaquiThemeAttributes.For(ThemeOpts.Value)">
<head>
 @* 2. Dark MODE (System/per-user) — dinámico, ANTES de cualquier stylesheet *@
 <script>
 (function(){
 try {
 var m = localStorage.getItem('cayaqui-color-mode') || 'system';
 var dark = m==='dark' || (m==='system' && matchMedia('(prefers-color-scheme: dark)').matches);
 if (dark) document.documentElement.setAttribute('data-cayaqui-mode','dark');
 } catch(_){}
 })();
 </script>

 @* Syncfusion dual-link (dark arranca disabled) + swap según el mode resuelto arriba *@
 <link id="sf-theme-light" rel="stylesheet" href="_content/Syncfusion.Blazor.Themes/tailwind3.css" />
 <link id="sf-theme-dark" rel="stylesheet" href="_content/Syncfusion.Blazor.Themes/tailwind3-dark.css" disabled />
 <script>
 (function(){
 if (document.documentElement.getAttribute('data-cayaqui-mode')==='dark') {
 document.getElementById('sf-theme-light').disabled = true;
 document.getElementById('sf-theme-dark').disabled = false;
 }
 })();
 </script>

 <link rel="stylesheet" href="_content/Cayaqui.Components/css/cayaqui-bundle.css" />
 <HeadOutlet />
</head>
// Program.cs
builder.Services.AddCayaquiComponents(opts => opts.DefaultAccent = ThemeAccent.Cobalt);

Resultado: el HTML SSR-rendered ya tiene <html data-cayaqui-accent="cobalt"> antes del primer paint → cero flicker. El ThemeService.SetAsync runtime sigue funcionando para overrides per-user (CSS specificity garantiza que el setProperty inline gane sobre el attribute selector).

¿Por qué dos piezas? El accent/density son estáticos (vienen de ThemeOptions → SSR vía @attributes). El dark mode System es per-user (depende de localStorage + OS del cliente), no se puede resolver en el servidor → va por el script inline. Guía completa: docs/themes/theme-setup-consumer.md.

5 accents soportados con paleta completa (50→800 stops): Cobalt, Indigo, Emerald (default), Amber, Slate. 3 densities (Compact, Comfort, Spacious) y 2 directions (A warm/sobria, B cool/expresiva) también soportan SSR via data-cayaqui-density y data-cayaqui-direction.

Sin breaking changes — los consumers que no adoptan el patrón siguen funcionando con Emerald como default.


v0.27.0 — Tier 1 native migration (sin breaking changes)

4 componentes core que internamente wrappeaban Syncfusion ahora son HTML nativo:

  • CayaquiButton<button> con CSS existente (cayaqui-btn primary/secondary/tertiary/link/destructive).
  • CayaquiIconButton<button class="cayaqui-btn icon-only">.
  • CayaquiRadio<input type="radio"> con role="radiogroup" y keyboard handling del browser.
  • CayaquiTabs<div role="tablist"> con <button role="tab"> y keyboard nav WAI-ARIA (← → / ↑ ↓ / Home / End).

API pública conservada — drop-in upgrade. Las clases CSS internas cambiaron: Ghost ahora emite class="cayaqui-btn tertiary" y Danger emite destructive. Si tu CSS custom tenía selectores .cayaqui-btn.ghost/.danger, hay que adaptarlos.

Por qué la migración: independencia de runtime de Syncfusion para los componentes más usados, control completo del CSS, menor superficie de licencia para estos cuatro. Tier 2 (CayaquiDialog<dialog>, CayaquiDrawer, CayaquiToastHost) en una release futura.


v0.26.0 — UX hardening (5 fixes/features desde feedback)

🐛 Bug fix — CayaquiRangeSlider tooltip: Syncfusion 33.x no interpola C# format strings en SliderTooltip.Format — el tooltip mostraba "USD {600000:N0} - USD {30000000:N0}" literal. Fix: usar OnTooltipChange callback que construye el texto en C#.

💰 Smart compact money — CayaquiMoneyScope + nueva regla Cayaqui:

@* Antes: cada MoneyDisplay decidía su escala individualmente *@
<MoneyDisplay Value="450_000m" Compact="true" /> @* "USD 450K" *@
<MoneyDisplay Value="3_500_000m" Compact="true" /> @* "USD 3.5M" — distinto criterio *@

@* v0.26.0: scope unifica escala basado en max value *@
<CayaquiMoneyScope Values="@(new [] { 450_000m, 3_500_000m })">
 <MoneyDisplay Value="450_000m" Compact="true" /> @* "MUSD 0,5" *@
 <MoneyDisplay Value="3_500_000m" Compact="true" /> @* "MUSD 3,5" *@
</CayaquiMoneyScope>

Regla Cayaqui nueva: kUSD con 0 decimales (kUSD 450); MUSD con 1 decimal (MUSD 4.500,1 en es-CL). Una página entera usa la escala del monto mayor — coherencia visual.

Breaking en MoneyDisplay compact: el output cambió de "USD 10.5M" (suffix) a "MUSD 10,5" (prefix). Añadidos params Scale: MoneyScale?, Culture: CultureInfo?, y CompactDecimals ahora es int? con default por-escala (override solo si querés saltarte la regla).

🌐 CayaquiCounter cultura: ahora hereda CultureInfo.CurrentCulture (era InvariantCulture). Con DefaultThreadCurrentCulture = es-CL en Cayaqui.Web, los números se formatean automáticamente con punto thousands y coma decimal.

💬 CayaquiButton + CayaquiIconButton — Tooltip param:

<CayaquiButton Tooltip="Guardar cambios pendientes">Guardar</CayaquiButton>
<CayaquiIconButton Icon="e-icons e-edit" Tooltip="Editar fila" />

Renderiza title (browser tooltip nativo) + aria-label (a11y) si AriaLabel no se especificó explícitamente.

🎨 CayaquiCard — header bg + line toggle:

@* Header con tint del Variant + sin línea inferior *@
<CayaquiCard Title="Resumen"
 Variant="CayaquiCardVariant.Success"
 HeaderTinted="true"
 HeaderBorder="false">
 ...
</CayaquiCard>

HeaderTinted (default false) aplica --cayaqui-card-tint al fondo del header. HeaderBorder (default true) controla la línea inferior. Combinados generan un header con look cohesionado al body.


v0.25.0 — CayaquiEnumSelectRequired + Metadata 0.4.0

CayaquiEnumSelect<TEnum> (introducido en v0.23) requiere Value: TEnum? (nullable struct) para soportar el placeholder "Seleccionar...". Esto NO compila con forms que tienen propiedades non-nullable:

@* NO COMPILA si _form.Status es 'Status' (non-nullable) *@
<CayaquiEnumSelect TEnum="Status" @bind-Value="_form.Status" />

CayaquiEnumSelectRequired<TEnum> es una sister component aditiva con Value: TEnum para el caso non-nullable:

@* OK con _form.Status: Status non-nullable *@
<CayaquiEnumSelectRequired TEnum="Status" @bind-Value="_form.Status" />

Cuándo usar cuál:

Escenario Componente
Form con [Required] + non-nullable enum prop <CayaquiEnumSelectRequired>
Filtro que permite "todas las opciones" (sin selección) <CayaquiEnumSelect> (nullable)

Bump transitivo: Cayaqui.Metadata 0.4.0+ — los enums con [Display(Name)] ahora se renderizan con la etiqueta localizada en CayaquiAutoGrid, CayaquiAutoBadge, CayaquiAutoForm y los renderers de Cayaqui.Reports.

v0.24.0 — AutoGrid Rich Renderers

CayaquiAutoGrid ahora rinde automáticamente celdas con componentes ricos del design system según attributes/types del DTO:

  • <StatusChip> automático cuando una propiedad del DTO es de tipo WorkflowStatus (Cayaqui.Metadata.Models, auto-detect, sin atributo).
  • <UserChip> automático cuando se decora con [UserColumn(AvatarSource, RoleSource)] (atributo nuevo en Cayaqui.Metadata 0.3.0). Apunta a propiedades hermanas del DTO.
  • Refactor de Status/AutoBadge cells: ahora rinden con <CayaquiBadge> componente real (con CayaquiBadgeVariant enum tipado v0.20+) en lugar de <span class="cayaqui-badge"> inline.
public class ChangeOrderDto
{
 public string Code { get; set; } = "";
 public WorkflowStatus Status { get; set; } // → automático <StatusChip> (using Cayaqui.Metadata.Models)

 [UserColumn(AvatarSource = nameof(OwnerAvatar), RoleSource = nameof(OwnerRole))]
 public string OwnerName { get; set; } = ""; // → automático <UserChip>
 public string? OwnerAvatar { get; set; }
 public string? OwnerRole { get; set; }
}

Sin breaking changes. Bumpea dependencia de Cayaqui.Metadata a 0.3.0. Migración en scripts/migrate-to-components-0.24.0.md.

v0.23.1 — Fix CayaquiNumeric culture (es-CL)

CayaquiNumeric ahora formatea + parsea con culture es-CL (. thousands, , decimal) en lugar de Invariant. Default Format=N2 con 1234.5m rinde "1.234,50". Sin breaking change.

v0.23.0 — Forms HTML-native + CayaquiEnumSelect

Los 6 componentes de formulario simples (CayaquiTextBox, CayaquiNumeric, CayaquiSelect, CayaquiInputMask, CayaquiCheckBox, CayaquiToggle) migran de wrappers Syncfusion a HTML-native:

  • Cero JS interop → SSR más confiable y primer paint más rápido
  • Tests sin [Collection("Syncfusion")] — no necesitan serialización
  • Bundle reducido: drop de Syncfusion.Blazor.DropDowns

Nuevo: CayaquiEnumSelect<TEnum> con auto-projection desde Enum.GetValues y labels desde [Display(Name="…")]:

public enum Status { [Display(Name="Aprobado")] Approved, ... }

<CayaquiFormField Label="Estado">
 <CayaquiEnumSelect TEnum="Status" @bind-Value="_status" />
</CayaquiFormField>

Breaking changes (2, mecánicos): CayaquiTextBox.InputType enum cambia (era SF, ahora propio); CayaquiSelect TextField/ValueFieldTextSelector/ValueSelector. Ver scripts/migrate-to-components-0.23.0.md.


Suite EPC completo + design system con 70 componentes activos del roadmap publicado (v0.20.0 — 5 nuevos: Accordion, Timeline, FileUploader, InputMask, AvatarGroup + improvements Button.Loading/Badge enum/Alert enum/Avatar.Status; v0.19.0 — Cards suite: variants/accents/behaviors + 4 nuevos cards especializados + token --color-info-*; v0.18.4 — fix CayaquiSelect popup + docs sidebar accent override; v0.18.3 — CayaquiPageHeader breadcrumbs auto-generados + acento izquierdo del tema en el card + tipografía refinada; v0.18.2 — fix 19 constantes CayaquiIcons con nombres CSS inválidos en Syncfusion; v0.18.1 — fix CayaquiDialog compatible con Syncfusion 33.2.3; v0.18.0 — CayaquiIcons ~150 constantes, IRouteLabelsProvider para breadcrumbs automáticos con label+icono, CayaquiPageHeader.Card mode; v0.17.0 — RiskHeatmap v2 chips/tooltip/filtro; v0.16.0 — UserProfileCard + UserChip.PopoverContent). Agrupados por sección:

  • Design system (Buttons · Forms · Data Display · Navigation · Overlays · Feedback · StatusChip)
  • Auto-metadata (v0.2.0) — CayaquiAutoGrid<T>, CayaquiAutoForm<TModel>, CayaquiAutoFormField<T>, CayaquiAutoBadge que leen attrs del DTO desde Cayaqui.Metadata
  • EVM / EPC (KPI strip · gauges CPI/SPI/PF · curvas S · Gantt · WBS tree grid · R9C · Risk heatmap · Change orders · Purchase orders · Engineering deliverables · LookaheadGrid Last Planner)
  • Project controls completos — P3 Schedule (MilestoneStrip, ResourceHistogram, CriticalPathSummary, ScheduleVarianceTable, BurndownChart) · P4 Risk (RiskRegisterTable, TornadoChart, MonteCarloHistogram, RiskBoard, RiskTrendLine) · P5 Scope/Change Control (ApprovalWorkflow, CayaquiStepper, ConfirmDialog, AttachmentList, RaciMatrix) · P6 Forms de dominio (WbsPicker, PeriodNavigator, DateRangePicker, CurrencyInput, CodedTextbox, SearchCombo) · P7 Data display genérico (BarChart, DonutChart, StackedBarChart, UserChip, UserProfileCard, Banner, EmptyStateIllustrated) · P8 Mining-specific (CommodityPriceChart, StockpileLevel, ProductionCurve, ShiftSchedule)

Distribución propietaria — requiere contrato comercial con Cayaqui. Ver LICENSE.txt.

Instalación

dotnet add package Cayaqui.Components

Registro de servicios

// Program.cs
using Cayaqui.Components;

builder.Services.AddCayaquiComponents(); // ThemeService + ToastService (scoped)
// Override de defaults:
builder.Services.AddCayaquiComponents(opts =>
{
 opts.DefaultAccent = ThemeAccent.Emerald;
 opts.DefaultDensity = ThemeDensity.Comfort;
 opts.DefaultRadiusScale = 10m / 6m; // "10 · Redondeado"
});

La persistencia por usuario del tema (guardar accent/density/radius en BD) no forma parte de este paquete — se implementa con IThemePersistence (interfaz expuesta aquí) y un módulo de administración propio del consumidor.

Imports globales

En _Imports.razor:

@using Cayaqui.Components.Design ← CayaquiIcons y otros tipos raíz
@using Cayaqui.Components.Design.Buttons
@using Cayaqui.Components.Design.Forms
@using Cayaqui.Components.Design.DataDisplay
@using Cayaqui.Components.Design.Navigation
@using Cayaqui.Components.Design.Overlays
@using Cayaqui.Components.Design.Feedback
@using Cayaqui.Components.Evm
@using Cayaqui.Components.Theming

Iconos — CayaquiIcons

CayaquiIcons es una clase estática de constantes (Cayaqui.Components.Design) que centraliza las clases CSS Syncfusion (e-icons e-*) usadas en toda la suite. Evita strings hardcodeados dispersos y hace los usos refactorizables.

// Namespace — ya incluido si seguís los imports recomendados:
@using Cayaqui.Components.Design

Uso básico

<CayaquiButton IconLeft="@CayaquiIcons.Add">Nuevo CA</CayaquiButton>
<CayaquiButton IconLeft="@CayaquiIcons.ExportExcel" Variant="CayaquiButton.ButtonVariant.Ghost">Exportar</CayaquiButton>
<CayaquiIconButton Icon="@CayaquiIcons.Edit" AriaLabel="Editar" Size="CayaquiButton.ButtonSize.Sm" />
<CayaquiIconButton Icon="@CayaquiIcons.Delete" AriaLabel="Eliminar" Size="CayaquiButton.ButtonSize.Sm" />

En items de navegación

new NavItem("Dashboard", "/", CayaquiIcons.Home, IsActive: true)
new NavItem("Control Accounts", "/ca", CayaquiIcons.GridView)
new NavItem("WBS", "/wbs", CayaquiIcons.Folder, Badge: "16")
new NavItem("Cronograma", "/schedule", CayaquiIcons.Schedule)
new NavItem("Riesgos", "/risk", CayaquiIcons.Warning)

Grupos disponibles (~150 constantes)

Grupo Ejemplos
Actions Add, Edit, Delete, Save, Download, Upload, Filter, Search, Undo, Redo, …
Export ExportExcel, ExportCsv, ExportPdf, ExportWord, ExportPng, …
Navigation Home, Folder, FolderOpen, Menu, Expand, Collapse, Pin, OpenLink, …
Arrows & Chevrons ArrowDown/Left/Up/Right, ChevronDown/Up/Left/Right + fills
Files & Attachments File, FilePdf, FileDocument, Attachment, Image, Link, …
People & Identity User, People, Password, Location
Status / Feedback Check, CircleCheck, CircleInfo, Warning, Clock, History, Star, …
Data & Tables Table, GrandTotal, SubTotal, Calculation, Level1Level5, …
Charts Chart, ChartLine, ChartDonut, ChartScatter, ChartColumn, …
EVM / Project Controls Kpi, CriticalPath, GanttGripper, TimelineDay/Week/Month, …

La galería completa con búsqueda y preview está en /catalogo/icons del proyecto Cayaqui.Web de referencia.

Estáticos

Los CSS/JS se sirven automáticamente bajo _content/Cayaqui.Components/. Snippet recomendado en App.razor — un único bundle más el theme de Syncfusion (que viaja como dependencia transitiva):


<link rel="stylesheet" href="_content/Syncfusion.Blazor.Themes/tailwind3.css" />


<link rel="stylesheet" href="_content/Cayaqui.Components/css/cayaqui-bundle.css" />

<script src="_content/Cayaqui.Components/js/cayaqui-theme.js"></script>

El theme Syncfusion debe ir antes que cayaqui-bundle.css para que cayaqui-syncfusion-overrides.css (incluido en el bundle) tenga la última palabra.

Cargar CSS individuales (opcional)

Si prefieres tree-shake manual o cargar sólo un subset, sustituye cayaqui-bundle.css por los archivos puntuales en este orden:

<link rel="stylesheet" href="_content/Cayaqui.Components/css/cayaqui-tokens.css" />
<link rel="stylesheet" href="_content/Cayaqui.Components/css/cayaqui-syncfusion-overrides.css" />
<link rel="stylesheet" href="_content/Cayaqui.Components/css/cayaqui-components.css" />
<link rel="stylesheet" href="_content/Cayaqui.Components/css/cayaqui-indicators.css" />
<link rel="stylesheet" href="_content/Cayaqui.Components/css/cayaqui-evm-extras.css" />
<link rel="stylesheet" href="_content/Cayaqui.Components/css/cayaqui-wbs-treegrid.css" />
<link rel="stylesheet" href="_content/Cayaqui.Components/css/cayaqui-gantt.css" />

Requisitos

  • .NET 10.0 o superior
  • Syncfusion.Blazor 33.2.3+ — el consumidor debe registrar su propia licencia Syncfusion:
Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense("YOUR_LICENSE_KEY");

Defaults del tema

Propiedad Default
Accent Emerald
Density Comfort
RadiusScale 10 / 6 (opción "10 · Redondeado")

Configurable vía ThemeOptions al registrar AddCayaquiComponents(opts => { ... }).

Auto-metadata (v0.2.0)

Con un DTO decorado usando atributos de Cayaqui.Metadata, los componentes CayaquiAutoGrid<T> y CayaquiAutoForm<TModel> generan columnas y campos automáticamente sin ceremonia manual.

public sealed class ControlAccountRow
{
 [Label("Código"), Wbs] public string Code { get; set; } = "";
 [Label("Nombre"), Display(Order = 1)] public string Name { get; set; } = "";
 [Currency("USD")] public decimal Bac { get; set; }
 [Percentage(0)] public decimal PctComplete { get; set; }
 [EvmIndicator(EvmKind.Cpi), EvmBand] public decimal Cpi { get; set; }
 [Badge] public CaPhase Phase { get; set; }
 [Hidden] public Guid Id { get; set; }
}
public enum CaPhase
{
 [BadgeColor(BadgeKind.Brand)] Engineering,
 [BadgeColor(BadgeKind.Purple)] Procurement,
 [BadgeColor(BadgeKind.Warning)] Construction
}
<CayaquiAutoGrid TItem="ControlAccountRow" DataSource="@rows" Title="Control Accounts" />
<CayaquiAutoForm TModel="ControlAccountRow" Model="@row" OnValidSubmit="SaveAsync" />

La dependencia Cayaqui.Metadata se auto-instala como transitive y AddCayaquiComponents() también llama internamente a AddCayaquiMetadata().

Layout shell (v0.4.0) — CayaquiSidebar + CayaquiAppHeader

Ambos componentes siguen Untitled UI Pro v8. Patrón canónico para una app:

@* MainLayout.razor *@
@inherits LayoutComponentBase
@inject ThemeService Theme

<div class="app-shell">
 <CayaquiSidebar @ref="_sidebar"
 Tone="CayaquiSidebar.SidebarTone.Branded"
 BrandLogo="@(new CayaquiSidebar.SidebarLogo(
 Src: \"/img/brand-app.svg\", @* 200×40 lockup horizontal *@
 SlimSrc: \"/img/brand-app-slim.svg\", @* 36×36 icon/iso *@
 Alt: \"Mi App\"))"
 CompanyLogo="@(new CayaquiSidebar.SidebarLogo(
 Src: \"/img/owner-logo.svg\", @* 160×28 lockup horizontal *@
 SlimSrc: \"/img/owner-logo-slim.svg\", @* 28×28 icon/iso *@
 Alt: \"Owner Inc\"))"
 Collapsible="true"
 CollapseStorageKey="myapp.sidebar.collapsed">
 <ChildContent>
 <CayaquiSidebarSection>
 <CayaquiSidebarItem Text="Inicio" Href="/" Match="CayaquiSidebar.ItemMatch.Exact">
 <Icon><svg width="18" height="18" ...></svg></Icon>
 </CayaquiSidebarItem>
 </CayaquiSidebarSection>

 <CayaquiSidebarSection Label="Control">
 <CayaquiSidebarItem Text="Proyectos" Href="/projects" Badge="12">
 <Icon><svg ...></svg></Icon>
 </CayaquiSidebarItem>
 </CayaquiSidebarSection>
 </ChildContent>

 <Footer>
 <CayaquiSidebarUser Name="Ana Pérez" Subtitle="ana@cayaqui.com" />
 </Footer>
 </CayaquiSidebar>

 <div class="app-content">
 <CayaquiAppHeader Sidebar="_sidebar"
 ShowHamburger="true"
 ShowSearch="true"
 SearchPlaceholder="Buscar…"
 OnSearch="@HandleSearch"
 UserName="Ana Pérez"
 UserSubtitle="ana@cayaqui.com">
 <UserMenu>
 <a href="/perfil">Mi perfil</a>
 <a href="/config">Configuración</a>
 <button @onclick="SignOut">Cerrar sesión</button>
 </UserMenu>
 </CayaquiAppHeader>

 <main class="app-main">
 @Body
 </main>
 </div>
</div>

@code {
 private CayaquiSidebar? _sidebar;

 protected override async Task OnAfterRenderAsync(bool firstRender)
 {
 if (firstRender) await Theme.InitializeAsync();
 }

 private void HandleSearch(string q) { /* navegar / filtrar */ }
 private async Task SignOut() { /* ... */ }
}

CSS mínimo del shell (en app.css del consumer — el bundle no incluye estos selectores porque varían según el layout):

.app-shell { display: flex; min-height: 100vh; background: var(--color-bg); }
.app-content { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.app-main { flex: 1; min-width: 0; padding: 32px; }

CayaquiSidebar — opciones

Parámetro Default Notas
Variant Application (280px) Slim (72px solo iconos)
Tone Neutral Tinted (lavado accent-50) o Branded (accent-700 con texto claro)
BrandLogo (v0.15.0) null SidebarLogo(Src, SlimSrc?, Alt?). Logo del producto en el header. App: 200×40 px. Slim: 36×36 px.
CompanyLogo (v0.15.0) null SidebarLogo(Src, SlimSrc?, Alt?). Logo del owner en franja inferior. App: 160×28 px. Slim: 28×28 px.
Sticky true Sticky al top del viewport (position: sticky; top: 0; height: 100vh). Setear false si la sidebar va embebida en un layout que no quiere ese comportamiento.
Collapsible false Toggle Application↔Slim en el header.
CollapseStorageKey null Si seteás un key, el estado collapsed persiste por usuario en localStorage.
AutoActive true Infiere item activo desde NavigationManager.Uri.
ChildContent null Modo declarativo (<CayaquiSidebarSection> + <CayaquiSidebarItem>).
Sections [] Modo data-driven legacy con NavSection/NavItem records.

Sticky requiere viewport scroll. Si tu shell tiene un ancestor con overflow: auto o overflow: hidden propio, position: sticky se ancla a ese ancestor — usualmente no es lo que querés. Mantené el shell sin overflow propio (el body scrollea) y el sticky funciona como espera el patrón Untitled UI v8.

Sidebar logos (v0.15.0)

CayaquiSidebar soporta de forma tipada dos logos parametrizables: del producto (header) y de la compañía/owner (franja inferior, opcional). Cada logo se declara con dos variantes — lockup horizontal para Application mode y icon/iso square para Slim/Collapsed.

<CayaquiSidebar Tone="CayaquiSidebar.SidebarTone.Branded"
 BrandLogo="@(new CayaquiSidebar.SidebarLogo(
 Src: "/img/brand-myapp.svg",
 SlimSrc: "/img/brand-myapp-slim.svg",
 Alt: "MyApp Suite"))"
 CompanyLogo="@(new CayaquiSidebar.SidebarLogo(
 Src: "/img/owner-logo.svg",
 SlimSrc: "/img/owner-logo-slim.svg",
 Alt: "Owner Inc"))"
 Collapsible="true"
 CollapseStorageKey="myapp.sidebar.collapsed">
 @* ChildContent / Footer slots ... *@
</CayaquiSidebar>
Tipo público
public sealed record SidebarLogo(string Src, string? SlimSrc = null, string? Alt = null);
  • Src — URL del lockup horizontal (Application mode).
  • SlimSrc — URL del icon/iso 1:1 (Slim mode o Collapsed=true). Opcional pero recomendado. Si es null, se reusa Src y puede verse apretado/deformado.
  • Alt — texto alt para accesibilidad.
Dimensiones recomendadas de los assets
Slot Application (sidebar 280px) Slim/Collapsed (sidebar 72px)
Brand (producto) 200×40 px 36×36 px
Company (owner) 160×28 px 28×28 px
  • SVG preferido (escalable, sin pérdida en retina). PNG aceptable a @2x (400×80, 72×72, 320×56, 56×56). Evitar JPG (sin alpha).
  • Las imágenes deben llegar trim (sin padding baked-in). El padding interno lo provee el slot CSS (.sb-header, .sb-company).
  • CompanyLogo se renderiza con opacity: 0.75 (Neutral/Tinted) ó 0.85 (Branded) — visualmente subordinado al brand del producto.
Tone="Branded" + logos

En modo Branded (sidebar pintado con accent-700), los logos a color sobre el fondo oscuro pueden no leer bien. Dos opciones:

  1. Recomendado: proveer un Src apuntando a la versión blanca/monocroma del logo (ej. logo-white.svg).
  2. Si tu logo es monocromo con alpha (typical SVG con fill="#000" o sin fill explícito), agregar la utility class invert-on-branded al <img> del logo invierte automáticamente a blanco vía filter: brightness(0) invert(1). La utility está disponible globalmente — no requiere parámetro adicional.
Layout en runtime
Application (280px) Slim (72px)
┌──────────────────────────┐ ┌──────┐
│ [logo MyApp lockup] ⇄ │ │ [Mi] │ ← BrandLogo.SlimSrc
├──────────────────────────┤ ├──────┤
│ ▸ Dashboard │ │ ▦ │
│ ▸ Proyectos 12 │ │ □ │
│ ▸ Riesgos │ │ ⚠ │
├──────────────────────────┤ ├──────┤
│ [Footer slot — user] │ │ [Av] │ ← Footer slot (opcional, CayaquiSidebarUser)
├──────────────────────────┤ ├──────┤
│ [logo Owner Inc] │ │ [Ow] │ ← CompanyLogo.SlimSrc
└──────────────────────────┘ └──────┘

Coexistencia con Footer slot: si declarás Footer (típicamente CayaquiSidebarUser) y CompanyLogo, ambos se apilan (Footer arriba, CompanyLogo abajo). El divisor entre ambos se suprime automáticamente para evitar doble línea (regla CSS > .sb-footer + .sb-company).

Precedencia en el header: si pasás un Header RenderFragment custom, ignora BrandLogo y BrandMark. Si pasás BrandLogo, ignora BrandMark. La intención es que cada nivel de override sea opt-in claro.

CayaquiAppHeader — opciones

Parámetro Default Notas
Sticky true Sticky al top del area de contenido.
ShowHamburger false Muestra el botón menú a la izquierda. Si querés que aparezca solo en mobile, condicionalo en el consumer (no se fuerza por CSS).
Sidebar null Ref al CayaquiSidebar. Si está seteado, el hamburger toggle-a Collapsed automáticamente.
OnHamburgerClick Override manual; toma precedencia sobre Sidebar.
ShowSearch false Renderiza un <input type="search"> con icono. OnSearch se dispara al apretar Enter.
UserName / UserSubtitle / UserImage Si UserName no es null, renderiza el dropdown de usuario.
UserMenu Slot con los items del dropdown (links, botones). Click cierra el menú.
Left / Center / Right Slots libres. Center se oculta en <768px.

Recomendaciones de uso

  • Usá una sola instancia de CayaquiAppHeader y CayaquiSidebar por shell. Para shells anidados (admin / contractor portal) duplicá el shell completo.
  • Tono de la sidebar: Branded para shell global (la marca visible). Si tenés un sub-shell (ej. configuración), usar Tinted o Neutral para diferenciar jerarquía.
  • Sidebar collapsed default: si tu app tiene una densidad alta de items, considerá iniciar con Collapsed=true y dejar al usuario expandir.
  • Iconos: SVG inline 18×18 con stroke="currentColor" heredan el color del item según estado (hover/active/branded). Evitá íconos rasterizados.
  • Auth-aware: el componente no decide qué items mostrar; envolvé <CayaquiSidebarItem> con <AuthorizeView Roles="..."> cuando necesites filtrar por rol.

Accesibilidad de formularios (v0.4.2+)

CayaquiFormField ahora cascadea un CayaquiFieldContext a sus inputs hijos. Los inputs (CayaquiTextBox, CayaquiNumeric, CayaquiSelect, CayaquiDatePicker, CayaquiCheckBox) leen el cascade y propagan id, aria-describedby (apunta a hint o error) y aria-invalid automáticamente al input subyacente — sin código extra del consumer.

<CayaquiFormField Label="Email" Hint="Correo de trabajo" Error="@_emailError" Required="true">
 <CayaquiTextBox @bind-Value="_email" />
</CayaquiFormField>

Resultado renderizado (simplificado):

<div class="cayaqui-field has-error">
 <label class="cayaqui-label" for="cayaqui-fld-abc123">Email <span aria-hidden="true">*</span></label>
 <div class="cayaqui-field-control">
 <input id="cayaqui-fld-abc123" aria-describedby="cayaqui-fld-abc123-error" aria-invalid="true" ... />
 </div>
 <div class="cayaqui-field-error" id="cayaqui-fld-abc123-error" role="alert" aria-live="polite">
 @_emailError
 </div>
</div>

El error se anuncia automáticamente a screen readers vía role="alert" + aria-live="polite".

AriaLabel para controles sin label visible

Cuando un input vive fuera de un CayaquiFormField (ej. checkbox dentro de tabla, button icon-only, dialog con HeaderTemplate sin texto), pasá AriaLabel explícito:

<CayaquiCheckBox @bind-Checked="@row.Selected" AriaLabel="Seleccionar fila" />
<CayaquiButton AriaLabel="Cerrar" IconLeft="e-icons e-close" />
<CayaquiDialog @bind-Visible="_open" AriaLabel="Detalle del proyecto">
 <ChildContent>...</ChildContent>
</CayaquiDialog>

CayaquiDialog deriva aria-label desde Title automáticamente si no pasás AriaLabel.

0.4.1 retirado: tenía un bug donde el id auto-generado de CayaquiFormField se regeneraba en cada rerender del padre, rompiendo la conexión label[for]/aria-describedby. Si estás en 0.4.1, subí a 0.4.2 (fix incluido).

Inicialización del tema (recomendado)

Para que el accent del tema (default Emerald) se aplique desde el primer frame, el consumer debe inicializar ThemeService una vez en su layout principal:

@inject ThemeService Theme

@code {
 protected override async Task OnAfterRenderAsync(bool firstRender)
 {
 if (firstRender) await Theme.InitializeAsync();
 }
}

Sin esto, los tokens accent quedan en su fallback estático (Direction A = emerald) hasta que el usuario cambie el tema desde la UI.

Dark / Light / System Mode (v0.46.0)

Add two inline scripts and the Syncfusion dual-link to your App.razor <head>, in this exact order:


<script>
(function(){
 try {
 var m = localStorage.getItem('cayaqui-color-mode') || 'system';
 var dark = m==='dark' || (m==='system' && matchMedia('(prefers-color-scheme: dark)').matches);
 if (dark) document.documentElement.setAttribute('data-cayaqui-mode','dark');
 } catch(_){}
})();
</script>


<link id="sf-theme-light" rel="stylesheet"
 href="_content/Syncfusion.Blazor.Themes/tailwind3.css" />
<link id="sf-theme-dark" rel="stylesheet"
 href="_content/Syncfusion.Blazor.Themes/tailwind3-dark.css"
 disabled />


<script>
(function(){
 if (document.documentElement.getAttribute('data-cayaqui-mode')==='dark') {
 var l = document.getElementById('sf-theme-light');
 var d = document.getElementById('sf-theme-dark');
 if (l) l.disabled = true;
 if (d) d.disabled = false;
 }
})();
</script>


<link rel="stylesheet" href="_content/Cayaqui.Components/css/cayaqui-bundle.css" />

Then place <CayaquiColorModeToggle /> anywhere in your layout:

@using Cayaqui.Components.Design.Navigation
<CayaquiColorModeToggle />

Or switch programmatically:

@inject ThemeService Theme

<button @onclick="() => Theme.SetAsync(mode: ThemeMode.Dark)">Dark</button>

Configure the default in Program.cs:

builder.Services.AddCayaquiComponents(o =>
{
 o.DefaultMode = ThemeMode.System; // Light, Dark, or System (default)
});

Known limitation: In dark mode on first load a brief (~50–150 ms) Syncfusion theme flash may occur because tailwind3.css starts downloading before Script 1 can swap to tailwind3-dark.css. This is the tradeoff of localStorage-based detection.

Cambio dinámico de acento

ThemeService permite cambiar el accent (y density / direction / radiusScale / fontFamily) en tiempo real desde cualquier página. La aplicación re-pinta instantáneamente — sidebar branded, KPI gauges, botones primary, focus rings, etc. — porque internamente el servicio reescribe las CSS custom properties (--color-accent-50--color-accent-700) en :root vía JS interop.

Acentos disponibles

public enum ThemeAccent { Cobalt, Indigo, Emerald, Amber, Slate }

5 paletas built-in. Cada acento expone una rampa completa de 9 stops (50/100/200/300/400/500/600/700/800/900) ya validada para contraste WCAG AA en texto y backgrounds. Emerald es el default si no override-as DefaultAccent.

Cambiar el acento desde una página

Patrón recomendado: CayaquiSegmented con un option por accent + binding al ThemeService.Accent.

@page "/configuracion"
@inject ThemeService Theme
@implements IDisposable

<CayaquiCard Title="Apariencia">
 <CayaquiFormField Label="Color del tema">
 <CayaquiSegmented TValue="ThemeAccent"
 Value="@Theme.Accent"
 ValueChanged="@(async v => await Theme.SetAsync(accent: v))"
 Options="@_accentOpts" />
 </CayaquiFormField>

 <CayaquiFormField Label="Densidad">
 <CayaquiSegmented TValue="ThemeDensity"
 Value="@Theme.Density"
 ValueChanged="@(async v => await Theme.SetAsync(density: v))"
 Options="@_densityOpts" />
 </CayaquiFormField>
</CayaquiCard>

@code {
 CayaquiSegmented<ThemeAccent>.Option[] _accentOpts = new[]
 {
 new CayaquiSegmented<ThemeAccent>.Option(ThemeAccent.Cobalt, "Cobalt"),
 new CayaquiSegmented<ThemeAccent>.Option(ThemeAccent.Indigo, "Indigo"),
 new CayaquiSegmented<ThemeAccent>.Option(ThemeAccent.Emerald, "Emerald"),
 new CayaquiSegmented<ThemeAccent>.Option(ThemeAccent.Amber, "Amber"),
 new CayaquiSegmented<ThemeAccent>.Option(ThemeAccent.Slate, "Slate"),
 };

 CayaquiSegmented<ThemeDensity>.Option[] _densityOpts = new[]
 {
 new CayaquiSegmented<ThemeDensity>.Option(ThemeDensity.Compact, "Compact"),
 new CayaquiSegmented<ThemeDensity>.Option(ThemeDensity.Comfort, "Comfort"),
 new CayaquiSegmented<ThemeDensity>.Option(ThemeDensity.Spacious, "Spacious"),
 };

 protected override void OnInitialized() => Theme.Changed += StateHasChanged;
 public void Dispose() => Theme.Changed -= StateHasChanged;
}

Theme.Changed es un event Action? que se dispara después de aplicar el cambio. Suscribirse + StateHasChanged permite que la página refleje el Theme.Accent actualizado en bindings (Value= del segmented).

Cambio programático

// Cambiar solo accent:
await Theme.SetAsync(accent: ThemeAccent.Cobalt);

// Cambiar varios atributos en un solo apply:
await Theme.SetAsync(accent: ThemeAccent.Indigo, density: ThemeDensity.Compact);

// Volver al default del tenant:
await Theme.SetAsync(accent: ThemeAccent.Emerald, density: ThemeDensity.Comfort);

SetAsync es debounced de facto — múltiples await consecutivos son seguros, pero en UIs reactivas (sliders, color pickers continuos) sumá tu propio debounce client-side para evitar flicker.

Persistencia entre sesiones

Para que la elección del usuario sobreviva F5 y logout/login, registrá una implementación de IThemePersistence:

public interface IThemePersistence
{
 Task<ThemeState?> LoadAsync(CancellationToken ct);
 Task SaveAsync(ThemeState state, CancellationToken ct);
}
Opción A — ProtectedLocalStorage (Blazor Server, default)
public sealed class LocalStorageThemePersistence : IThemePersistence
{
 private readonly ProtectedLocalStorage _store;
 private const string Key = "cayaqui-color-mode";

 public LocalStorageThemePersistence(ProtectedLocalStorage store) => _store = store;

 public async Task<ThemeState?> LoadAsync(CancellationToken ct)
 {
 try
 {
 var r = await _store.GetAsync<ThemeState>(Key);
 return r.Success ? r.Value : null;
 }
 catch { return null; }
 }

 public async Task SaveAsync(ThemeState state, CancellationToken ct)
 => await _store.SetAsync(Key, state);
}

// Program.cs
services.AddScoped<IThemePersistence, LocalStorageThemePersistence>();
Opción B — DB por usuario (multi-device)

Si tu app necesita que el tema viaje entre dispositivos, persistí ThemeState en una columna JSON sobre la tabla de usuarios:

public sealed class DbThemePersistence : IThemePersistence
{
 private readonly ICurrentUser _user;
 private readonly AppDbContext _db;

 public async Task<ThemeState?> LoadAsync(CancellationToken ct)
 {
 var u = await _db.Users.FindAsync([_user.Id], ct);
 return u?.ThemeJson is not null
 ? JsonSerializer.Deserialize<ThemeState>(u.ThemeJson)
 : null;
 }

 public async Task SaveAsync(ThemeState state, CancellationToken ct)
 {
 var u = await _db.Users.FindAsync([_user.Id], ct);
 if (u is null) return;
 u.ThemeJson = JsonSerializer.Serialize(state);
 await _db.SaveChangesAsync(ct);
 }
}

ThemeState es un record público con todos los atributos del tema:

public sealed record ThemeState(
 ThemeDirection Direction,
 ThemeAccent Accent,
 ThemeDensity Density,
 decimal RadiusScale,
 string FontFamily,
 ThemeMode Mode);
Migration: IThemePersistence implementors

If you implement IThemePersistence directly and persist theme state to a database, ThemeState now has a 6th required parameter Mode (added in v0.46.0):

// Before (0.45.x):
new ThemeState(Direction, Accent, Density, RadiusScale, FontFamily)

// After (0.46.0):
new ThemeState(Direction, Accent, Density, RadiusScale, FontFamily, Mode)

// When loading from DB with no stored mode yet, use System as default:
Mode: Enum.TryParse<ThemeMode>(savedModeString, true, out var m) ? m : ThemeMode.System

If you store theme columns individually (not as JSON), add a nullable ThemeMode string column to your preferences table:

ALTER TABLE UserPreferences ADD ThemeMode nvarchar(16) NULL;

Reactividad en componentes custom del consumer

Para componentes custom que no usen CSS variables (ej. canvas/SVG con colores hardcodeados), suscribirse al evento Changed y recolorear:

@inject ThemeService Theme
@implements IDisposable

<canvas @ref="_canvas" width="400" height="200"></canvas>

@code {
 private ElementReference _canvas;

 protected override void OnInitialized() => Theme.Changed += OnThemeChanged;
 public void Dispose() => Theme.Changed -= OnThemeChanged;

 private async void OnThemeChanged()
 {
 // Theme.Accent cambió — recolorear el canvas custom.
 await JS.InvokeVoidAsync("myChart.recolor", _canvas, Theme.Accent.ToString());
 StateHasChanged();
 }
}

Tip: la mayoría de componentes Cayaqui y tu UI consumer nativa no requieren esto — heredan el accent automáticamente vía CSS variables. Solo te preocupa esto si tenés rendering custom fuera del flujo CSS (canvas/WebGL/charts third-party que reciben colores como argumento, no como CSS).

Acento exclusivo de un componente (override puntual)

ThemeService.SetAsync(accent: ...) reescribe los --color-accent-* en :root — el cambio afecta toda la app. Si necesitás que solo el sidebar (o cualquier componente puntual) use un acento distinto al global, sobrescribí las custom properties en un selector más específico — las variables CSS cascadean y solo afectan al sub-árbol donde se redefinen.

<CayaquiSidebar Class="sb-corporate" Sections="@_sections" />

<style>
 .cayaqui-sidebar.sb-corporate {
 --color-accent-50: #EEF2FF;
 --color-accent-100: #E0E7FF;
 --color-accent-700: #4338CA;
 }
</style>

Botones, KPIs, focus rings y resto de la UI conservan el acento global. Solo cambia el highlight del item activo del sidebar marcado con Class="sb-corporate".

Variables que consume CayaquiSidebar (por impacto visual):

Variable Dónde se usa
--color-accent-50 Fondo del item activo (Tone Neutral/Tinted)
--color-accent-100 Borde del item activo + tinte de fondo Tone="Tinted"
--color-accent-700 Texto + iconos del item activo
--color-accent-600 Fondo de la sidebar en Tone="Branded"

Si solo querés cambiar el highlight sin migrar toda la rampa, podés ir más directo:

.cayaqui-sidebar.sb-corporate .sb-item.active {
 background: #1F2937;
 color: #FFFFFF;
}

Default por tenant en Program.cs

Si tu app es multi-tenant y cada tenant tiene un default distinto:

services.AddCayaquiComponents(opts =>
{
 opts.DefaultAccent = currentTenant.BrandAccent; // ej. ThemeAccent.Cobalt
 opts.DefaultDensity = ThemeDensity.Comfort;
 opts.DefaultFontFamily = "'Inter', system-ui, sans-serif";
});

El usuario siempre puede sobrescribir vía Theme.SetAsync — el default solo aplica en la primera carga si no hay state persistido.

ThemeDirection — A vs B

public enum ThemeDirection { A, B }
Valor Efecto visual
A Sidebar neutral (fondo --color-bg), acentos sólo en items activos. Estética corporativa/sobria. Default.
B Sidebar usa el acento como color de fondo. Estética más expresiva/colorida.
// Cambiar a dirección B:
await Theme.SetAsync(direction: ThemeDirection.B);

CayaquiColorModeToggle — props

Parámetro Tipo Default Descripción
Size CayaquiSegmentedSize Md Tamaño del toggle: Sm · Md · Lg
Class string? null Clase CSS adicional
@using Cayaqui.Components.Design.Navigation
<CayaquiColorModeToggle /> @* Md (default) *@
<CayaquiColorModeToggle Size="CayaquiSegmentedSize.Sm" /> @* compacto para toolbar *@

CSS tokens semánticos — dark mode compatibility

Para que componentes custom del consumer reaccionen automáticamente al dark mode, usar exclusivamente estos tokens (no hardcodear colores):

Token Descripción Uso típico
--color-bg Fondo de app/página body, main, page wrapper
--color-bg-subtle Fondo alternativo Table rows alternadas, cards secundarias
--color-surface Superficies elevadas Cards, dropdowns, modals
--color-surface-alt Superficies más elevadas Popups sobre cards
--color-border Borde estándar Inputs, tablas, divisores
--color-border-strong Borde enfatizado Focus rings, separadores importantes
--color-text Texto primario Títulos, labels, body copy
--color-text-secondary Texto secundario Subtítulos, descripciones
--color-text-tertiary Texto apagado Placeholders, metadata
--color-accent-600 Acento principal activo Botones primary, links, highlights

Ejemplo de componente custom dark-compatible:

.mi-tarjeta {
 background: var(--color-surface);
 border: 1px solid var(--color-border);
 color: var(--color-text);
 border-radius: calc(var(--radius-base) * 1px);
}
.mi-tarjeta .descripcion {
 color: var(--color-text-secondary);
}
.mi-tarjeta .accion {
 color: var(--color-accent-600);
}

El selector dark activo es [data-cayaqui-mode="dark"] en <html> — los tokens se redefinen automáticamente bajo ese selector en cayaqui-tokens.css.

Catálogo de componentes por categoría

Lista resumida — para sintaxis + props + casos completos ver /docs/components en el repo.

Buttons (Cayaqui.Components.Design.Buttons)

Componente Versión Propósito
CayaquiButton 0.1.0 Botón base — wrapper de SfButton. Variants: Primary / Secondary / Ghost / Danger / Link. Sizes Sm / Md / Lg. Slots IconLeft / IconRight (clase CSS, ej. e-icons e-plus). AriaLabel para botones icon-only o texto no descriptivo. HtmlType="button" (default), "submit", "reset".
CayaquiIconButton 0.1.0 Botón cuadrado solo con icono. Required: Icon (clase CSS). Required best-practice: AriaLabel.
CayaquiButtonGroup 0.21.0 Toggle data-driven entre opciones (Items: IReadOnlyList<CayaquiButtonGroupItem> + @bind-Value). Reusa CayaquiButton.ButtonSize. Selected item recibe ButtonVariant.Primary.

v0.15.0 fix: tanto CayaquiButton como CayaquiIconButton enrutaban Type y aria-label como atributos sueltos al SfButton interno. En Syncfusion 33.2.3, SfButton declara HtmlAttributes con [Parameter(CaptureUnmatchedValues=true)] — cualquier atributo no reconocido choca con la asignación explícita y dispara InvalidOperationException al renderizar. Ahora ambos componentes consolidan los atributos HTML en el diccionario HtmlAttributes interno (incluyendo type y aria-label). Cero impacto en tu APIHtmlType y AriaLabel siguen siendo los mismos parámetros del consumer.

<CayaquiButton Variant="CayaquiButton.ButtonVariant.Primary"
 IconLeft="e-icons e-plus">Nuevo CA</CayaquiButton>

<CayaquiButton Variant="CayaquiButton.ButtonVariant.Ghost"
 IconLeft="e-icons e-export-excel">Exportar</CayaquiButton>

<CayaquiIconButton Icon="e-icons e-edit"
 AriaLabel="Editar fila"
 Size="CayaquiButton.ButtonSize.Sm" />

<CayaquiButton HtmlType="submit"
 Variant="CayaquiButton.ButtonVariant.Primary"
 Block="true">Guardar cambios</CayaquiButton>

Forms (Cayaqui.Components.Design.Forms)

Componente Versión Propósito
CayaquiFormField 0.1.0 Wrapper label + hint + error.
CayaquiTextBox 0.1.0 Input texto (single/multi/password).
CayaquiNumeric 0.1.0 Numérico con stepper, min/max, format.
CayaquiSelect<TValue, TItem> 0.1.0 DropDown genérico.
CayaquiDatePicker 0.1.0 Selector de fecha.
CayaquiCheckBox 0.1.0 Checkbox 2-state / tristate.
CayaquiRadio<TValue> 0.1.0 Grupo radio genérico.
CayaquiToggle 0.1.0 Switch on/off.
WbsPicker 0.12.0 Selector jerárquico CA/WP con búsqueda + chip.
PeriodNavigator 0.12.0 < Apr-2026 > Day/Week/Month/Quarter/Year.
DateRangePicker 0.12.0 Rango con 8 presets + Custom + ExtraPresets.
CurrencyInput 0.12.0 Numeric + currency selector, default 0 decimales.
CodedTextbox 0.12.0 Auto-formato WBS/CBS uppercase + grouping.
SearchCombo<TItem> 0.12.0 Autocomplete genérico con debounce + match highlight.
CayaquiFileUploader 0.20.0 Drag-drop dropzone; emite IBrowserFile[]; validación MIME + tamaño; OnRejected.
CayaquiInputMask 0.20.0 Wrapper SfMaskedTextBox con presets RutChile/RucPeru/PhoneIntl.
CayaquiRangeSlider 0.22.0 Slider dual-handle numérico (wrapper SfSlider<double[]> Range). API decimal. Format/Prefix/Suffix en tooltips.
CayaquiColorPicker 0.22.0 Color picker free-form (Picker) o restringido a paleta (Palette). Wrapper SfColorPicker.

Data Display (Cayaqui.Components.Design.DataDisplay)

CayaquiAvatar · CayaquiBadge · StatusChip · CayaquiCard · CayaquiStatCard · CayaquiMediaCard · CayaquiReviewCard · CayaquiActionCard · CayaquiEmpty · CayaquiProgress · CayaquiGrid<T> · CayaquiGridColumn · CayaquiGridActionColumn · CayaquiAutoGrid<T> · CayaquiAutoBadge + nuevos en 0.11.0/0.13.0/0.19.0/0.20.0: | Componente | Versión | Propósito | |---|---|---| | AttachmentList | 0.11.0 | Lista archivos + extension icons + preview/download/delete. | | BarChart | 0.13.0 | Wrapper SfChart Vertical/Horizontal con paleta Cayaqui. | | DonutChart | 0.13.0 | SfAccumulationChart con InnerRadius + center label. | | StackedBarChart | 0.13.0 | N series stacked, modo Percent (StackingColumn100). | | UserChip | 0.13.0 | Avatar + nombre + rol compacto inline, 3 tamaños. | | CayaquiStatCard | 0.19.0 | Card de métricas inline con trend indicator. | | CayaquiMediaCard | 0.19.0 | Card con imagen (top cap o side). | | CayaquiReviewCard | 0.19.0 | Rating estrellas + autor. | | CayaquiActionCard | 0.19.0 | Header con persona + dropdown de acciones. | | CayaquiTimeline | 0.20.0 | Eventos cronológicos con dots por CayaquiTimelineStatus; orientación Vertical/Horizontal. | | CayaquiAvatarGroup | 0.20.0 | Stack horizontal de N avatares con overlap -8px; excedente colapsa a chip +N. | | CayaquiKanban<TItem> | 0.21.0 | Kanban genérico con selector functions (IdSelector, ColumnSelector) y drag-drop HTML5 native. OnItemMoved reporta CayaquiKanbanMove<TItem>. | | CayaquiRating | 0.21.0 | Rating estrellas standalone. Interactive (@bind-Value + hover preview) o read-only. 3 sizes (Sm/Md/Lg). | | CayaquiCounter | 0.21.0 | Número animado con easing cubic-out. Format/Prefix/Suffix/Culture configurables. Duration=0 = set inmediato. | | CayaquiTreeView<TNode> | 0.22.0 | Tree view genérico con selector functions (IdSelector, ParentSelector, LabelSelector, IconSelector). Wrapper SfTreeView. Single-select + ExpandAll. | | CayaquiListGroup | 0.44.0 | Lista estilizada model-driven. Icono, subtítulo, badge, @bind-SelectedItemId, Disabled, Flush, ItemTemplate. | | CayaquiFileManager | 0.44.0 | Browser Grid/Lista de archivos. Auto-icono por extensión. @bind-ViewMode, OnOpen, OnDelete. |

Navigation (Cayaqui.Components.Design.Navigation)

CayaquiBreadcrumbs · CayaquiPageHeader · CayaquiSegmented<TValue> · CayaquiSidebar (+ CayaquiSidebarSection + CayaquiSidebarItem + CayaquiSidebarUser) · CayaquiTabs · CayaquiAppHeader + nuevo: | Componente | Versión | Propósito | |---|---|---| | CayaquiStepper | 0.11.0 | Wizard multi-paso con CanAdvance/CanFinish + AllowJumpBack. | | CayaquiPagination | 0.22.0 | Page nav hand-rolled con ellipsis + SortedSet dedup. ShowSummary, ShowSizeSelector opcionales. | | CayaquiColorModeToggle | 0.46.0 | Segmented Light/System/Dark toggle. Requiere ThemeService. | | CayaquiFullscreenToggle | 0.51.0 | Botón toggle fullscreen browser. Requiere cayaqui-fullscreen.js en App.razor. EnterLabel, ExitLabel, Class. |

CayaquiBreadcrumbs — resolución automática vía IRouteLabelsProvider

Registrar una única vez en DI y todos los breadcrumbs con AutoGenerate="true" resuelven label + icono automáticamente sin parámetros por página.

1 — Implementar en la app:

using Cayaqui.Components.Design.Navigation;

public sealed class AppRouteLabelsProvider : IRouteLabelsProvider
{
 private static readonly Dictionary<string, RouteInfo> Routes =
 new(StringComparer.OrdinalIgnoreCase)
 {
 ["/"] = new("Inicio", "e-icons e-home"),
 ["/proyectos"] = new("Proyectos", "e-icons e-gantt-chart"),
 ["/proyectos/overview"] = new("Vista General", "e-icons e-eye"),
 ["/control-accounts"] = new("Control Accounts", "e-icons e-hierarchy"),
 ["/riesgos"] = new("Riesgos", "e-icons e-warning"),
 ["/schedule"] = new("Cronograma", "e-icons e-schedule"),
 // Segmentos sueltos (fallback cuando el path completo no matchea)
 ["overview"] = new("Vista General", "e-icons e-eye"),
 };

 public RouteInfo? GetRoute(string pathOrSegment) =>
 Routes.TryGetValue(pathOrSegment, out var info) ? info : null;
}

2 — Registrar en Program.cs (una sola vez):

builder.Services.AddSingleton<IRouteLabelsProvider, AppRouteLabelsProvider>();

3 — Usar en cualquier página sin parámetros extra:

<CayaquiBreadcrumbs AutoGenerate="true" />

Prioridad de resolución por segmento: Items explícito → RouteLabels param → IRouteLabelsProvider DI → title-case del segmento.

RouteInfo(string Label, string? Icon)Icon acepta cualquier clase CSS de Syncfusion (ej. "e-icons e-home").
Si IRouteLabelsProvider no está registrado en DI, el componente lo ignora silenciosamente (sin excepción).

Overlays (Cayaqui.Components.Design.Overlays)

CayaquiDialog · CayaquiDrawer · CayaquiPopover · CayaquiTooltip · CayaquiDropdownMenu · CayaquiCommandMenu + nuevo: | Componente | Versión | Propósito | |---|---|---| | ConfirmDialog | 0.11.0 | Wrapper Default/Danger/Warning sobre CayaquiDialog + IsBusy. |

Feedback (Cayaqui.Components.Design.Feedback)

CayaquiAlert · CayaquiSkeleton · CayaquiToastHost (con ToastService) + nuevos en 0.13.0/0.20.0/0.51.0: | Componente | Versión | Propósito | |---|---|---| | CayaquiBanner | 0.13.0 | Sticky top con 5 variants — Env purple gradient para QA/STAGING/DEV. | | CayaquiEmptyStateIllustrated | 0.13.0 | 6 illustration kinds inline SVG + acción opcional. | | CayaquiAccordion | 0.20.0 | Contenedor colapsable template-based vía CascadingValue. Multiple permite varios abiertos. | | CayaquiAccordionItem | 0.20.0 | Sección hija de CayaquiAccordion. Disabled suprime click. Animación chevron + body via CSS. | | CayaquiSpinner | 0.38.0 | Spinner circular CSS puro. Size (Xs/Sm/Md/Lg), Color (Primary/Muted/White/Success/Warning/Danger). | | CayaquiReconnectModal | 0.51.0 | Diálogo reconexión Blazor Server. Requiere cayaqui-reconnect.js (type="module") después de blazor.web.js. Todos los textos son [Parameter]. |

Engineering · Workflow (Cayaqui.Components.Engineering.Workflow)

Componente Versión Propósito
CayaquiWorkflowEditor 0.51.0 Pipeline editor interactivo. Nodes (IReadOnlyList<NodeDef>), @bind-ActiveKeys, Presets opcionales, Disabled. Nodos fijos siempre activos; opcionales toggle por click. Nested types: NodeDef(Key, Label, Title, IsFixed, IsTerminal), Preset(Label, ActiveKeys).
CayaquiWorkflowMini 0.51.0 Vista compacta read-only del pipeline. Mismos Nodes (tipo CayaquiWorkflowEditor.NodeDef) + ActiveKeys. Badge con conteo de pasos activos.

Engineering · Documents (Cayaqui.Components.Engineering.Documents)

Componente Versión Propósito
CayaquiDocCard 0.41.0 Card de documento con estado, revisión y acciones.
CayaquiDocRevisionList 0.41.0 Lista revisiones de un documento.
CayaquiDocStatusBadge 0.41.0 Badge de estado de documento.
CayaquiEngProgressTable 0.42.0 Tabla Plan/Forecast/Actual/Var por documento con hitos configurables.

EVM / EPC (Cayaqui.Components.Evm) — 42 componentes

P1 EVM/AACE (8): EvmKpiStrip · KpiCard · CayaquiGauge · CayaquiBulletGauge · CpiGauge · SpiGauge · CpiIndicator · SpiIndicator · VarianceIndicator · ForecastIndicator · EvmSemaforo · TrendChip · DoubleProgress · TripleProgress · EvmCashflowCurve · PhysicalProgressCurve · TcpiIndicator · EarnedScheduleIndicator · HealthDot · VariancePill · TrendDelta · CayaquiSparkline · CsiIndicator · EvmControlChart

P2 Cost Controls (7): MoneyDisplay · QuantityDisplay · CommitmentGauge · Waterfall · CashflowChart · ContingencyDrawdown · ManagementReserveTracker

Otros pre-roadmap: GanttChart · WbsTreeGrid · WbsKanban · R9cRow · R9cTable · RiskHeatmap · ChangeOrderLog · PurchaseOrderRegister · DeliverablesProgressTable · LookaheadGrid

Componente Versión Sección Propósito
MilestoneStrip 0.10.0 P3 Schedule Barra horizontal hitos + health + Hoy + critical rombo.
ResourceHistogram 0.10.0 P3 Schedule StackingColumn por categoría + capacity stripline.
CriticalPathSummary 0.10.0 P3 Schedule Widget ejecutivo float + critical + slip + next milestone.
ScheduleVarianceTable 0.10.0 P3 Schedule Tabla baseline/current/forecast + slip pill + indent WBS.
BurndownChart 0.10.0 P3 Schedule Plan dashed + Actual con markers + status burn rate.
RiskRegisterTable 0.9.0 P4 Risk Tabla PMI completa con filtros + búsqueda + drill-down.
TornadoChart 0.9.0 P4 Risk Sensitivity ranking low/high simétricas.
MonteCarloHistogram 0.9.0 P4 Risk Distribución QRA + percentile striplines (P50/P80/P90).
RiskBoard 0.9.0 P4 Risk Kanban PMI lifecycle.
RiskTrendLine 0.9.0 P4 Risk Sparkline burden total + TrendDelta LowerIsBetter.
ApprovalWorkflow 0.11.0 P5 Scope Cadena aprobadores con states + comments + overall computed.
RaciMatrix 0.11.0 P5 Scope Role × actividad + validación PMBoK 9.1.2.1 automática.
CommodityPriceChart 0.14.0 P8 Mining Cu/Au/Li temporal + baseline stripline + Δ% pill.
StockpileLevel 0.14.0 P8 Mining Barra horizontal + bandas operacionales + status auto.
ProductionCurve 0.14.0 P8 Mining Plan vs Actual + nameplate + status achievement %.
ShiftSchedule 0.14.0 P8 Mining Calendario semanal turnos Day/Night/Maint/Off/Custom.

Novedades v0.22.0 — Specialized Inputs

4 componentes nuevos:

  • CayaquiRangeSlider — slider dual-handle numérico (wrapper SfSlider Range).
  • CayaquiColorPicker — color picker free-form + palette (wrapper SfColorPicker).
  • CayaquiTreeView<TNode> — tree view genérico con selector functions (wrapper SfTreeView).
  • CayaquiPagination — page nav hand-rolled con ellipsis dedup.

Sin breaking changes.

Novedades v0.21.0 — Dashboards Polish

4 componentes nuevos:

  • CayaquiKanban<TItem> — kanban genérico con selector functions y drag-drop HTML5 native.
  • CayaquiRating — rating estrellas standalone (interactive / read-only).
  • CayaquiCounter — número animado con easing cubic-out + cancellation correcta.
  • CayaquiButtonGroup — toggle data-driven entre opciones.

3 improvements opt-in:

  • CayaquiProgress.Shape="Circular" con SVG ring.
  • CayaquiTabs.Orientation="Vertical" (mapea a Syncfusion).
  • CayaquiTooltip.ContentTemplate para markup rico.

Refactor interno: WbsKanban ahora wrappea CayaquiKanban<KanbanPackage> — API pública idéntica. Sin breaking changes.

Novedades v0.20.0 — Forms & Patterns

5 componentes nuevos:

  • CayaquiAccordion + CayaquiAccordionItem — secciones colapsables template-based con CascadingValue.
  • CayaquiTimeline — eventos cronológicos, vertical/horizontal con status-colored dots.
  • CayaquiFileUploader — drag-drop dropzone (sin HTTP); emite IBrowserFile[].
  • CayaquiInputMask — wrapper sobre SfMaskedTextBox con presets RUT/RUC/Phone.
  • CayaquiAvatarGroup — stack de N avatares con chip +N.

4 improvements:

  • CayaquiButton.Loading con spinner inline.
  • CayaquiBadge enum + Pill + Outline modifiers.
  • CayaquiAlert enum + Dismissible + OnDismiss.
  • CayaquiAvatar.Status overlay dot.

Breaking minor: CayaquiBadge.Variant y CayaquiAlert.Variant pasaron de string a enum (CayaquiBadgeVariant/CayaquiAlertVariant). Migración mecánica vía find/replace; VariantString [Obsolete] provee escape hatch hasta v1.0. Detalles en scripts/migrate-to-components-0.20.0.md.

Novedades v0.19.0 — Cards suite

  • CayaquiCard refactored — 6 variants semánticas (Default | Primary | Success | Warning | Danger | Info), 4 modos de acento (Bar | Border | Tinted | None), 2 densidades (Comfortable | Compact). Todos los params opt-in; defaults 100% backward-compat. Cards con Title muestran una barra vertical gris muy suave por default (Accent="Bar"); suprimir con Accent="CayaquiCardAccent.None".
  • 4 comportamientos opt-in: Collapsible (@bind-Open), Closable (OnClose), Fullscreen (ESC sin JS interop), Tabs (@bind-ActiveTabId + slot TabbedContent).
  • 4 componentes nuevos: CayaquiStatCard (métrica + trend inline), CayaquiMediaCard (image cap top/side), CayaquiReviewCard (rating estrellas + autor), CayaquiActionCard (header persona + dropdown).
  • Token palette --color-info-* en cayaqui-tokens.css (Direction A + B). Resuelve referencias huérfanas pre-existentes en cayaqui-evm-extras.css y cayaqui-wbs-treegrid.css.
  • UserProfileCard refactorizado internamente para envolver <CayaquiCard NoPadding> — API pública idéntica.

Novedades v0.18.0

  • CayaquiIcons — clase estática (~150 constantes) con iconos Syncfusion agrupados por categoría semántica (Actions, Navigation, Export, Files, People, Status, Data, Charts, EVM, Arrows). Namespace Cayaqui.Components.Design. Elimina strings hardcodeados y hace los usos refactorizables.
  • IRouteLabelsProvider + RouteInfo — interfaz DI para resolución automática de label + icono en CayaquiBreadcrumbs. Registrar AddSingleton<IRouteLabelsProvider, MyProvider>() una sola vez en Program.cs; todos los breadcrumbs con AutoGenerate="true" lo consumen automáticamente.
  • CayaquiPageHeader.Card — nuevo parámetro bool Card = true que envuelve el header en una card blanca con borde gris. Personalizable con CardBackground y CardBorderColor (valores CSS arbitrarios).
  • CayaquiDialog fixDialogEvents.OnOverlayClick renombrado a OnOverlayModalClick en Syncfusion 33.2.3. Corrige InvalidOperationException en runtime al renderizar cualquier modal.
  • SVGs eliminados — todos los iconos SVG inline de la librería (AppHeader, Sidebar, Breadcrumbs, Grid, AutoGrid, etc.) reemplazados por clases e-icons de Syncfusion — bundle más pequeño, consistencia visual con el design system.

Novedades v0.17.0 — RiskHeatmap v2

RiskHeatmap fue completamente rediseñado. Las celdas ahora muestran chips con el ID del riesgo (R-01, O-02) en lugar de un contador, tooltip rico con título/responsable/categoría/score al hover, overflow "+N más" con popover de lista completa, y un filtro segmentado Inherente / Residual / Objetivo. Las amenazas se distinguen en rojo y las oportunidades en verde.

Nuevos campos en RiskItem (todos nullable, backwards-compatible):

  • ProbabilityResidual, ImpactResidual — coordenadas de la vista Residual.
  • ProbabilityTarget, ImpactTarget — coordenadas de la vista Objetivo.
  • IsOpportunitytrue para oportunidades (chip verde).

Nuevos parámetros en RiskHeatmap:

  • View + ViewChanged — binding bidireccional (@bind-View).
  • ShowViewFilter — muestra/oculta el selector de vista (default true).

Migración entre versiones

Cada versión tiene su script de migración en scripts/migrate-to-components-X.Y.Z.md del repo. Para upgrades multi-versión (e.g. 0.4.x → 0.14.0) usar scripts/consumer-upgrade-to-0.10.0.md + el script de la versión target.

Para greenfield (proyecto Blazor WebApp nuevo): scripts/consumer-setup.md configura todo desde cero (Program.cs + App.razor + MainLayout).

Documentación completa

El catálogo vivo (demos + props detallados + ejemplos) está en github.com/Cayaqui/XMOVESUNDERXDESIGN:

  • /docs/components/*.md — sintaxis, ejemplos y tabla de props para cada componente.
  • /docs/roadmap-componentes.md — estado del roadmap (47 items, P1–P8 cerrado).
  • /CHANGELOG.md — historial de versiones con breaking changes y migration notes.
  • /scripts/migrate-to-components-*.md — scripts de migración por versión (0.5.0 → 0.14.0).
  • /docs/infrastructure/metadata.md — integración con Cayaqui.Metadata.
Product Versions Compatible and additional computed target framework versions.
.NET net10.0 net10.0 is compatible.  net10.0-android net10.0-android was computed.  net10.0-browser net10.0-browser was computed.  net10.0-ios net10.0-ios was computed.  net10.0-maccatalyst net10.0-maccatalyst was computed.  net10.0-macos net10.0-macos was computed.  net10.0-tvos net10.0-tvos was computed.  net10.0-windows net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.3.8 0 6/18/2026
0.3.7 0 6/18/2026
0.3.6 0 6/18/2026
0.3.5 32 6/18/2026
0.3.4 43 6/17/2026
0.1.2 45 6/16/2026
0.1.1 55 6/16/2026
0.1.0 55 6/15/2026

0.3.8 — YNEX visual fidelity (preset ynex): .cayaqui-card border-radius 0.375rem (era radius-md 8px). .cayaqui-crumbs a.crumb color var(--color-accent-600) (era text-tertiary). .sb-item.active font-weight 600. .cayaqui-badge font-weight 700. CompanyThemes.Ynex.RadiusScale 1 (era 4/6; radius-sm=6px = YNEX base 0.375rem). Sin breaking changes.
0.3.7 — CompanyThemes.Ynex: nuevo tema canónico YNEX (violet #845BDF, sidebar Default, header Default, direction A, density Comfort, radiusScale 4/6). Activar: opts.DefaultCompanyThemeId = CompanyThemes.Ynex.Id. Sin breaking changes.
0.3.6 — YNEX KPI card fidelity (preset ynex). .kpi-card: border-color transparent + box-shadow 0 2px 6px rgba(56,65,74,.15) (era solo border). .kpi-badge-mark: circular pill 40×40px (era rounded square radius-md). .kpi-value: --text-3xl 24px (era --text-4xl 30px). Status variants (--success/warning/danger) conservan borde semántico vía :not(). Dark mode override explícito (rgba 0,0,0,.30). Sin breaking changes.
0.1.2 — CayaquiLineChart: nuevo parámetro LabelFormat con formatter del eje Y en es-CL. MpsPageHeader: .ph-title aumenta a var(--text-3xl) (era text-xl). Sin breaking changes.
0.65.8 — YNEX table fidelity: .cayaqui-table y Syncfusion .e-grid/.e-treegrid alineados a YNEX. Headers sin uppercase ni letter-spacing, font-size var(--text-sm), font-weight 600, color var(--color-text), background var(--color-surface). Border-radius var(--radius-md). .cayaqui-table td color var(--color-text). Sticky first-col background corregido a var(--color-surface). Untitled preset reintroduce estilo original: radius-xl, uppercase + letter-spacing, font-size xs, weight 500, color tertiary, bg surface-alt. Sin breaking changes.
0.65.7 — YNEX card fidelity: .cayaqui-card margin-block: 1.5rem (espaciado vertical entre cards). .cayaqui-card-footer sin background (era var(--color-surface-alt), YNEX usa transparent). .cayaqui-card-group y .cayaqui-kpi-tile zerean el margen (el gap del grid maneja el espaciado). Sin breaking changes de API.
0.65.6 — YNEX form fidelity global: inputs/textareas usan border ligero (--color-border), border-radius 6px (radius-sm), sin shadow en reposo, hover sutil (border-strong), focus solo cambia border-color (sin ring 4px). Labels 0.8rem weight 600. Placeholders weight 500. Checkboxes/radios border 1px ligero. Botones radius 6px (radius-sm). Untitled preset preserva estilo original: radius-md + shadow-xs para inputs, label var(--text-sm) weight 500, btn radius-md. Sin breaking changes de API.
0.65.5 — Fix: .cayaqui-kpi-tile--info .cayaqui-card usaba border-color (ignorado con border:none base de 0.65.4); corregido a border: 1px solid. 0.65.4 — MpsCard YNEX fidelity global: base card ahora coincide con YNEX por defecto (sin border, border-radius 8px/radius-md, bottom shadow 0 0.125rem 0 rgba(10,10,10,.06)); dark mode override explícito (rgba 30%). Padding base alineado a YNEX: header/footer 16px/20px, body 20px. Title 0.9375rem weight 700. Untitled preset mantiene su estilo propio via [data-cayaqui-theme="untitled"] overrides (border, radius-xl, shadow-sm, padding original, title text-lg 600). Sin breaking changes de API. 0.65.3 — MpsPageHeader full-bleed: patrón margin negativo + padding simétrico. El consumer establece --cayaqui-ph-bleed-x en el contenedor padre (igual al padding horizontal del contenedor). El header extiende su fondo/sombra de borde a borde mientras el contenido interno alinea con el resto de la página. Sin bleed (default 0px): comportamiento actual sin márgenes negativos. 0.65.2 — MpsPageHeader: margin-left e margin-right explícitamente 0 (era margin-bottom solamente; header HTML puede heredar márgenes de resets). 0.65.1  — MpsPageHeader: padding horizontal 0 (era var(--sp-6)), width: 100%. El consuming layout provee el padding horizontal. 0.65.0 — MpsSidebar YNEX behavior completo: sidebar fixed (position: fixed, full-height), mobile off-canvas drawer con backdrop (transform slide-in &lt;1024px), flyout submenus animados opacity/visibility/transform (era display:none/block), ToggleSidebarAsync() viewport-aware (desktop=collapse/expand, mobile=drawer), auto-close drawer on navigation, CSS layout utilities cayaqui-sb-shell/cayaqui-sb-content con :has() auto margin-left. Sin breaking changes. 1166 tests. 0.64.0 — MpsPageHeader YNEX redesign: full-width white band, dual-layer blurred shadow, breadcrumbs below subtitle. Eliminados parámetros obsoletos: Card/Tinted/CardBackground/CardBorderColor. 0.63.0 — Responsive móvil por defecto. Los 184 componentes renderizan correctamente a 390px sin configuración: mecanismo híbrido container queries (componentes embebibles se adaptan a su celda) + media queries viewport (solo layout global) + pointer:coarse (touch targets 44px WCAG 2.5.8, 40px en items densos). Tablas: patrón .cayaqui-table-scroll (scroll-x con hint de sombras + primera columna sticky bajo 640px de contenedor + min-width configurable vía --cayaqui-table-min-width) aplicado a R9C, RiskRegister, PurchaseOrder, Deliverables, ScheduleVariance, ChangeOrderLog, Lookahead, EngProgress, RACI; SfGrid/SfTreeGrid usan scroll interno Syncfusion con min-width override (sticky vía FrozenColumns = follow-up). Charts: nuevo MpsChartResponsive (public static, idempotente) aplicado a los 24 charts ApexCharts — bajo 640px viewport: leyenda abajo, dataLabels off, labels 10px, toolbar oculto; Timeline/Gantt con scroll-x y ancho mínimo 700px. Layout: modals/dialogs full-screen bajo 640px (incl. SfDialog), drawers 100%, toasts stretch, AppHeader alineado a convención 640/1024, sidebar off-canvas bajo 1024px con nuevos parámetros MpsSidebar.MobileOpen/MobileOpenChanged (@bind) y backdrop. Forms: EditForm de MpsAutoForm con clase .cayaqui-autoform (container), submit full-width en contenedor angosto. Fixes colaterales: .cayaqui-radio .box tenía tamaño 0x0 (invisible desde siempre) — ahora 18px base; botón delete de MpsFileManager era hover-only (inaccesible touch) — siempre visible; MpsCommandMenu/popovers/dropdowns con cap calc(100vw-16px). Sin breaking changes: API solo aditiva (MobileOpen/MobileOpenChanged, MpsChartResponsive). +47 tests (1158 total). Auditoría completa en docs/components/2026-06-11-mobile-audit.md. 0.62.1 — Fix MpsBarChart NaN labels en barras horizontales. Xaxis.Type ahora Numeric (no Category) para Orientation=Vertical (barras horizontales); Yaxis.Labels.Formatter usa función identidad para categorías string en vez del formateador numérico — evita que Intl.NumberFormat() devuelva NaN al recibir strings de etiqueta.
0.62.0 — Badge i18n en columnas manuales (issue #3). MpsGridColumn Kind=AutoBadge sin DtoType/PropertyName (columnas manuales con &lt;Columns&gt;) ahora resuelve el texto del badge vía [Display(Name)] del miembro del enum y el color vía [BadgeColor] del miembro — antes caía a enum.ToString() (inglés) y color gris. MpsAutoBadge standalone también lee [Display(Name)] para el texto (el color por [BadgeColor] vía EnumBadgeMap se mantiene, indexado por nombre del miembro). Fallback a ToString() cuando no hay [Display]. Aditivo, sin breaking — el modo AUTO (resolver-driven) queda igual. +4 tests (1135 total).
0.61.1 — Fix dependencia: requiere Cayaqui.Metadata 0.20.0. La 0.61.0 declaraba dep en Metadata 0.19.0, cuyo binario publicado tenía `IExtendedPropertyResolver` en el namespace raíz `Cayaqui.Metadata` mientras el source ya lo había movido a `Cayaqui.Metadata.Resolver` — provocaba `TypeLoadException` en runtime al renderizar grids/componentes metadata-driven. Sin otros cambios respecto a 0.61.0.
0.61.0 — MpsAppHeader: action items estilo YNEX (opt-in). Nuevos params: ShowNotifications + Notifications/NotificationBadge/PulseBadge/OnNotificationClick/OnViewAllNotifications (bell + badge unread con cap 9+ + dropdown), ShowFullscreen (reusa MpsFullscreenToggle), ShowAppsGrid + AppShortcuts/OnAppShortcutClick (apps-grid e-grid-view), ShowLanguageSelector + Languages/CurrentLanguageCode/OnLanguageChanged. Nuevos records MpsHeaderNotification/MpsHeaderAppShortcut/MpsHeaderLanguage. Estado unificado: un solo dropdown abierto a la vez + backdrop click-outside (incluye el user-menu existente). Aditivo, sin breaking.
0.60.3 — Nuevo accent de marca ThemeAccent.AndesIron (Andes Iron SpA, minera): rust óxido de hierro #ED6F51, escala 50–800 light+dark en cayaqui-tokens.css + cayaqui-theme.js, swatch en MpsThemeSwitcher. Aditivo, sin breaking.
0.60.2 — MpsColumnChart&lt;T&gt;: nuevo ColorField (Func&lt;TItem,string?&gt;) — color por columna (distributed mode, serie única) para color semántico / atenuación de cross-filter. Aditivo.

0.60.1 — MpsLineChart&lt;T&gt; y MpsColumnChart&lt;T&gt;: nuevo OnPointClick (EventCallback&lt;TItem&gt;) vía OnDataPointSelection — habilita cross-filter por columna/punto (ej. distribución por programa en dashboards Portfolio). Aditivo, sin breaking.

0.60.0 — Charts: 3 nuevos + 2 mejoras de interactividad (cierra la migración fuera de Syncfusion). Nuevos: MpsLineChart&lt;T&gt; (serie única o multi-serie vía Series=MpsChartSeries&lt;T&gt;, marcador ControlDate con XAxis=DateTime), MpsColumnChart&lt;T&gt; (agrupado/apilado, Plan-Real-EAT), MpsPieChart (motor Donut con InnerRadius=0, hereda interactividad). MpsDonutChart/MpsPieChart: OnItemClick (EventCallback&lt;DonutItem&gt;), SelectedLabel + DimUnselected (atenúa no seleccionados para cross-filter), color semántico por item. MpsScatterChart&lt;T&gt;: OnPointClick (drill-down), ejes fijos XMin/XMax/XInterval + YMin/YMax/YInterval, plotlines XPlotLine/YPlotLine, bubble vía SizeField/ColorField, DecimalPlaces. Nuevos tipos públicos: MpsChartSeries&lt;T&gt;, MpsAxisType, MpsChartPalette. BREAKING menor: DonutItem ahora es record (Label, Value, Color?) — la deconstrucción posicional de 2 elementos (`is DonutItem(var l, var v)`) deja de compilar; la construcción de 2 args sigue válida. +17 tests (1111 total). API pública sin dependencia de ApexCharts.

0.59.0 — BREAKING: MpsAutoGrid eliminado, fusionado en MpsGrid. MpsGrid ahora soporta modo AUTO: omití &lt;Columns&gt; y las columnas se generan desde los atributos de Cayaqui.Metadata (igual que el viejo MpsAutoGrid). Params absorbidos: Include, Exclude, RowActions, RowActionsHeader, RowActionsWidth. Migración: renombrá la etiqueta &lt;MpsAutoGrid&gt; → &lt;MpsGrid&gt; — los parámetros son idénticos, no requiere otros cambios. El modo MANUAL (con &lt;Columns&gt;) queda sin cambios. 0.58.1 — Dark-mode theme engine fixes. Fix: opts.mode=undefined treated as 'system' (was defaulting to 'light', causing dark-attr/light-palette mismatch). Fix: OS dark/light toggle now refreshes inline accent palette (init() listener now calls apply(_lastOpts) instead of only applyMode()). Fix: custom accent generates correct dark-mode palette when isDark=true (was always generating light values). Fix: unknown accent key in dark mode falls back to dark cobalt (not light cobalt). Fix: CSS comment corrects specificity annotation on branded/gradient dark override (0,6,0).

0.58.0 — YNEX fidelity + Violet accent. YNEX preset now matches original YNEX admin template (body #F0F1F7, Montserrat sidebar font, 240px sidebar, 60px header, no-border 8px-radius cards with bottom shadow). New accent: Violet (#845BDF). Fix: Accent=Bar restored under YNEX (border:none shorthand was killing border-inline-start). Fix: dark YNEX sidebar hover uses rgba(255,255,255,0.08) instead of near-white. Fix: dark Direction B text tokens now set correctly.

0.57.0 — Mixed Mode (DetailList + AutoForm) + Grid Attributes. MpsDetailList: Source= + MpsDetailItem children como overrides/appends. MpsAutoForm: ChildContent con MpsAutoFormField For= como overrides de campo. Nuevos attrs de grid (requiere Cayaqui.Metadata 0.19.0): [GridWidth] y [GridFormat] para MpsAutoGrid. BREAKING: MpsBadge y MpsAlert eliminan param obsoleto VariantString — usar Variant enum. Fix: MpsProgressBars/MpsProgress usan InvariantCulture en CSS widths. Fix: MpsSidebarItem.ToggleOpen usa StateHasChanged. MpsThemeSwitcher: 4 botones de preset (Ynex A/B, Untitled, Untitled Cool).

0.56.0 — Metadata-driven MpsDetailItem + MpsDetailList. MpsDetailItem: nuevo parámetro For= (LambdaExpression) — auto-label, formato y badge desde atributos DTO ([Label], [Currency], [Date], [Badge]/[BadgeColor]). MpsDetailList: nuevo parámetro Source= (object?) — genera automáticamente todos los ítems visibles del DTO vía IExtendedPropertyResolver; group headers cuando GroupName cambia. Ambos backward-compatible — sin cambios en API existente.

0.55.0 — Preset auto-defaults + 4 nuevos componentes. ThemeService.SetAsync detecta cambio de preset y aplica accent/density/radius fijos (Ynex→Emerald, Untitled→Cobalt). Nuevos: MpsDivider, MpsFeatureCard, MpsDetailList+MpsDetailItem, MpsStepIndicator+MpsStep.

0.54.0 — UntitledUI v8-Inspired Theme: nuevo ThemePreset (Ynex/Untitled) + ThemeGray (Neutral/Cool). Tema paralelo al sistema YNEX, activado vía data-cayaqui-theme="untitled". Grays UntitledUI exactos (Gray-25 #FCFCFD como bg principal). Variante Cool gray con tinte azul-frío. Dark mode completo para ambas variantes. MpsThemeSwitcher actualizado: sección "Tema Visual" con 4 opciones (Ynex A · Ynex B · Untitled · Untitled Cool). ThemeState extendido con Preset + Gray (defaults backwards-compat). Sin breaking changes para consumidores existentes.

0.53.0 — YNEX Accent System: 4 nuevas paletas (Navy/Teal/Rose/Orange) + Custom accent picker (HSL palette generator en JS). ThemeSidebarTone global (Default/Tinted/Branded/Gradient/Transparent) vía data-cayaqui-sidebar. ThemeHeaderStyle global (Default/Color/Gradient) vía data-cayaqui-header. MpsSidebar.SidebarTone ampliado con Gradient + Transparent. MpsThemeSwitcher renovado con secciones de Sidebar Tone, Header Style y Custom Color Picker. Fix: Cayaqui.Licensing.dll ahora está incluido en lib/net10.0/ del .nupkg (mismo bug de packaging que 0.45.0/0.45.1 y 0.52.6 — pack sin build previo).

0.52.6 — Fix: accordion CSS base rule (.cayaqui-sidebar .sb-submenu max-height:0) was silently dropped by browser CSS parser due to a stray closing brace after the MpsChat media query block. Accordion visually open/close now works correctly in all browsers.

0.52.5 — MpsSidebar accordion multinivel YNEX-style: MpsSidebarItem completely rewritten. Supports ChildContent nesting (declarative) and Children parameter (data-driven). Submenu slides open/closed with CSS max-height transition. In collapsed/slim mode, submenus appear as hover flyout popovers. MpsSidebar: RegisterRootItem / OnItemExpanded for exclusive accordion behaviour.

0.52.4 — MpsBulletGauge, MpsGauge, MpsSparkline: ShouldRender() optimization — skips DOM diff when no parameter has changed. Prevents unnecessary re-renders on parent rerender in dashboard layouts.

0.52.3 — MpsAutoGrid, MpsGrid: EnableVirtualization parameter (bool, default false). When Height is set and DataSource exceeds 50 items, virtualization auto-activates. Explicit EnableVirtualization="true" forces virtual rendering regardless of count.

0.52.2 — MpsTimeline: Simple, Detailed, TwoColumns layout support; LoadMore button; sub-badges. MpsThemeSwitcher: ThemeService-synchronized offcanvas panel.

0.52.1 — PackageReadme documentation update and minor build fixes.

0.52.0 — YNEX Premium components integration: MpsChat (collaboration center with contact list, sidebar filtering and JS auto-scroll via cayaqui-chat.js), MpsTimeline detailed layouts (Simple, Detailed, TwoColumns layouts, custom avatars, sub-badges and deferred loading), MpsTaskCard (priority cards with assignee avatars and starring), MpsTeamSparklineList (ApexCharts performance sparkline for team members) and MpsThemeSwitcher (offcanvas style control panel synchronized with ThemeService).

0.51.0 — MpsWorkflowEditor + MpsWorkflowMini (Engineering.Workflow): generic pipeline editor and compact read-only variant — parameter-driven nodes/presets, ActiveKeys two-way binding. MpsFullscreenToggle (Design.Navigation): browser fullscreen API button with JS interop via cayaqui-fullscreen.js. MpsReconnectModal (Design.Feedback): Blazor Server circuit reconnect dialog with i18n parameters via cayaqui-reconnect.js.

0.50.0 — MpsDomainHeader: Collapsible parameter (bool). MpsScheduleTimeline (Evm): new visual timeline bar — PlannedStart/End, PhysicalProgress, Spi, DaysDeviation, ProjectedEnd.

0.49.8 — Fix: MpsCardGroup reverted to minmax(min, max) — MaxCardWidth="Xpx" is a hard column cap; use default 1fr for full-width rows. App.razor link to {App}.styles.css documented as required.

0.49.7 — Fix: MpsCardGroup grid CSS moved to cayaqui-bundle.css (cayaqui-components.css) — previously only in Blazor scoped bundle, causing layout to break when styles.css was not linked.

0.49.6 — MpsCardGroup: new MaxCardWidth parameter (default "1fr"). Use MinCardWidth="280px" MaxCardWidth="400px" to cap card size in auto-fill grids.

0.49.5 — Merge: MpsCpiGauge + MpsSpiGauge absorbed into MpsGauge via GaugePreset.Cpi/Spi. Merge: MpsVariancePill + MpsTrendDelta absorbed into MpsDeltaChip (Variant=Variance/Trend). Migration: MpsCpiGauge → MpsGauge Preset="GaugePreset.Cpi"; MpsTrendDelta → MpsDeltaChip Variant="DeltaVariant.Trend".

0.49.4 — Fix: MpsGrid Number column formatting now uses CultureInfo.CurrentCulture instead of InvariantCulture — numeric values now display with correct locale separators (e.g. es-CL: 1.234.567 instead of 1,234,567).

0.49.3 — Merge: MpsPhysicalProgressCurve absorbed into MpsProgressSCurve (ShowPartialBars=false). ProgressSCurvePoint gains BaselineCumulative?. Migration: use MpsProgressSCurve ShowPartialBars="false"; rename BaselinePct→BaselineCumulative, PlanPct→PlanCumulative, ActualPct→ActualCumulative, ForecastPct→ForecastCumulative.

0.49.2 — Docs: GenerateDocumentationFile enabled; 876 [Parameter] properties now carry /// &lt;summary&gt; XML IntelliSense docs across all 181 components (Design, Evm, Engineering). No API or binary changes.

0.49.1 — MpsCardGroup: equal-height card grid container (auto-fill responsive + optional Columns override).

0.47.2 — Fix: MpsGrid Height defaults to "auto" when not set — prevents NullReferenceException in SfGrid.GetStyle() during SSR. No breaking changes.

0.47.1 — Fix: MpsGrid now accepts Height parameter (string?, e.g. "280px") and forwards it to SfGrid — fixes InvalidOperationException "does not have a property matching the name 'Height'". No breaking changes.

0.47.0 — R9cRow.R9cEntry: breaking change — Ac→Incurred, ToCommit→Paid, nuevo Trends, eliminado Variance. PctExec renderiza correctamente en escala 0..1 (fix: era 0.9% en vez de 85%). 0.46.1 — Docs: theming guide expandida en PackageReadme. Secciones nuevas: ThemeDirection A vs B, MpsColorModeToggle props, tabla de CSS tokens semánticos (--color-bg, --color-text, --color-surface, --color-accent-*) para dark mode compatibility en componentes custom del consumer. Sin cambios de API ni binarios.

0.46.0 — Dark / Light / System color mode. New: ThemeMode enum, ThemeOptions.DefaultMode (default=System), ThemeService.Mode + SetAsync(mode:) + InitializeAsync with Mode, MpsThemeAttributes dark support (emits data-cayaqui-mode=dark), MpsColorModeToggle component (Light/System/Dark segmented toggle with SVG icons). CSS: dark palette in cayaqui-tokens.css for Direction A+B and all 5 accents. JS: cayaqui-theme.js applyMode() + OS prefers-color-scheme change listener. Consumer setup: add dual Syncfusion &lt;link&gt; + 2 anti-FOUC scripts to App.razor (see PackageReadme). Breaking: ThemeState record gains Mode as last parameter — update any ThemeState(...) direct constructors to add ThemeMode.System as final arg.

v0.45.2 — Fix: Cayaqui.Licensing.dll ahora se incluye en lib/net10.0/ del .nupkg. En 0.45.0/0.45.1 el DLL faltaba en el deploy del consumer (502.5 en IIS). Sin cambios de API.

v0.45.1 — Fix: re-publicación de 0.45.0 con binarios correctos (0.45.0 empaquetó binarios sin las adiciones de licensing por flag --no-build). Sin diferencia de API.

v0.45.0 — Licensing: AddMpsComponents acepta opts.LicenseKey (ECDSA P-256). Sin clave válida se muestra banner en app header y marca de agua en output. ComponentsLicenseState registrado en DI. Sin breaking changes — licenseKey es opcional y todos los comportamientos existentes se mantienen cuando no se provee.

v0.44.4 — Docs: secciones completas de uso (parámetros + ejemplos) para EvmCashflowCurve y PhysicalProgressCurve en PackageReadme. Nota de los fixes 0.44.2–0.44.3 (ArgumentException DateTimeOffset). Sin cambios de código.

v0.44.3 — Fix: mismo ArgumentException en DateTimeOffset..ctor(DateTime, TimeSpan.Zero) corregido en los 5 componentes restantes con el patrón: PhysicalProgressCurve, MpsProgressSCurve, ContingencyDrawdown, CashflowChart, MpsTimelineChart. Todos usan DateTime.SpecifyKind(x.Date, DateTimeKind.Utc). Sin breaking changes.

v0.44.2 — Fix: EvmCashflowCurve lanzaba ArgumentException al recibir un ControlDate con DateTimeKind.Local (ej. DateTime.Today). DateTimeOffset..ctor(DateTime, TimeSpan.Zero) requiere Kind.Utc o Kind.Unspecified. Corregido con DateTime.SpecifyKind(cd.Date, DateTimeKind.Utc). Sin breaking changes.

v0.44.1 — Fix: Tooltip.Intersect=false en 7 componentes con Shared=true (StackedBarChart, ContingencyDrawdown, ResourceHistogram, EvmControlChart, EvmCashflowCurve, PhysicalProgressCurve, ProductionCurve) — ApexCharts lanza excepción si ambos son true. Sin breaking changes.

v0.44.0 — MpsListGroup: lista estilizada model-driven (icono, badge, selección, Flush, ItemTemplate). MpsFileManager: browser Grid/Lista para documentos — auto-icono por extensión, OnOpen/OnDelete, @bind-ViewMode. Migración Syncfusion.Blazor.Charts → ApexCharts (17 componentes). Sin breaking changes en API pública. Consumers deben quitar Syncfusion.Blazor.Charts de sus propios csproj si no lo usan en otro lugar. 999 tests totales.

0.43.8 — MpsProgressSCurve: etiqueta de Fecha de Control vertical sobre línea punteada; leyendas simplificadas (Plan/Real/Forecast, sin " acum."). v0.43.7 — MpsProgressSCurve: títulos de ejes Y — "Avance Acumulado" en Y1 izquierdo y "Avance Parcial" en Y2 derecho, ambos con escala %. v0.43.6 — Fix MpsProgressSCurve leyenda: selector CSS corregido de data-series-index a rel (1-based) para ocultar barras parciales — ApexCharts usa rel en ítems de leyenda. v0.43.5 — Fix MpsProgressSCurve: eje Y secundario para barras parciales implementado con 6 entradas YAxis + SeriesName binding (elimina InvalidOperationException por YAxisIndex no disponible como parámetro Blazor). 956 tests. v0.43.4 — MpsProgressSCurve: barras parciales en eje Y2, leyenda limpia (series bar ocultas via CSS), Forecast acum. anclado al último punto Real acum., Plan acum. línea continua. v0.43.3 — Fix tooltip JS error (shared+intersect). v0.43.2 — MpsEngProgressTable totales y bordes. v0.43.1/0.43.0 — MpsProgressSCurve: Curva S de avance físico, gráfico mixto ApexCharts. Fix MpsTimelineChart eje X. v0.43.0 — MpsProgressSCurve: Curva S de avance físico con gráfico mixto ApexCharts (barras periódicas + líneas acumuladas) para Plan/Real/Forecast. Paleta EVM canónica (#2E5BFF/#D92D20/#039855). Anotación ControlDate vertical y goal line 100%. Consumer provee parciales y acumulados explícitamente (ProgressSCurvePoint). Fix: MpsTimelineChart eje X corregido a XAxisType.Datetime. 956 tests totales. v0.42.0 — MpsEngProgressTable: tabla Plan/Forecast/Actual/Var por documento con hitos configurables. v0.41.0 — MpsDocCard + MpsDocRevisionList + MpsDocStatusBadge. v0.40.0 — MpsCalendar (FullCalendar 6). v0.39.0 — MpsHeatmapChart + MpsTimelineChart (ApexCharts). v0.34.0 — Skeleton composites para arquetipos de loading-state. Cinco componentes nuevos sobre MpsSkeleton cubren los arquetipos comunes: MpsSkeletonStack (N líneas para forms/párrafos), MpsSkeletonCard (header + body línea/rect para detail/charts), MpsSkeletonRow (avatar + título + subtítulo para listas), MpsSkeletonGrid (grilla de tiles para KPI strips, default 1x4), MpsSkeletonTable (toolbar + N filas para index pages, RowHeight default 2.5rem para match con MpsAutoGrid). Composición típica de dashboard reemplaza un &lt;MpsSkeleton /&gt; plano por &lt;MpsSkeletonGrid /&gt; + &lt;MpsSkeletonCard Height="280px" /&gt; + &lt;MpsSkeletonTable /&gt; — reduce layout shift y comunica visualmente qué tipo de contenido viene. Todos los composites consumen internamente &lt;MpsSkeleton/&gt; — heredan shimmer y prefers-reduced-motion. +37 tests bUnit (798 total). Sin breaking changes — aditivos sobre v0.33.0. Ver scripts/migrate-to-components-0.34.0.md para recetas. v0.33.0 — MpsSkeleton runtime fix. El componente rendereaba `&lt;div class="cayaqui-skeleton ..."&gt;` pero la regla CSS empacada era solo `.skeleton` — desde la primera versión. En 0.33.0 la clase se alinea (`.cayaqui-skeleton`), `@keyframes shimmer` se namespacea como `cayaqui-skeleton-shimmer`, se agregan defaults dimensionales por shape (line 100% × 0.875rem, rect 100% × 6rem, circle 2.5rem × 2.5rem) — `&lt;MpsSkeleton /&gt;` sin parámetros ahora es visible. Soporte `prefers-reduced-motion: reduce` (WCAG 2.3.3). +7 tests bUnit (761 total). Sin breaking changes; consumers que aplicaron hotfix consumer-side (regla `.cayaqui-skeleton` en `app.css`) pueden removerlo. v0.32.0 — MpsPageHeader sincroniza el browser tab title automáticamente. Nuevo `ThemeOptions.AppName` (configurable en AddMpsComponents) sirve como sufijo. Formato `{Title} · {AppName}` (middot). Override por instancia con `BrowserTabSuffix` (sufijo) y `BrowserTabTitle` (título distinto al header). Opt-out con `SetBrowserTab=false`. Helper estático `MpsPageHeader.ComputeBrowserTabTitle(...)` testeable. Fix de bug: la versión anterior tenía `<PageTitle>@Title - MOVES</PageTitle>` hardcodeado en una librería genérica — rompía consumers no-MOVES y filtraba el nombre del proyecto. DoubleProgress / TripleProgress: barras a 90% opacidad (antes 50%). +12 tests (754 total). Sin breaking de API; el browser tab default sigue activo (ahora correcto). v0.31.0 — CashflowChart leyenda con valores en CutOffDate. Reemplaza el header "totales" por una leyenda HTML con dos grupos: "Mes de cutoff" (Plan/Real/Forecast columnas — valor del mes de control, Forecast=total restante) y "Acumulado al cutoff" (Plan acum./Real acum./Forecast acum.=EAC). Si no hay CutOffDate, los valores son los totales del rango. Cada entrada con swatch que replica el estilo del chart (columnas opacidad 0.65, líneas sólidas, Forecast acum. dashed verde). Legend Syncfusion built-in se oculta — la nueva leyenda HTML usa MoneyDisplay para formato consistente con el resto del design system. Nuevo helper estático `ComputeLegendValues(raw, cutOffDate)` testeable. +3 tests (742 total). Sin breaking de API. v0.30.1 — CashflowChart palette EVM canónica. Plan=azul (#2E5BFF), Real=rojo (#D92D20), Forecast=verde (#039855) con la línea acumulada de Forecast en verde segmentado (DashArray 6,3). Las columnas mensuales usan los mismos hex al 75% de opacidad para diferenciarse visualmente de las líneas acumuladas (100%). Reemplaza la paleta inicial 0.30.0 (Plan azul, Real verde, Forecast naranja).

v0.30.0 — CashflowChart 2.0: extiende el componente con capa acumulada (3 series tipo línea sobre eje Y secundario) además de las columnas mensuales. Plan acum. cubre todo el rango; Real acum. ≤ CutOffDate; Forecast acum. arranca en el Real acum. del cutoff (continuidad visual con la línea Real) y luego suma los Forecast period-by-period. Las columnas Forecast quedan filtradas automáticamente a meses &gt; CutOffDate (antes el caller debía nullear los pre-cutoff manualmente). Nuevo parámetro `ShowCumulative` (default `true`) controla la capa de líneas. Nuevo parámetro `CutOffDate` (alias retro-compat de `ControlDate`). Anchor robusto cuando CutOffDate no coincide con un punto exacto del dataset (cae en el último ≤ cutoff). +10 tests (739 total). Sin breaking changes; consumers que pasen `ShowCumulative="false"` mantienen el aspecto 0.29.x.

v0.29.0 — Tipografía dual Cayaqui. Roboto Condensed para charts, tablas, valores numéricos, KPIs y códigos tabulares (Money/Counter/Range/Stat-card/Pagination/R9C/PO/Risk/Sensitivity/Lookahead). Inter para cuerpo, labels, títulos, botones — "el resto del contenido". Nuevos tokens CSS: --font-numeric, --font-table, --font-chart. Charts Syncfusion (SfChart, AccumulationChart, StockChart, RangeNavigator, Sparkline, Gauges, Gantt) y custom (cayaqui-gauge, cayaqui-bullet) reciben Roboto Condensed via SVG &lt;text&gt; rule. SfGrid + TreeGrid + .cayaqui-table + .cayaqui-po-table + .cayaqui-deliv-table + .cayaqui-risk-table + .cayaqui-svt-table heredan font-table. Utility `.mono` re-apuntada a --font-numeric (los 30+ usos en razor — MoneyDisplay/MpsCounter/CurrencyInput/MpsGridColumn/etc — quedan correctos sin migración). Nuevo `.kbd` para mono real (JetBrains Mono kept). El @import del Google Fonts ahora trae Inter 300/400/500/600/700 + Roboto Condensed 300/400/500/700 + JetBrains Mono. Recomendado: el consumer precarga las fuentes con &lt;link rel="preconnect"&gt; en App.razor para LCP óptimo (ver PackageReadme). v0.28.1 — Patch fix de IOptions&lt;ThemeOptions&gt; en AddMpsComponents. v0.28.0 — Theme SSR support, elimina FOUC. Sin breaking changes en v0.29.0; sólo cambia la familia tipográfica visual.