feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
<script lang="ts">
|
|
|
|
|
import './button.css';
|
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
/**
|
|
|
|
|
* Eidos `<Button>` — visual wrapper over Soma's headless button.
|
|
|
|
|
*
|
|
|
|
|
* Soma owns the click flow, `data-state`, `aria-busy`, `aria-disabled`
|
refactor(button): align with book cap. 22 — contact.activate, intent visual-only (Plan B commit 2)
Button morfo declared `commit-action` with verb `action` (not in canon)
and full intent range. Per «Diseñando lo que ocurre»:
- Cap 22 §10: "Botón: contact.press" — the press is reception of the
gesture, not the commit.
- Cap 22 §11: "el intent fuerte no debería vivir en el contacto, sino
en la señal o consecuencia posterior. La interfaz puede anticipar el
peso mediante forma, color o señal previa."
- Cap 22 §8: "Error típico: contact.press + fulfill — Esto hace que el
sistema diga 'ya terminó' cuando solo ha empezado."
Strict book reading applied:
- Morfo event renamed: `commit-action` → `contact-activate`
(family: `contact`, verb: `activate`, no intent binding)
- Soma provider trigger string + comments updated
- `intent` prop survives as VISUAL signal only — drives `data-color`
and chip variant (anticipatory weight via form/color per cap. 22 §11)
- README + types JSDoc updated with the book's prescription and the
composition pattern: perceptual richness emerges from the OTHER
morfos in the flow (Dialog warning, Item being deleted, etc.) firing
their own commit/signal events at the actual moment of the
consequence
- `EVENT_NAME_ALLOWLIST` in morfo-vocabulary-check.ts emptied — no
exceptions to the canon needed
No `declaresOutcome` props, no imperative sema escape hatches: the
morfo remains the single source of truth for events. If a flow loses
perceptual differentiation, the answer is to model the missing morfo,
not to overload the Button.
Verification:
- npm run morfo:vocabulary → EXIT 0 (zero allowlisted)
- npx vitest src/uix/sema src/uix/morfo → 194/194 pass
- npm run check → no new errors from these changes
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
* and the `contact-activate` perceptual event (book cap. 22 §10).
|
|
|
|
|
* Eidos adds the visual API on top — `variant`, `size`, `rounded`,
|
|
|
|
|
* `block`, `iconOnly`, the `icon` / `endIcon` snippet slots, and the
|
|
|
|
|
* loading Spinner — and wires those to the `data-*` selectors that
|
|
|
|
|
* `button.css` reacts to.
|
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
*/
|
|
|
|
|
import { ActiveEidos } from '$uix/eidos';
|
|
|
|
|
import * as Button from '$soma/components/button';
|
|
|
|
|
import ButtonSpinner from './button-spinner.svelte';
|
|
|
|
|
import type { ButtonProps } from './types';
|
|
|
|
|
|
|
|
|
|
let {
|
|
|
|
|
variant = 'solid',
|
|
|
|
|
size = 'md',
|
|
|
|
|
rounded,
|
|
|
|
|
shape,
|
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
block = false,
|
|
|
|
|
iconOnly = false,
|
|
|
|
|
loading = false,
|
|
|
|
|
icon,
|
|
|
|
|
endIcon,
|
|
|
|
|
spinner,
|
|
|
|
|
spinnerPlacement = 'start',
|
|
|
|
|
loadingText,
|
|
|
|
|
children: bodyContent,
|
|
|
|
|
...headlessProps
|
|
|
|
|
}: ButtonProps = $props();
|
|
|
|
|
|
|
|
|
|
const eidos = ActiveEidos.require();
|
|
|
|
|
const resolvedSize = $derived(eidos.resolve(size, 'md'));
|
|
|
|
|
const resolvedRounded = $derived(eidos.resolve(rounded));
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<Button.Provider
|
|
|
|
|
{...headlessProps}
|
|
|
|
|
{loading}
|
|
|
|
|
{loadingText}
|
|
|
|
|
{spinnerPlacement}
|
|
|
|
|
data-variant={variant}
|
|
|
|
|
data-size={resolvedSize}
|
|
|
|
|
data-rounded={resolvedRounded ?? undefined}
|
|
|
|
|
data-shape={shape}
|
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
data-block={block ? '' : undefined}
|
|
|
|
|
data-icon-only={iconOnly ? '' : undefined}
|
|
|
|
|
data-has-icon={icon || (loading && spinnerPlacement === 'start') ? '' : undefined}
|
|
|
|
|
data-spinner-placement={spinnerPlacement}
|
|
|
|
|
>
|
|
|
|
|
{#snippet children(snippetProps)}
|
|
|
|
|
<!-- Start slot: spinner (when loading) wins over icon at start placement. -->
|
|
|
|
|
{#if loading && spinnerPlacement === 'start'}
|
|
|
|
|
{#if spinner}<ButtonSpinner>{@render spinner()}</ButtonSpinner>{:else}<ButtonSpinner />{/if}
|
|
|
|
|
{:else if icon}
|
|
|
|
|
<span class="eidos-button-icon" data-button-icon="start" aria-hidden="true">
|
|
|
|
|
{@render icon(snippetProps)}
|
|
|
|
|
</span>
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
|
|
|
<!--
|
|
|
|
|
* Body wrapper holds the text label. When `iconOnly` is on, the
|
|
|
|
|
* recipe makes it visually-hidden but keeps it in the accessibility
|
|
|
|
|
* tree so screen readers still announce the label. When loading
|
|
|
|
|
* with `loadingText`, the original children remain in DOM (sr-only)
|
|
|
|
|
* and the loadingText takes the visual slot.
|
|
|
|
|
-->
|
|
|
|
|
<span class="eidos-button-body">
|
|
|
|
|
{#if loading && loadingText}
|
|
|
|
|
<span class="eidos-button-loading-text">{loadingText}</span>
|
|
|
|
|
<span class="eidos-button-sr-only">{@render bodyContent?.(snippetProps)}</span>
|
|
|
|
|
{:else}
|
|
|
|
|
{@render bodyContent?.(snippetProps)}
|
|
|
|
|
{/if}
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
|
|
<!-- End slot: spinner (when loading) wins over endIcon at end placement. -->
|
|
|
|
|
{#if loading && spinnerPlacement === 'end'}
|
|
|
|
|
{#if spinner}<ButtonSpinner>{@render spinner()}</ButtonSpinner>{:else}<ButtonSpinner />{/if}
|
|
|
|
|
{:else if endIcon}
|
|
|
|
|
<span class="eidos-button-icon" data-button-icon="end" aria-hidden="true">
|
|
|
|
|
{@render endIcon(snippetProps)}
|
|
|
|
|
</span>
|
|
|
|
|
{/if}
|
|
|
|
|
{/snippet}
|
|
|
|
|
</Button.Provider>
|