{"version":3,"file":"index.mjs","sources":["../../../src/view/index.ts"],"sourcesContent":["import { noop } from \"motion-utils\"\nimport type { GroupAnimation } from \"../animation/GroupAnimation\"\nimport { AnimationOptions, DOMKeyframesDefinition } from \"../animation/types\"\nimport { addToQueue } from \"./queue\"\nimport {\n ViewTransitionOptions,\n ViewTransitionTarget,\n ViewTransitionTargetDefinition,\n} from \"./types\"\nimport \"./types.global\"\n\n// Re-export the public view-transition types so they flow out through\n// motion-dom -> framer-motion -> motion alongside `animateView`.\nexport type * from \"./types\"\n\nexport class ViewTransitionBuilder {\n private currentSubject: ViewTransitionTargetDefinition = \"root\"\n\n targets = new Map()\n\n /**\n * Definitions that must be resolved to elements (and assigned a\n * `view-transition-name`) rather than treated as pre-named layers.\n */\n resolveDefs = new Set()\n\n /**\n * Per-subject crop override: `true` forces the crop (clip + object-fit:\n * cover + animated corner radii) on, `false` forces it off. A subject with\n * no entry uses the default - crop only a genuine morph (a layer present in\n * both snapshots), so a fade-only enter/exit isn't clipped to nothing.\n */\n cropOverride = new Map()\n\n /**\n * Subjects paired with a different new-snapshot target (the second `.add()`\n * argument), so two distinct elements share one name and morph into each\n * other - a shared-element transition.\n */\n pairs = new Map<\n ViewTransitionTargetDefinition,\n ViewTransitionTargetDefinition\n >()\n\n /**\n * A `view-transition-class` to apply to each subject's resolved elements,\n * so authors can target the generated layers from CSS by class rather than\n * the opaque generated name.\n */\n classNames = new Map()\n\n /**\n * Subjects opted out of automatic group nesting via `.group(false)`. Their\n * layer stays a flat top-level group (`view-transition-group: none`) instead\n * of nesting under its DOM-ancestor layer - so it animates independently and\n * escapes an ancestor's clip/transform (e.g. an element that lifts out of a\n * card and flies across, which nesting would clip to the card).\n */\n flatGroups = new Set()\n\n update: () => void | Promise\n\n options: ViewTransitionOptions\n\n notifyReady: (value: GroupAnimation) => void = noop\n\n notifyReject: (error: unknown) => void = noop\n\n private readyPromise = new Promise((resolve, reject) => {\n this.notifyReady = resolve\n this.notifyReject = reject\n })\n\n constructor(\n update: () => void | Promise,\n options: ViewTransitionOptions = {}\n ) {\n this.update = update\n this.options = {\n interrupt: \"wait\",\n ...options,\n }\n // Avoid an unhandled rejection when a failed transition has no\n // `.then(_, reject)` handler attached (e.g. fire-and-forget).\n this.readyPromise.catch(noop)\n addToQueue(this)\n }\n\n /**\n * Target elements resolved from a selector or Element, each assigned a\n * `view-transition-name` automatically.\n *\n * Passing a second target pairs them: the first is resolved in the old\n * snapshot and the second in the new, sharing one name so two *different*\n * elements morph into each other (e.g. `.add(card, \".modal\")`). Symmetric -\n * pass them the other way round to morph back.\n */\n add(\n subject: ViewTransitionTargetDefinition,\n newSubject?: ViewTransitionTargetDefinition\n ) {\n this.currentSubject = subject\n this.resolveDefs.add(subject)\n if (newSubject !== undefined) this.pairs.set(subject, newSubject)\n // Register the subject so it participates (and gets an automatic\n // layout/morph animation) even without an explicit enter/exit/layout.\n if (!this.targets.has(subject)) this.targets.set(subject, {})\n\n return this\n }\n\n /**\n * Control this subject's crop (clip + `object-fit: cover` + animated\n * corners). By default a subject auto-crops only when it actually morphs -\n * present in both snapshots (a survivor, or an `.add(a, b)` pair). A\n * fade-only enter/exit has no second box to crop against, so it's left to\n * the browser default; in particular the `overflow: clip` a crop adds would\n * otherwise clip a mis-sized enter/exit layer to nothing.\n *\n * `.crop(false)` forces the crop off (e.g. a text morph, where\n * `object-fit: cover` clips glyphs as the box grows); `.crop(true)` forces\n * it on for a non-morph the default wouldn't otherwise crop.\n */\n crop(enabled = true) {\n this.cropOverride.set(this.currentSubject, enabled)\n\n return this\n }\n\n /**\n * By default a subject's layer nests under its nearest DOM-ancestor layer\n * (`view-transition-group: contain`), so the ancestor's clip/transform/opacity\n * apply to it through the transition - mirroring how the DOM actually paints,\n * and letting a wrapper crop its child for the whole morph rather than only\n * once the live DOM takes back over. (Needs a browser that supports nested\n * view-transition groups; elsewhere it degrades to the flat default.)\n *\n * Call `.group(false)` to opt out: the layer stays flat and top-level, so it\n * animates independently and escapes an ancestor's clip - e.g. an element\n * that should lift out of a card and fly across, which nesting would clip.\n */\n group(enabled = true) {\n enabled\n ? this.flatGroups.delete(this.currentSubject)\n : this.flatGroups.add(this.currentSubject)\n\n return this\n }\n\n /**\n * Tag this subject's generated layers with a `view-transition-class`, so\n * they can be targeted from CSS - `::view-transition-group(.name)`,\n * `::view-transition-old/new(.name)`, `::view-transition-image-pair(.name)`\n * - without the opaque generated `view-transition-name`. Because `.add()`\n * can match many elements, a shared class targets them all at once (and,\n * for a pair, both ends). The escape hatch for z-index / custom keyframes\n * on a morph layer.\n */\n class(name: string) {\n this.classNames.set(this.currentSubject, name)\n\n return this\n }\n\n /**\n * Set the transition for this subject's morph. The morph is enabled\n * automatically by `.add()`; this just customises its timing (duration,\n * easing, a `delay`/`stagger`, …). On the implicit `root` subject it also\n * opts the page into the transition (the root crossfade).\n */\n layout(options: AnimationOptions = {}) {\n this.updateTarget(\"layout\", {}, options)\n\n return this\n }\n\n enter(keyframes: DOMKeyframesDefinition, options?: AnimationOptions) {\n this.updateTarget(\"enter\", keyframes, options)\n\n return this\n }\n\n exit(keyframes: DOMKeyframesDefinition, options?: AnimationOptions) {\n this.updateTarget(\"exit\", keyframes, options)\n\n return this\n }\n\n /**\n * Animate the new view directly, whether the element is appearing or\n * persisting (unlike `.enter()`, which only fires for a pure newcomer).\n * Pair with `.old()` for a crossfade or slide-through.\n */\n new(keyframes: DOMKeyframesDefinition, options?: AnimationOptions) {\n this.updateTarget(\"new\", keyframes, options)\n\n return this\n }\n\n /**\n * Animate the old view directly, whether the element is leaving or\n * persisting (unlike `.exit()`, which only fires for a pure leaver).\n */\n old(keyframes: DOMKeyframesDefinition, options?: AnimationOptions) {\n this.updateTarget(\"old\", keyframes, options)\n\n return this\n }\n\n updateTarget(\n target: \"enter\" | \"exit\" | \"layout\" | \"new\" | \"old\",\n keyframes: DOMKeyframesDefinition,\n options: AnimationOptions = {}\n ) {\n const { currentSubject, targets } = this\n\n if (!targets.has(currentSubject)) {\n targets.set(currentSubject, {})\n }\n\n const targetData = targets.get(currentSubject)!\n\n targetData[target] = { keyframes, options }\n }\n\n then(resolve: () => void, reject?: () => void) {\n return this.readyPromise.then(resolve, reject)\n }\n}\n\nexport function animateView(\n update: () => void | Promise,\n options: ViewTransitionOptions = {}\n) {\n return new ViewTransitionBuilder(update, options)\n}\n"],"names":[],"mappings":"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"}