Mission Control Dashboard - Initial implementation

This commit is contained in:
Daniel Arroyo
2026-03-27 18:36:05 +00:00
parent 257cea2c7d
commit a8fb4d4555
12516 changed files with 2307128 additions and 2 deletions

View File

@@ -0,0 +1,80 @@
import { animateVisualElement, setTarget } from 'motion-dom';
import { invariant } from 'motion-utils';
function stopAnimation(visualElement) {
visualElement.values.forEach((value) => value.stop());
}
function setVariants(visualElement, variantLabels) {
const reversedLabels = [...variantLabels].reverse();
reversedLabels.forEach((key) => {
const variant = visualElement.getVariant(key);
variant && setTarget(visualElement, variant);
if (visualElement.variantChildren) {
visualElement.variantChildren.forEach((child) => {
setVariants(child, variantLabels);
});
}
});
}
function setValues(visualElement, definition) {
if (Array.isArray(definition)) {
return setVariants(visualElement, definition);
}
else if (typeof definition === "string") {
return setVariants(visualElement, [definition]);
}
else {
setTarget(visualElement, definition);
}
}
/**
* @public
*/
function animationControls() {
/**
* Track whether the host component has mounted.
*/
let hasMounted = false;
/**
* A collection of linked component animation controls.
*/
const subscribers = new Set();
const controls = {
subscribe(visualElement) {
subscribers.add(visualElement);
return () => void subscribers.delete(visualElement);
},
start(definition, transitionOverride) {
invariant(hasMounted, "controls.start() should only be called after a component has mounted. Consider calling within a useEffect hook.");
const animations = [];
subscribers.forEach((visualElement) => {
animations.push(animateVisualElement(visualElement, definition, {
transitionOverride,
}));
});
return Promise.all(animations);
},
set(definition) {
invariant(hasMounted, "controls.set() should only be called after a component has mounted. Consider calling within a useEffect hook.");
return subscribers.forEach((visualElement) => {
setValues(visualElement, definition);
});
},
stop() {
subscribers.forEach((visualElement) => {
stopAnimation(visualElement);
});
},
mount() {
hasMounted = true;
return () => {
hasMounted = false;
controls.stop();
};
},
};
return controls;
}
export { animationControls, setValues };
//# sourceMappingURL=animation-controls.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,19 @@
"use client";
import { useConstant } from '../../utils/use-constant.mjs';
import { useUnmountEffect } from '../../utils/use-unmount-effect.mjs';
import { createScopedWaapiAnimate } from '../animators/waapi/animate-style.mjs';
function useAnimateMini() {
const scope = useConstant(() => ({
current: null, // Will be hydrated by React
animations: [],
}));
const animate = useConstant(() => createScopedWaapiAnimate(scope));
useUnmountEffect(() => {
scope.animations.forEach((animation) => animation.stop());
});
return [scope, animate];
}
export { useAnimateMini };
//# sourceMappingURL=use-animate-style.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"use-animate-style.mjs","sources":["../../../../src/animation/hooks/use-animate-style.ts"],"sourcesContent":["\"use client\"\n\nimport { useConstant } from \"../../utils/use-constant\"\nimport { useUnmountEffect } from \"../../utils/use-unmount-effect\"\nimport { createScopedWaapiAnimate } from \"../animators/waapi/animate-style\"\nimport { AnimationScope } from \"motion-dom\"\n\nexport function useAnimateMini<T extends Element = any>() {\n const scope: AnimationScope<T> = useConstant(() => ({\n current: null!, // Will be hydrated by React\n animations: [],\n }))\n\n const animate = useConstant(() => createScopedWaapiAnimate(scope))\n\n useUnmountEffect(() => {\n scope.animations.forEach((animation) => animation.stop())\n })\n\n return [scope, animate] as [AnimationScope<T>, typeof animate]\n}\n"],"names":[],"mappings":";;;;;;AAQI;;AAEI;AACH;AAED;;AAGI;AACJ;AAEA;AACJ;;"}

View File

@@ -0,0 +1,23 @@
"use client";
import { useMemo } from 'react';
import { useConstant } from '../../utils/use-constant.mjs';
import { useUnmountEffect } from '../../utils/use-unmount-effect.mjs';
import { useReducedMotionConfig } from '../../utils/reduced-motion/use-reduced-motion-config.mjs';
import { createScopedAnimate } from '../animate/index.mjs';
function useAnimate() {
const scope = useConstant(() => ({
current: null, // Will be hydrated by React
animations: [],
}));
const reduceMotion = useReducedMotionConfig() ?? undefined;
const animate = useMemo(() => createScopedAnimate({ scope, reduceMotion }), [scope, reduceMotion]);
useUnmountEffect(() => {
scope.animations.forEach((animation) => animation.stop());
scope.animations.length = 0;
});
return [scope, animate];
}
export { useAnimate };
//# sourceMappingURL=use-animate.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"use-animate.mjs","sources":["../../../../src/animation/hooks/use-animate.ts"],"sourcesContent":["\"use client\"\n\nimport { useMemo } from \"react\"\nimport { AnimationScope } from \"motion-dom\"\nimport { useConstant } from \"../../utils/use-constant\"\nimport { useUnmountEffect } from \"../../utils/use-unmount-effect\"\nimport { useReducedMotionConfig } from \"../../utils/reduced-motion/use-reduced-motion-config\"\nimport { createScopedAnimate } from \"../animate\"\n\nexport function useAnimate<T extends Element = any>() {\n const scope: AnimationScope<T> = useConstant(() => ({\n current: null!, // Will be hydrated by React\n animations: [],\n }))\n\n const reduceMotion = useReducedMotionConfig() ?? undefined\n\n const animate = useMemo(\n () => createScopedAnimate({ scope, reduceMotion }),\n [scope, reduceMotion]\n )\n\n useUnmountEffect(() => {\n scope.animations.forEach((animation) => animation.stop())\n scope.animations.length = 0\n })\n\n return [scope, animate] as [AnimationScope<T>, typeof animate]\n}\n"],"names":[],"mappings":";;;;;;;;AAUI;;AAEI;AACH;AAED;;;AAQI;AACA;AACJ;AAEA;AACJ;;"}

View File

@@ -0,0 +1,64 @@
"use client";
import { animateVisualElement, VisualElement, createBox } from 'motion-dom';
import { useState, useLayoutEffect } from 'react';
import { makeUseVisualState } from '../../motion/utils/use-visual-state.mjs';
import { useConstant } from '../../utils/use-constant.mjs';
const createObject = () => ({});
class StateVisualElement extends VisualElement {
constructor() {
super(...arguments);
this.measureInstanceViewportBox = createBox;
}
build() { }
resetTransform() { }
restoreTransform() { }
removeValueFromRenderState() { }
renderInstance() { }
scrapeMotionValuesFromProps() {
return createObject();
}
getBaseTargetFromProps() {
return undefined;
}
readValueFromInstance(_state, key, options) {
return options.initialState[key] || 0;
}
sortInstanceNodePosition() {
return 0;
}
}
const useVisualState = makeUseVisualState({
scrapeMotionValuesFromProps: createObject,
createRenderState: createObject,
});
/**
* This is not an officially supported API and may be removed
* on any version.
*/
function useAnimatedState(initialState) {
const [animationState, setAnimationState] = useState(initialState);
const visualState = useVisualState({}, false);
const element = useConstant(() => {
return new StateVisualElement({
props: {
onUpdate: (v) => {
setAnimationState({ ...v });
},
},
visualState,
presenceContext: null,
}, { initialState });
});
useLayoutEffect(() => {
element.mount({});
return () => element.unmount();
}, [element]);
const startAnimation = useConstant(() => (animationDefinition) => {
return animateVisualElement(element, animationDefinition);
});
return [animationState, startAnimation];
}
export { useAnimatedState };
//# sourceMappingURL=use-animated-state.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"use-animated-state.mjs","sources":["../../../../src/animation/hooks/use-animated-state.ts"],"sourcesContent":["\"use client\"\n\nimport {\n animateVisualElement,\n createBox,\n ResolvedValues,\n TargetAndTransition,\n VisualElement,\n} from \"motion-dom\"\nimport { useLayoutEffect, useState } from \"react\"\nimport { makeUseVisualState } from \"../../motion/utils/use-visual-state\"\nimport { useConstant } from \"../../utils/use-constant\"\n\ninterface AnimatedStateOptions {\n initialState: ResolvedValues\n}\n\nconst createObject = () => ({})\n\nclass StateVisualElement extends VisualElement<\n ResolvedValues,\n {},\n AnimatedStateOptions\n> {\n type: \"state\"\n build() {}\n measureInstanceViewportBox = createBox\n resetTransform() {}\n restoreTransform() {}\n removeValueFromRenderState() {}\n renderInstance() {}\n scrapeMotionValuesFromProps() {\n return createObject()\n }\n getBaseTargetFromProps() {\n return undefined\n }\n\n readValueFromInstance(\n _state: ResolvedValues,\n key: string,\n options: AnimatedStateOptions\n ) {\n return options.initialState[key] || 0\n }\n\n sortInstanceNodePosition() {\n return 0\n }\n}\n\nconst useVisualState = makeUseVisualState({\n scrapeMotionValuesFromProps: createObject,\n createRenderState: createObject,\n})\n\n/**\n * This is not an officially supported API and may be removed\n * on any version.\n */\nexport function useAnimatedState(initialState: any) {\n const [animationState, setAnimationState] = useState(initialState)\n const visualState = useVisualState({}, false)\n\n const element = useConstant(() => {\n return new StateVisualElement(\n {\n props: {\n onUpdate: (v) => {\n setAnimationState({ ...v })\n },\n },\n visualState,\n presenceContext: null,\n },\n { initialState }\n )\n })\n\n useLayoutEffect(() => {\n element.mount({})\n return () => element.unmount()\n }, [element])\n\n const startAnimation = useConstant(\n () => (animationDefinition: TargetAndTransition) => {\n return animateVisualElement(element, animationDefinition)\n }\n )\n\n return [animationState, startAnimation]\n}\n"],"names":[],"mappings":";;;;;;AAiBA;AAEA;AAAA;;;;AAMI;AAEA;AACA;AACA;AACA;;;;;AAKI;;AAGJ;;;;AASI;;AAEP;AAED;AACI;AACA;AACH;AAED;;;AAGG;AACG;;;AAIF;;AAGY;AACI;AACI;;AAEP;;AAED;AACH;AAGT;;AAGI;AACA;AACJ;;AAIQ;AACJ;AAGJ;AACJ;;"}

View File

@@ -0,0 +1,43 @@
"use client";
import { useConstant } from '../../utils/use-constant.mjs';
import { useIsomorphicLayoutEffect } from '../../utils/use-isomorphic-effect.mjs';
import { animationControls } from './animation-controls.mjs';
/**
* Creates `LegacyAnimationControls`, which can be used to manually start, stop
* and sequence animations on one or more components.
*
* The returned `LegacyAnimationControls` should be passed to the `animate` property
* of the components you want to animate.
*
* These components can then be animated with the `start` method.
*
* ```jsx
* import * as React from 'react'
* import { motion, useAnimation } from 'framer-motion'
*
* export function MyComponent(props) {
* const controls = useAnimation()
*
* controls.start({
* x: 100,
* transition: { duration: 0.5 },
* })
*
* return <motion.div animate={controls} />
* }
* ```
*
* @returns Animation controller with `start` and `stop` methods
*
* @public
*/
function useAnimationControls() {
const controls = useConstant(animationControls);
useIsomorphicLayoutEffect(controls.mount, []);
return controls;
}
const useAnimation = useAnimationControls;
export { useAnimation, useAnimationControls };
//# sourceMappingURL=use-animation.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"use-animation.mjs","sources":["../../../../src/animation/hooks/use-animation.ts"],"sourcesContent":["\"use client\"\n\nimport { LegacyAnimationControls } from \"motion-dom\"\nimport { useConstant } from \"../../utils/use-constant\"\nimport { useIsomorphicLayoutEffect } from \"../../utils/use-isomorphic-effect\"\nimport { animationControls } from \"./animation-controls\"\n\n/**\n * Creates `LegacyAnimationControls`, which can be used to manually start, stop\n * and sequence animations on one or more components.\n *\n * The returned `LegacyAnimationControls` should be passed to the `animate` property\n * of the components you want to animate.\n *\n * These components can then be animated with the `start` method.\n *\n * ```jsx\n * import * as React from 'react'\n * import { motion, useAnimation } from 'framer-motion'\n *\n * export function MyComponent(props) {\n * const controls = useAnimation()\n *\n * controls.start({\n * x: 100,\n * transition: { duration: 0.5 },\n * })\n *\n * return <motion.div animate={controls} />\n * }\n * ```\n *\n * @returns Animation controller with `start` and `stop` methods\n *\n * @public\n */\nexport function useAnimationControls(): LegacyAnimationControls {\n const controls = useConstant(animationControls)\n\n useIsomorphicLayoutEffect(controls.mount, [])\n\n return controls\n}\n\nexport const useAnimation = useAnimationControls\n"],"names":[],"mappings":";;;;;AAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BG;;AAEC;AAEA;AAEA;AACJ;AAEO;;"}