From 189932d93978fd49b989b1b07adc0d6798a1526f Mon Sep 17 00:00:00 2001 From: dev Date: Thu, 18 Jun 2026 02:32:10 +0200 Subject: [PATCH] feat(eidos): IconButton primitive + Lote 0 iconOnly->IconButton cascade Lote 0 of the component-coherence audit (FASE 2): - New IconButton primitive (composes Button: inherits variant/size/intent/ color/rounded/shape/loading + Button's morfo + sema, no new morfo; aria-label required; glyph as children). New svg/ glyphs: SvgX, SvgPlus, SvgMinus. - Button: rounded='full' 9999px -> var(--radius-full) (theme-driven radius, value-identical). - Migrate icon-only Button consumers to IconButton: carousel prev/next (pilot), tree-grid expand, table row-detail, search-field clear, combobox clear. Pattern: glyph->children, label->aria-label, drop iconOnly. - carousel.css: fix arrow positioning (specificity vs Button's base position:relative, exposed by the IconButton import-order flip) + the press-squeeze jump (centre via the translate property so the contact press transform:scale composes instead of replacing the centring). - Doc: COMPONENT_COHERENCE_AUDIT - indicator-chevron vs discrete IconButton distinction (tree-view/accordion stay out); 5F width closed (full-width); Lote 0 hand-off + pending select-family faults. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/uix/eidos/COMPONENT_COHERENCE_AUDIT.md | 88 +++++++++++++++++-- src/uix/eidos/components/button/button.css | 2 +- .../carousel/carousel-next-trigger.svelte | 26 ++---- .../carousel/carousel-prev-trigger.svelte | 36 +++----- .../eidos/components/carousel/carousel.css | 51 +++++------ src/uix/eidos/components/carousel/types.ts | 9 +- .../combobox/combobox-clear-button.svelte | 34 +++---- .../eidos/components/icon-button/README.md | 48 ++++++++++ .../components/icon-button/icon-button.svelte | 23 +++++ src/uix/eidos/components/icon-button/index.ts | 18 ++++ src/uix/eidos/components/icon-button/types.ts | 25 ++++++ .../search-field-clear-trigger.svelte | 33 +++---- src/uix/eidos/components/svg/index.ts | 3 + src/uix/eidos/components/svg/svg-minus.svelte | 30 +++++++ src/uix/eidos/components/svg/svg-plus.svelte | 32 +++++++ src/uix/eidos/components/svg/svg-x.svelte | 32 +++++++ .../table/table-row-detail-trigger.svelte | 34 ++----- src/uix/eidos/components/table/types.ts | 9 +- .../tree-grid/tree-grid-expand-trigger.svelte | 31 ++----- src/uix/eidos/components/tree-grid/types.ts | 9 +- 20 files changed, 398 insertions(+), 175 deletions(-) create mode 100644 src/uix/eidos/components/icon-button/README.md create mode 100644 src/uix/eidos/components/icon-button/icon-button.svelte create mode 100644 src/uix/eidos/components/icon-button/index.ts create mode 100644 src/uix/eidos/components/icon-button/types.ts create mode 100644 src/uix/eidos/components/svg/svg-minus.svelte create mode 100644 src/uix/eidos/components/svg/svg-plus.svelte create mode 100644 src/uix/eidos/components/svg/svg-x.svelte diff --git a/src/uix/eidos/COMPONENT_COHERENCE_AUDIT.md b/src/uix/eidos/COMPONENT_COHERENCE_AUDIT.md index 23e1345b2..419a68c78 100644 --- a/src/uix/eidos/COMPONENT_COHERENCE_AUDIT.md +++ b/src/uix/eidos/COMPONENT_COHERENCE_AUDIT.md @@ -151,6 +151,21 @@ tienen chrome propio coherente, se quedan bespoke-tokenizados. | radio-cards / rating-group | card/item | commit | bespoke (tokenizado) | | tree-view / tree-grid | node | commit/emerge | bespoke (tokenizado) | +> **Indicador vs botón discreto (chevron de expand) — verificado 2026-06-18.** El +> chevron de expand es **IconButton SOLO cuando es un botón DISCRETO** (`tree-grid` +> `expand-trigger`: un botoncito aparte en la fila, que compone ` + + {#if customIcon}{@render customIcon()}{:else}{/if} + {/if} {/snippet} diff --git a/src/uix/eidos/components/carousel/carousel-prev-trigger.svelte b/src/uix/eidos/components/carousel/carousel-prev-trigger.svelte index ad321858f..6d460a9e6 100644 --- a/src/uix/eidos/components/carousel/carousel-prev-trigger.svelte +++ b/src/uix/eidos/components/carousel/carousel-prev-trigger.svelte @@ -1,29 +1,26 @@ -{#snippet defaultIcon()} - -{/snippet} - {#snippet child({ props })} {#if outerChild} {@render outerChild({ props })} {:else} - + + {#if customIcon}{@render customIcon()}{:else}{/if} + {/if} {/snippet} diff --git a/src/uix/eidos/components/carousel/carousel.css b/src/uix/eidos/components/carousel/carousel.css index 1998d654b..e823bdcb5 100644 --- a/src/uix/eidos/components/carousel/carousel.css +++ b/src/uix/eidos/components/carousel/carousel.css @@ -231,19 +231,28 @@ flex: 0 0 100%; } -/* ── Triggers (Button consumer pattern) ─ +/* ── Triggers (IconButton consumer pattern) ─ * - * The triggers are rendered as + {/if} + {/if} {/snippet} diff --git a/src/uix/eidos/components/icon-button/README.md b/src/uix/eidos/components/icon-button/README.md new file mode 100644 index 000000000..df197b934 --- /dev/null +++ b/src/uix/eidos/components/icon-button/README.md @@ -0,0 +1,48 @@ +# IconButton + +The canonical **icon-only button**. A first-class public primitive (as in +MUI / Radix / Chakra), not an ad-hoc ` + {/if} + {/if} {/snippet} diff --git a/src/uix/eidos/components/svg/index.ts b/src/uix/eidos/components/svg/index.ts index 4a9fcce3a..62f3edb90 100644 --- a/src/uix/eidos/components/svg/index.ts +++ b/src/uix/eidos/components/svg/index.ts @@ -17,4 +17,7 @@ export { default as SvgChevron } from './svg-chevron.svelte'; export { default as SvgCheck } from './svg-check.svelte'; export { default as SvgDash } from './svg-dash.svelte'; export { default as SvgDot } from './svg-dot.svelte'; +export { default as SvgX } from './svg-x.svelte'; +export { default as SvgPlus } from './svg-plus.svelte'; +export { default as SvgMinus } from './svg-minus.svelte'; export type { SvgPrimitiveProps, SvgChevronDirection } from './types'; diff --git a/src/uix/eidos/components/svg/svg-minus.svelte b/src/uix/eidos/components/svg/svg-minus.svelte new file mode 100644 index 000000000..ab7aa0ed8 --- /dev/null +++ b/src/uix/eidos/components/svg/svg-minus.svelte @@ -0,0 +1,30 @@ + + + diff --git a/src/uix/eidos/components/svg/svg-plus.svelte b/src/uix/eidos/components/svg/svg-plus.svelte new file mode 100644 index 000000000..f4cbabacd --- /dev/null +++ b/src/uix/eidos/components/svg/svg-plus.svelte @@ -0,0 +1,32 @@ + + + diff --git a/src/uix/eidos/components/svg/svg-x.svelte b/src/uix/eidos/components/svg/svg-x.svelte new file mode 100644 index 000000000..020f8facc --- /dev/null +++ b/src/uix/eidos/components/svg/svg-x.svelte @@ -0,0 +1,32 @@ + + + diff --git a/src/uix/eidos/components/table/table-row-detail-trigger.svelte b/src/uix/eidos/components/table/table-row-detail-trigger.svelte index 2233f26b7..b3c52640c 100644 --- a/src/uix/eidos/components/table/table-row-detail-trigger.svelte +++ b/src/uix/eidos/components/table/table-row-detail-trigger.svelte @@ -1,29 +1,25 @@ -{#snippet defaultIcon()} - -{/snippet} - {#snippet child({ props })} {#if outerChild} {@render outerChild({ props })} {:else} - + + {#if customIcon}{@render customIcon()}{:else}{/if} + {/if} {/snippet} diff --git a/src/uix/eidos/components/tree-grid/types.ts b/src/uix/eidos/components/tree-grid/types.ts index 4482109c2..2f08a30f8 100644 --- a/src/uix/eidos/components/tree-grid/types.ts +++ b/src/uix/eidos/components/tree-grid/types.ts @@ -1,3 +1,4 @@ +import type { Snippet } from 'svelte'; import type { ColorRole, ControlVariant, @@ -103,10 +104,10 @@ export type TreeGridExpandTriggerProps = ExpandTriggerProps & { color?: EidosButtonProps['color']; /** Evaluative intent. */ intent?: EidosButtonProps['intent']; - /** Icon-only mode. @default true */ - iconOnly?: boolean; - /** Leading icon snippet (replaces default chevron). */ - icon?: EidosButtonProps['icon']; + /** Accessible name for the icon-only trigger. @default 'Toggle row' */ + 'aria-label'?: string; + /** Override the default chevron glyph. */ + icon?: Snippet; }; export type {