# AstrolUI — Guía de migración del refactor .NET 10 > **Para IA / agentes:** este documento es la fuente de verdad para migrar un proyecto que usa > paquetes `Astrol.*` a la versión refactorizada. Cada cambio tiene un **ID estable** (`M-xxx`), > un patrón de **detección** (regex o búsqueda literal), la **acción** a aplicar y un ejemplo > **antes / después**. Aplica los cambios en orden de ID. Si un patrón no aparece en el proyecto, > el cambio no aplica. No renombres clases de iconos `astrol-*`: se conservan todas. > > **Para humanos:** también sirve como base para documentar las novedades en > `Astrol.Web.UI.Docuemnt`. La sección "Notas para la documentación" de cada cambio indica qué > página del documentador hay que tocar. ## Convenciones - Versionado de paquetes: `.` → con .NET 10.0.8 los paquetes eran `10.0.8.N`; desde el 2026-10-24 todo AstrolUI usa .NET **10.0.13** y los paquetes son `10.0.13.N` (ver V-025). - Ámbito: `[Assets]` = rutas CSS/JS en `index.html` / `App.razor` / `_Host.cshtml`; `[API]` = código C#/Razor; `[Visual]` = cambia el aspecto sin romper compilación; `[Interno]` = no requiere acción del consumidor. - Severidad: **Rompe** (no compila o falla en runtime) · **Visual** (se ve distinto) · **Ninguna**. ## Versiones El refactor se desarrolla en la rama `AI-NET-10` y **no se publica por partes**: cuando esté pulido se publicará una única primera versión del refactor con todos los paquetes a la vez. Hasta entonces, la última versión publicada de cada paquete es la previa al refactor: | Paquete | Última publicada (pre-refactor) | Afectado por el refactor | |---|---|---| | Astrol.Entities.Basic | 10.0.8.2 | sí | | Astrol.JSInterop.Base | 10.0.8.1 | sí | | Astrol.Component.Basic | 10.0.8.7 | sí | | Astrol.Component.RichText | 10.0.8.1 | sí (assets de Quill) | | Astrol.Component.Board | 10.0.8.1 | sí (interact.js) | --- ## Lote 1 — Base y dieta de assets (Fase 0 + Fase 1) Resultado medido en el documentador: el CSS de Basic pasa de ~220 KB en 4 peticiones encadenadas (`@import`) a **1 fichero de 62 KB (12 KB gzip)**; interact.js (126 KB) y Quill (260 KB) dejan de formar parte de Basic. ### M-001 · Bootstrap ya no se incluye en `astrol-basic.min.css` — [Assets][Visual] · Severidad: Visual `astrol-basic.css` importaba `bootstrap.min.css` (159 KB). Se elimina y se sustituye por un *reboot* mínimo propio (box-sizing, márgenes de títulos/párrafos, herencia de fuente en controles, cursor en botones…). **Detección** (clases de bootstrap en el proyecto consumidor): ```regex class="[^"]*\b(container(-fluid)?|row|col(-(sm|md|lg|xl|xxl))?(-\d+)?|btn(-[a-z]+)*|form-(control|select|check|label)[a-z-]*|input-group[a-z-]*|d-(none|flex|block|inline[a-z-]*)|justify-content-[a-z]+|align-items-[a-z]+|m[trblxy]?-[0-5]|p[trblxy]?-[0-5]|w-(25|50|75|100)|h-100|text-(center|start|end|muted)|card[a-z-]*|table[a-z-]*|alert[a-z-]*|badge|navbar[a-z-]*|g-[0-5])\b ``` **Acción:** - Si el proyecto **usa bootstrap de forma extensa**, añade bootstrap tú mismo antes de AstrolUI: ```html ``` - Si solo usa **unas pocas utilidades**, defínelas en el `app.css` del proyecto. Ejemplo usado en el documentador: ```css .w-100 { width: 100%; } ``` - Utilidades equivalentes que **sí** trae AstrolUI: `.w-1` … `.w-10` (10 %…100 %), `.fl`, `.fr`, `.tac`, `.tal`, `.tar`, `.to-upper`. **Notas para la documentación:** página *Basic components › Installation*: indicar que AstrolUI no depende de bootstrap. --- ### M-002 · interact.js sale de Basic — [Assets] · Severidad: Rompe (404 si se sigue referenciando) Basic ya no usa interact.js: arrastrar y redimensionar modales/confirm y redimensionar columnas del Grid se hace con Pointer Events nativos dentro de `Astrol.JSInterop.Base`. El fichero se movió a `Astrol.Component.Board`, que sí lo necesita. **Detección:** ```text _content/Astrol.Component.Basic/js/interact.min.js _content/Astrol.Component.Basic/js/interact.js ``` **Acción:** - Proyecto **sin** `Astrol.Component.Board` → **elimina** la etiqueta ` ``` **Notas para la documentación:** *Basic › Installation* y *Charts › Installation* ya no muestran el paso de interact.js (hecho). *Board › Example* ya muestra la nueva ruta (hecho). --- ### M-003 · Assets de Quill (RichText) se mueven a `Astrol.Component.RichText` — [Assets] · Severidad: Rompe **Detección:** ```text _content/Astrol.Component.Basic/js/astrol-rich-text _content/Astrol.Component.Basic/css/astrol-rich-text ``` **Acción:** sustituir el prefijo `_content/Astrol.Component.Basic/` por `_content/Astrol.Component.RichText/` en esas dos rutas. ```html ``` Si el proyecto **no usa** `AstrolRichText`, elimina ambas etiquetas. **Notas para la documentación:** *Rich text › Installation* ya muestra las rutas nuevas (hecho). --- ### M-004 · Fuente de iconos: solo WOFF2 y un único CSS — [Assets] · Severidad: Rompe solo si se referencian los ficheros eliminados Se conservan **todos los nombres** de iconos (`astrol-*`, 1034 iconos). Se eliminan formatos y variantes obsoletas: `fontello.eot`, `.ttf`, `.svg`, `.woff`, `fontello-codes.min.css`, `fontello-embedded.min.css`, `fontello-ie7.min.css`, `fontello-ie7-codes.min.css`. La `@font-face` usa ahora `font-display: block` (no muestra glifos falsos mientras carga). **Detección:** ```regex _content/Astrol\.Component\.Basic/fontello/(font/fontello\.(eot|ttf|svg|woff)\b|css/fontello-(codes|embedded|ie7|ie7-codes)\.min\.css) ``` **Acción:** elimina esas referencias. Los iconos ya vienen dentro de `astrol-basic.min.css` (ver M-005). Si solo quieres los iconos sin el resto de estilos, usa `_content/Astrol.Component.Basic/fontello/css/fontello.min.css`. --- ### M-005 · `astrol-basic.min.css` ahora incluye iconos y animación (sin `@import`) — [Assets] · Severidad: Ninguna (recomendado limpiar) Antes `astrol-basic.min.css` hacía `@import` de bootstrap, fontello y animation (cadena de peticiones que bloquea el render). Ahora es un único fichero que ya contiene `fontello.min.css` y `animation.min.css`. El fichero fuente sin minificar (`css/astrol-basic.css`) deja de publicarse en el paquete. **Detección:** ```text _content/Astrol.Component.Basic/fontello/css/fontello.min.css _content/Astrol.Component.Basic/fontello/css/animation.min.css _content/Astrol.Component.Basic/css/astrol-basic.css ``` **Acción:** si el proyecto ya enlaza `astrol-basic.min.css`, elimina los enlaces a `fontello.min.css` y `animation.min.css` (estarían duplicados). Cambia `astrol-basic.css` por `astrol-basic.min.css`. --- ### M-006 · Arrastrar / redimensionar nativo — [Interno][Visual] · Severidad: Ninguna `AstrolJSInterop.DragAndDropModal`, `DragAndDropConfirm`, `Resizable`, `ResizableColumn` y `RestoreTranslateByClassName` mantienen su firma. Cambios de comportamiento: - El arrastre empieza tras mover 3 px (un clic simple ya no se interpreta como arrastre). - Al soltar, el elemento se reajusta para quedar dentro de su contenedor. - Arrastrar no selecciona texto y soltar fuera del modal ya no lo cierra. - Al redimensionar un modal también se ajusta su `max-width`, así que ahora puede crecer por encima del ancho de su clase (`m-short`, `m-middle`…). - Durante la interacción el elemento recibe las clases `aui-dragging` / `aui-resizing` (útiles para estilos). --- ### M-007 · `AuxiliarIcon` compacto — [API] · Severidad: Ninguna `Astrol.Entities.Basic.Static.AuxiliarIcon.GetIconList()` y `GetOnlyClassIconArray()` devuelven exactamente los mismos datos y en el mismo orden. El código fuente pasa de 175 KB a 20 KB y la DLL de `Astrol.Entities.Basic` pesa mucho menos. Novedades: `AuxiliarIcon.Count` y `AuxiliarIcon.Prefix` (`"astrol-"`). --- ### M-008 · Dependencias entre paquetes — [Interno] · Severidad: Ninguna Las librerías de la solución se referencian ahora con `ProjectReference`; al empaquetar se convierten en dependencias NuGet con la versión exacta de cada proyecto. Un proyecto consumidor solo necesita referenciar el paquete de más alto nivel que use (p. ej. `Astrol.Component.Basic`), y recibe `Astrol.Entities.Basic` y `Astrol.JSInterop.Base` de forma transitiva. **Acción opcional:** quitar las `PackageReference` explícitas a `Astrol.Entities.Basic` / `Astrol.JSInterop.Base` si solo se añadieron por arrastre. --- ## Lote 2 — Interop bajo demanda y componentes nativos (Fase 2) Resultado: el módulo JS común baja de 18 KB a **8 KB** y solo se descarga en la primera llamada a `AstrolJSInterop`. Arrastrar/redimensionar (6 KB) y los módulos de Modal, ComboBox y RichText se descargan únicamente cuando se usa el componente. La paginación ya no hace llamadas JS para habilitar o deshabilitar sus botones, y el modal ya no cuenta elementos del DOM para calcular su `z-index`. ### M-009 · Nuevo `GetColorContrast` — [API] · Severidad: Ninguna (novedad) `Astrol.Entities.Basic.Static.Extensions.StringExtensions.GetColorContrast(this string? colorHex, string lightColor = "#ffffff", string darkColor = "#222222")` devuelve el color de texto con mayor contraste **WCAG** sobre el fondo indicado. - Acepta `#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`, con o sin `#` (el alfa se ignora). - Devuelve `null` si el color está vacío o no es válido (no lanza excepción). - No usa `System.Drawing`: seguro en Blazor WebAssembly. ```csharp "#ffd800".GetColorContrast(); // "#222222" "#c10000".GetColorContrast(); // "#ffffff" "#ffd800".GetColorContrast("#fafafa", "#000"); // "#000" ``` > Nota: al usar contraste WCAG real, algunos azules medios (p. ej. `#007bff`) devuelven el color > oscuro, cuando una fórmula de brillo simple habría devuelto blanco. **Notas para la documentación:** añadir a la página de utilidades/extensiones. --- ### M-010 · Miembros eliminados de `AstrolJSInterop` — [API] · Severidad: Rompe (no compila si se usan) Se eliminan los métodos que eran detalles internos de un componente y ahora viven en su propio módulo: | Eliminado | Sustituto | |---|---| | `CreateQuill`, `CreateQuillAsync`, `GetHTML`, `GetText`, `GetContent`, `LoadQuillContent(Async)`, `LoadQuillHTMLContent` / `LoadQuillHtmlContentAsync`, `InsertQuillText(Async)`, `InsertQuillImage(Async)`, `InsertQuillVideo(Async)`, `EnableQuillEditor(Async)` | Usar los métodos públicos del componente `AstrolRichText` | | `MountComboBoxDropdown`, `UpdateComboBoxDropdownPosition`, `UnmountComboBoxDropdown` | Ninguno (lo gestiona `AstrolComboBox` internamente) | | `EnableNavButton` | Ninguno (`AstrolPagination` renderiza el estado `disabled`) | | `SetClassBySelector` | Ninguno (la función JS nunca existió; fallaba en tiempo de ejecución) | **Detección:** ```regex \.(CreateQuill|GetHTML|GetText|GetContent|LoadQuill\w*|InsertQuill\w*|EnableQuillEditor\w*|MountComboBoxDropdown|UpdateComboBoxDropdownPosition|UnmountComboBoxDropdown|EnableNavButton|SetClassBySelector)\s*\( ``` Solo aplica si la instancia es un `AstrolJSInterop` (suele llamarse `jsI`). **Se mantienen** con la misma firma: `Notification`, `CopyToClipboard` (ahora usa la Clipboard API con fallback), `IdleTimer`, `SaveAs`, `GetPasteFunctionReference`, `FocusElement`, `CountElementExistToHTML`, `GetWidthBySelector`, `GetHeightBySelector`, `Prompt`, `SetInputValue`, `ParentComboBox` (ya no acumula listeners), `RemoveAllOcurrencesSelectorID`, `AddIdByClase`, `DragAndDropModal`, `DragAndDropConfirm`, `Resizable`, `ResizableColumn`, `RestoreTranslateByClassName`. Las cinco últimas cargan el módulo `astrolInteractions` bajo demanda. --- ### M-011 · `Astrol.Component.RichText` ya no depende de `Astrol.JSInterop.Base` — [Interno] · Severidad: Ninguna `AstrolRichText` usa su propio módulo (`BaseRichText.razor.js`) a través de `IJSRuntime`. Un proyecto que **solo** use RichText ya no necesita registrar `AstrolJSInterop`. Las rutas de los assets de Quill no cambian respecto a M-003. --- ### M-012 · Modal y Confirm usan `` nativo — [Visual][Assets CSS] · Severidad: Visual / Rompe solo con CSS personalizado `BaseModal` (y por tanto `AstrolModal`, `AstrolConfirm` y `AstrolUploadFile`) se abre con `dialog.showModal()`. Mismos parámetros y mismo aspecto. Mejoras: - Capa superior nativa: siempre por encima de todo, sin `z-index` y sin interop para contar modales. - El resto de la página queda inerte (no se puede tabular ni hacer clic detrás del modal). - Esc cierra solo el modal superior (si `ClosedInteractive = true`). - Al cerrar, el foco vuelve al elemento que abrió el modal. - `AstrolButton Autofocus="true"` dentro de un modal recibe el foco al abrirse (p. ej. "Aceptar" en Confirm, de modo que Enter confirma). - Accesible: el título del modal es el nombre (`aria-labelledby`) del diálogo. **Cambios en el DOM / CSS** (solo afectan a quien personalizó estilos): | Antes | Ahora | |---|---| | `