diff --git a/src/uix/eidos/COMPONENT_COHERENCE_AUDIT.md b/src/uix/eidos/COMPONENT_COHERENCE_AUDIT.md index eb20e1e19..f75ca9b8d 100644 --- a/src/uix/eidos/COMPONENT_COHERENCE_AUDIT.md +++ b/src/uix/eidos/COMPONENT_COHERENCE_AUDIT.md @@ -709,10 +709,22 @@ time-picker + morfo: **65/65**. Navegador: langs ES + transición de los 4 input ### Pendiente (orden sugerido) -1. **DIM 1 composición — Lote A** (Button-consumer): closes dialog/drawer/popover/ - banner/toast → `IconButton`+`SvgX`; calendar/range prev/next → `IconButton`+ - `SvgChevron`; **code-block copy → componer ``** (cierra también su - hardcode de langs). Borrar el chrome `--*-control-*`/`--*-close-*` redundante. +1. **DIM 1 composición — Lote A** (Button-consumer) — **EN CURSO**: + - ✅ **popover-close** + **banner-close** → `IconButton`+`SvgX` (slices completos: + wrapper + types + borrado de chrome CSS + eliminación de tokens recipe huérfanos + + regen; verificados en navegador, consistentes con dialog/drawer-close). + - ✅ **drawer-close**: limpiados los 15 tokens recipe huérfanos que la migración + previa dejó + arreglado el manifiesto de `component-visual-attrs` (drawer + + popover componen IconButton → no estampan `data-icon-only`, sin entrada). Suite + eidos 9→8 fallas (las 8 restantes son heredadas: spin-field, palabras, icon). + - **Gotcha confirmado** ([[iconbutton-lote0]]): migrar a IconButton voltea el orden + de carga CSS → `[data-button]{margin:0}` (igual especificidad, carga después) pisa + el positioning del consumidor. Fix: subir especificidad con ancestro + (`[data-banner] [data-banner-close]`). + - ⏳ **Pendiente del Lote A**: **toast-close** (19 refs CSS — chrome más complejo), + **float-panel-close** (chrome COMPARTIDO con `action`+`stage-trigger` → migrar los + tres o extraer con cuidado), **calendar/range prev/next** → `IconButton`+`SvgChevron` + (+ borrar `--calendar-control-*`), **code-block copy** → componer ``. 2. **DIM 1 — Lote B** (estructural): 6 `` (calendar month/year, range-calendar month/year, color-field/color-picker format). 3. **Barrido de langs — cola** (deferidos arriba): avatar-group conteo, date-range-picker diff --git a/src/uix/eidos/component-visual-attrs.test.ts b/src/uix/eidos/component-visual-attrs.test.ts index 7ad14a16d..66b690fee 100644 --- a/src/uix/eidos/component-visual-attrs.test.ts +++ b/src/uix/eidos/component-visual-attrs.test.ts @@ -31,11 +31,11 @@ const VISUAL_ATTRS = [ ], ['checkbox/checkbox.svelte', ['data-size', 'data-variant', 'data-color']], ['checkbox/checkbox-group.svelte', ['data-columns']], - // The close composes , which owns the icon-only layout — the - // wrapper only wires the dialog-specific floating `data-position`. + // The close composes , which owns the icon-only layout. dialog + // adds the floating `data-position`; drawer + popover stamp no wrapper-specific + // visual attr (they fully delegate to IconButton) so they have no entry. ['dialog/dialog-close.svelte', ['data-position']], ['dialog/dialog-content.svelte', ['data-size', 'data-position', 'data-sheet']], - ['drawer/drawer-close.svelte', ['data-icon-only']], ['drawer/drawer-content.svelte', ['data-size']], ['editable/editable.svelte', ['data-size', 'data-variant', 'data-color']], ['field/field.svelte', ['data-size', 'data-variant', 'data-orientation', 'data-color']], @@ -44,7 +44,6 @@ const VISUAL_ATTRS = [ ['meter/meter.svelte', ['data-size', 'data-shape']], ['number-field/number-field.svelte', ['data-size', 'data-variant', 'data-color']], ['pagination/pagination.svelte', ['data-size']], - ['popover/popover-close.svelte', ['data-icon-only']], ['popover/popover-content.svelte', ['data-size']], ['progress/progress.svelte', ['data-size', 'data-shape']], ['radio-group/radio-group.svelte', ['data-size', 'data-variant', 'data-color', 'data-columns']], diff --git a/src/uix/eidos/components/banner/banner-close.svelte b/src/uix/eidos/components/banner/banner-close.svelte index 0b39919e0..ec0507196 100644 --- a/src/uix/eidos/components/banner/banner-close.svelte +++ b/src/uix/eidos/components/banner/banner-close.svelte @@ -1,50 +1,38 @@ - + {#if children}{@render children()}{:else}{/if} + diff --git a/src/uix/eidos/components/banner/banner.css b/src/uix/eidos/components/banner/banner.css index a6123fe7e..a805aed8b 100644 --- a/src/uix/eidos/components/banner/banner.css +++ b/src/uix/eidos/components/banner/banner.css @@ -141,30 +141,12 @@ /* ── Close button (eidos-only part) ────────────────────────────────── */ -[data-banner-close] { - display: inline-flex; - align-items: center; - justify-content: center; +/* Positioning only — `Banner.Close` composes the canonical ``, so + its chrome (size, bg, border, hover, focus ring) comes from button.css. The + `margin-inline-start: auto` pushes the dismiss to the end of the banner row. + Scoped under `[data-banner]` (0,2,0) so it out-ranks `[data-button]`'s own + `margin` (0,1,0) — composing IconButton flips the CSS load order, so an + equal-specificity bare selector would lose the tie. */ +[data-banner] [data-banner-close] { margin-inline-start: auto; - inline-size: var(--space-6); - block-size: var(--space-6); - padding: 0; - background: transparent; - color: inherit; - border: 0; - border-radius: var(--radius-sm, var(--space-1)); - cursor: pointer; - opacity: var(--opacity-subtle); - transition: opacity var(--duration-fast) ease, background-color var(--duration-fast) ease; -} - -[data-banner-close]:hover { - opacity: 1; - background: color-mix(in srgb, currentColor 12%, transparent); -} - -[data-banner-close]:focus-visible { - outline: var(--border-width-medium) solid currentColor; - outline-offset: 1px; - opacity: 1; } diff --git a/src/uix/eidos/components/banner/types.ts b/src/uix/eidos/components/banner/types.ts index 5d6b8250d..97b93bbf1 100644 --- a/src/uix/eidos/components/banner/types.ts +++ b/src/uix/eidos/components/banner/types.ts @@ -2,6 +2,7 @@ import type { Snippet } from 'svelte'; import type { HTMLAttributes } from 'svelte/elements'; import type { ColorRole, ResponsiveProp, Size } from '$uix/eidos/lib/types'; import type { ChipVariant } from '$uix/eidos/lib/types'; +import type { IconButtonProps } from '$uix/eidos/components/icon-button'; /** * Banner intent vocabulary. Mirrors the canonical UIX `ColorRole` set @@ -49,8 +50,15 @@ export type BannerProps = Omit, 'children'> & { children?: Snippet; }; -export type BannerCloseProps = Omit, 'children'> & { - /** Accessible label for the dismiss button. @default 'Dismiss' */ +/** + * `Banner.Close` composes the canonical ``, so it inherits its + * full prop surface (variant / size / color / onclick / disabled / …). It only + * relaxes the two IconButton requirements: `aria-label` (defaults to a + * localized "Dismiss") and `children` (the glyph, defaults to ✕). + */ +export type BannerCloseProps = Omit & { + /** Accessible label for the dismiss button. @default localized 'Dismiss' */ 'aria-label'?: string; + /** Glyph override (defaults to the ✕). */ children?: Snippet; }; diff --git a/src/uix/eidos/components/popover/popover-close.svelte b/src/uix/eidos/components/popover/popover-close.svelte index e60057a36..d252ce383 100644 --- a/src/uix/eidos/components/popover/popover-close.svelte +++ b/src/uix/eidos/components/popover/popover-close.svelte @@ -1,31 +1,50 @@ - - {#if children} - {@render children()} - {:else} - - {/if} + + {#snippet child({ props })} + {#if outerChild} + {@render outerChild({ props })} + {:else if children} + + {:else} + + + + {/if} + {/snippet} diff --git a/src/uix/eidos/components/popover/popover.css b/src/uix/eidos/components/popover/popover.css index cfc5dad6d..aad143089 100644 --- a/src/uix/eidos/components/popover/popover.css +++ b/src/uix/eidos/components/popover/popover.css @@ -224,45 +224,9 @@ } /* ── Close button ────────────────────────────────────────────────────── - * Default sizing is auto-fit (text labels like "Close" or "Dismiss" fit - * naturally). For icon-only close buttons (× glyph), the consumer sets - * `data-icon-only` on `` to switch to a fixed square. */ -[data-popover-close] { - display: inline-flex; - align-items: center; - justify-content: center; - min-block-size: var(--popover-close-size); - padding-inline: var(--space-3); - border: var(--popover-close-border-width) solid var(--popover-close-border); - border-radius: var(--popover-close-radius); - background: var(--popover-close-bg); - color: var(--popover-close-color); - box-shadow: none; - font: inherit; - font-size: var(--popover-close-font-size); - cursor: pointer; - transition: - background var(--popover-transition-duration) var(--popover-transition-ease), - border-color var(--popover-transition-duration) var(--popover-transition-ease), - color var(--popover-transition-duration) var(--popover-transition-ease), - box-shadow var(--popover-transition-duration) var(--popover-transition-ease); -} - -[data-popover-close][data-icon-only] { - inline-size: var(--popover-close-size); - block-size: var(--popover-close-size); - padding: 0; -} - -[data-popover-close]:hover { - background: var(--popover-close-bg-hover); - border-color: var(--popover-close-border-hover); -} - -[data-popover-close]:focus-visible { - outline: none; - box-shadow: var(--focus-ring); -} + * `Popover.Close` composes the canonical `` / `