DIM 1 composition (component-coherence audit), close family:
- popover-close + banner-close now compose the canonical <IconButton>/<Button>
(via soma child snippet for popover; direct for the eidos-only banner) instead
of bespoke chrome. They inherit Button's variant/size/color/focus-ring; the
aria-label routes through langs ("Cerrar" / "Descartar"). Consistent with the
already-migrated dialog/drawer closes (solid/primary default; consumer overrides
for subtle).
- Removed the redundant [data-popover-close] / [data-banner-close] chrome from CSS
and the now-orphaned --popover-close-* / --popover-transition-* recipe tokens;
regenerated base.css. banner keeps only `margin-inline-start: auto` for end
placement, scoped under [data-banner] so it out-ranks [data-button] (composing
IconButton flips CSS load order — the equal-specificity bare selector loses).
- Cleaned the 15 orphaned --drawer-close-* recipe tokens the earlier drawer-close
migration left behind, and fixed the component-visual-attrs manifest: drawer +
popover closes delegate icon-only to IconButton, so they stamp no wrapper attr.
eidos suite 9->8 failures (the 8 remaining are inherited: spin-field + palabras +
icon, outside this work). svelte-check clean for all touched files. Verified in
browser. Excludes words/palabras/chronos.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
active-uix
parent
ebc742e73b
commit
0a43225ec2
@ -1,50 +1,38 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
/**
|
/**
|
||||||
* Eidos `<Banner.Close>` — visually-styled dismiss button. Pure
|
* Eidos `<Banner.Close>` — the banner dismiss control. Composes the canonical
|
||||||
* eidos-only part: meets the four rules in
|
* `<IconButton>` (eidos-only part — Banner has no soma close; the consumer
|
||||||
* `eidos/components/README.md` (no behavior, no aria contract, no
|
* wires `onclick` to their own visibility state). Inherits Button's chrome,
|
||||||
* event-target role, no keyboard). The consumer wires `onclick` to
|
* focus ring and disabled treatment; only the positioning
|
||||||
* their own visibility state — Banner does not own the dismissal.
|
* (`margin-inline-start: auto`) stays in `banner.css`. Default `variant='ghost'
|
||||||
*
|
* color='neutral'` — a subtle dismiss. The glyph defaults to ✕.
|
||||||
* Defaults to a localized "Dismiss" `aria-label` (via langs) so consumers
|
|
||||||
* don't have to remember, but the consumer can override.
|
|
||||||
*/
|
*/
|
||||||
import { ActiveEidos } from '$uix/eidos';
|
import { ActiveEidos } from '$uix/eidos';
|
||||||
|
import { IconButton } from '$uix/eidos/components/icon-button';
|
||||||
|
import { SvgX } from '$uix/eidos/components/svg';
|
||||||
import type { BannerCloseProps } from './types';
|
import type { BannerCloseProps } from './types';
|
||||||
|
|
||||||
let {
|
let {
|
||||||
'aria-label': ariaLabel,
|
'aria-label': ariaLabel,
|
||||||
class: className,
|
variant = 'ghost',
|
||||||
|
size,
|
||||||
|
color = 'neutral',
|
||||||
children,
|
children,
|
||||||
...restProps
|
...restProps
|
||||||
}: BannerCloseProps = $props();
|
}: BannerCloseProps = $props();
|
||||||
|
|
||||||
const eidos = ActiveEidos.require();
|
const eidos = ActiveEidos.require();
|
||||||
// Accessible name routes through langs — explicit prop wins, else the
|
// Accessible name routes through langs — explicit prop wins, else localized.
|
||||||
// localized default. No hardcoded English.
|
|
||||||
const resolvedLabel = $derived(ariaLabel ?? eidos.langs.ts('#?common.buttons.dismiss|Dismiss'));
|
const resolvedLabel = $derived(ariaLabel ?? eidos.langs.ts('#?common.buttons.dismiss|Dismiss'));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<button
|
<IconButton
|
||||||
type="button"
|
|
||||||
{...restProps}
|
{...restProps}
|
||||||
|
{variant}
|
||||||
|
size={size ?? 'sm'}
|
||||||
|
{color}
|
||||||
aria-label={resolvedLabel}
|
aria-label={resolvedLabel}
|
||||||
class={className}
|
|
||||||
data-banner-close=""
|
data-banner-close=""
|
||||||
>
|
>
|
||||||
{#if children}{@render children()}{:else}<svg
|
{#if children}{@render children()}{:else}<SvgX />{/if}
|
||||||
viewBox="0 0 16 16"
|
</IconButton>
|
||||||
width="14"
|
|
||||||
height="14"
|
|
||||||
aria-hidden="true"
|
|
||||||
focusable="false"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M3 3l10 10M13 3L3 13"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="1.5"
|
|
||||||
stroke-linecap="round"
|
|
||||||
/>
|
|
||||||
</svg>{/if}
|
|
||||||
</button>
|
|
||||||
|
|||||||
@ -1,31 +1,50 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
/**
|
/**
|
||||||
* Eidos `Popover.Close` — passes through to headless. Optional auto-X
|
* Eidos `Popover.Close` — composes the canonical button primitives via soma's
|
||||||
* icon when no children are provided (matches the air baseline +
|
* `child` snippet (no bespoke close chrome — it inherits Button's variant /
|
||||||
* Dialog/Drawer pattern). The recipe styles a square button with
|
* focus-ring / disabled):
|
||||||
* focus ring.
|
*
|
||||||
|
* - no text children → icon close: an `<IconButton>` with the ✕ glyph and a
|
||||||
|
* localized "Close" `aria-label`.
|
||||||
|
* - text children → text close: a `<Button>` with the label inline.
|
||||||
|
*
|
||||||
|
* A `child` snippet bypasses both primitives.
|
||||||
*/
|
*/
|
||||||
|
import { ActiveEidos } from '$uix/eidos';
|
||||||
import * as Popover from '$soma/components/popover';
|
import * as Popover from '$soma/components/popover';
|
||||||
|
import { Button } from '$uix/eidos/components/button';
|
||||||
|
import { IconButton } from '$uix/eidos/components/icon-button';
|
||||||
|
import { SvgX } from '$uix/eidos/components/svg';
|
||||||
import type { PopoverCloseProps } from './types';
|
import type { PopoverCloseProps } from './types';
|
||||||
|
|
||||||
let { children, ...rest }: PopoverCloseProps = $props();
|
let {
|
||||||
|
variant,
|
||||||
|
size,
|
||||||
|
color,
|
||||||
|
'aria-label': ariaLabel,
|
||||||
|
child: outerChild,
|
||||||
|
children,
|
||||||
|
...rest
|
||||||
|
}: PopoverCloseProps = $props();
|
||||||
|
|
||||||
|
const eidos = ActiveEidos.require();
|
||||||
|
const resolvedSize = $derived(size ?? 'md');
|
||||||
|
// Accessible name routes through langs — explicit prop wins, else localized.
|
||||||
|
const closeLabel = $derived(ariaLabel ?? eidos.langs.ts('#?common.buttons.close|Close'));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Popover.Close {...rest} data-icon-only={!children ? '' : undefined}>
|
<Popover.Close {...rest}>
|
||||||
{#if children}
|
{#snippet child({ props })}
|
||||||
{@render children()}
|
{#if outerChild}
|
||||||
{:else}
|
{@render outerChild({ props })}
|
||||||
<svg
|
{:else if children}
|
||||||
width="12"
|
<Button {...props} {variant} size={resolvedSize} {color} aria-label={ariaLabel ?? undefined}>
|
||||||
height="12"
|
{@render children()}
|
||||||
viewBox="0 0 14 14"
|
</Button>
|
||||||
fill="none"
|
{:else}
|
||||||
stroke="currentColor"
|
<IconButton {...props} {variant} size={resolvedSize} {color} aria-label={closeLabel}>
|
||||||
stroke-width="1.6"
|
<SvgX />
|
||||||
stroke-linecap="round"
|
</IconButton>
|
||||||
aria-hidden="true"
|
{/if}
|
||||||
>
|
{/snippet}
|
||||||
<path d="M3 3l8 8M11 3l-8 8" />
|
|
||||||
</svg>
|
|
||||||
{/if}
|
|
||||||
</Popover.Close>
|
</Popover.Close>
|
||||||
|
|||||||
Loading…
Reference in new issue