// Opens the product detail as a morph out of the card that was tapped, in // place of the old full-height bottom Drawer (which slid up from off-screen and // then jumped once the detail fetch landed). One overlay for the whole app — // components/product/ProductMorph.vue, mounted once in App.vue — instead of a // Drawer per card: ProductCard used to carry its own, so every catalogue grid // rendered one per product. // // Callers only say WHICH product. The card it came from is found from the tap // itself: every card root is marked `data-product-origin`, and the last // pointerdown is remembered here, so the tap's own target leads back to its // card without each emit chain (ProductPanel → ProductCarousel → HomeView) having // to thread an element through. A caller that does hold the element can pass // it; with neither (keyboard activation), the overlay falls back to a plain // rise-and-fade instead of a morph. import { shallowRef } from 'vue' import type { ProductSummary } from '../api/client' export interface ProductMorphRequest { product: ProductSummary origin: HTMLElement | null } export const productMorph = shallowRef(null) let lastPointerTarget: Element | null = null if (typeof document !== 'undefined') { document.addEventListener( 'pointerdown', (e) => { lastPointerTarget = e.target instanceof Element ? e.target : null }, { capture: true, passive: true }, ) } export function openProduct(product: ProductSummary, origin?: HTMLElement | null) { const fromTap = lastPointerTarget?.closest('[data-product-origin]') ?? null productMorph.value = { product, origin: origin ?? fromTap } } export function closeProduct() { productMorph.value = null }