diff --git a/web/routes/blocks/pricing/PricingSite.svelte b/web/routes/blocks/pricing/PricingSite.svelte index aeb4e4ed4..04cb42202 100644 --- a/web/routes/blocks/pricing/PricingSite.svelte +++ b/web/routes/blocks/pricing/PricingSite.svelte @@ -13,6 +13,37 @@ import { Badge } from '$uix/eidos/components/badge'; import { Button } from '$uix/eidos/components/button'; import { Link } from '$uix/eidos/components/link'; + import { tick } from 'svelte'; + import { getActiveUix } from '$active-uix'; + + const uix = getActiveUix(); + + // The full semantic arc of choosing a plan. Pressing already emits + // `contact-activate` (the Button's own morfo event, for free by composition); + // what NO reference can express is the CONSEQUENCE — so the app emits the + // `commit.select` that says the choice was fixed. `affirm`, per CANON §2: an + // active choice is affirmative. This is app-land on purpose: a block has no + // morfo and cannot invent the outcome of the app's own action. + let chosen = $state(null); + + async function choose(plan: string, event: MouseEvent) { + const target = event.currentTarget as HTMLElement; + chosen = plan; + + // The commit is the CONSEQUENCE, not the press: pressing already emitted + // `contact-activate` (the Button's own morfo event). We wait for the + // outcome to land and only then say what was fixed — which is also what + // keeps the two signals from colliding on the same element (emitting both + // synchronously, the contact projection overwrites the commit's). + await tick(); + void uix.events?.emit({ + target, + name: 'commit-select', + family: 'commit', + intent: 'affirm', + message: plan + }); + } type Plan = { name: string; @@ -103,8 +134,9 @@ block variant={plan.featured ? 'solid' : 'surface'} intent={plan.featured ? 'fulfill' : 'affirm'} + onclick={(event) => choose(plan.name, event)} > - {plan.cta} + {chosen === plan.name ? 'Plan elegido' : plan.cta}