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,13 @@
import { motionComponentSymbol } from './symbol.mjs';
/**
* Checks if a component is a `motion` component.
*/
function isMotionComponent(component) {
return (component !== null &&
typeof component === "object" &&
motionComponentSymbol in component);
}
export { isMotionComponent };
//# sourceMappingURL=is-motion-component.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"is-motion-component.mjs","sources":["../../../../src/motion/utils/is-motion-component.ts"],"sourcesContent":["import { motionComponentSymbol } from \"./symbol\"\n\n/**\n * Checks if a component is a `motion` component.\n */\nexport function isMotionComponent(component: React.ComponentType | string) {\n return (\n component !== null &&\n typeof component === \"object\" &&\n motionComponentSymbol in component\n )\n}\n"],"names":[],"mappings":";;AAEA;;AAEG;AACG,SAAU,iBAAiB,CAAC,SAAuC,EAAA;IACrE,QACI,SAAS,KAAK,IAAI;QAClB,OAAO,SAAS,KAAK,QAAQ;QAC7B,qBAAqB,IAAI,SAAS;AAE1C;;;;"}

View File

@@ -0,0 +1,4 @@
const motionComponentSymbol = Symbol.for("motionComponentSymbol");
export { motionComponentSymbol };
//# sourceMappingURL=symbol.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"symbol.mjs","sources":["../../../../src/motion/utils/symbol.ts"],"sourcesContent":["export const motionComponentSymbol = Symbol.for(\"motionComponentSymbol\")\n"],"names":[],"mappings":"AAAO,MAAM,qBAAqB,GAAG,MAAM,CAAC,GAAG,CAAC,uBAAuB;;;;"}

View File

@@ -0,0 +1,18 @@
import { isMotionComponent } from './is-motion-component.mjs';
import { motionComponentSymbol } from './symbol.mjs';
/**
* Unwraps a `motion` component and returns either a string for `motion.div` or
* the React component for `motion(Component)`.
*
* If the component is not a `motion` component it returns undefined.
*/
function unwrapMotionComponent(component) {
if (isMotionComponent(component)) {
return component[motionComponentSymbol];
}
return undefined;
}
export { unwrapMotionComponent };
//# sourceMappingURL=unwrap-motion-component.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"unwrap-motion-component.mjs","sources":["../../../../src/motion/utils/unwrap-motion-component.ts"],"sourcesContent":["import { isMotionComponent } from \"./is-motion-component\"\nimport { motionComponentSymbol } from \"./symbol\"\n\n/**\n * Unwraps a `motion` component and returns either a string for `motion.div` or\n * the React component for `motion(Component)`.\n *\n * If the component is not a `motion` component it returns undefined.\n */\nexport function unwrapMotionComponent(\n component: React.ComponentType | string\n): React.ComponentType | string | undefined {\n if (isMotionComponent(component)) {\n return component[motionComponentSymbol as keyof typeof component]\n }\n\n return undefined\n}\n"],"names":[],"mappings":";;;AAGA;;;;;AAKG;AACG,SAAU,qBAAqB,CACjC,SAAuC,EAAA;AAEvC,IAAA,IAAI,iBAAiB,CAAC,SAAS,CAAC,EAAE;AAC9B,QAAA,OAAO,SAAS,CAAC,qBAA+C,CAAC;IACrE;AAEA,IAAA,OAAO,SAAS;AACpB;;;;"}

View File

@@ -0,0 +1,52 @@
"use client";
import { useRef, useInsertionEffect, useCallback } from 'react';
/**
* Creates a ref function that, when called, hydrates the provided
* external ref and VisualElement.
*/
function useMotionRef(visualState, visualElement, externalRef) {
/**
* Store externalRef in a ref to avoid including it in the useCallback
* dependency array. Including externalRef in dependencies causes issues
* with libraries like Radix UI that create new callback refs on each render
* when using asChild - this would cause the callback to be recreated,
* triggering element remounts and breaking AnimatePresence exit animations.
*/
const externalRefContainer = useRef(externalRef);
useInsertionEffect(() => {
externalRefContainer.current = externalRef;
});
// Store cleanup function returned by callback refs (React 19 feature)
const refCleanup = useRef(null);
return useCallback((instance) => {
if (instance) {
visualState.onMount?.(instance);
}
const ref = externalRefContainer.current;
if (typeof ref === "function") {
if (instance) {
const cleanup = ref(instance);
if (typeof cleanup === "function") {
refCleanup.current = cleanup;
}
}
else if (refCleanup.current) {
refCleanup.current();
refCleanup.current = null;
}
else {
ref(instance);
}
}
else if (ref) {
ref.current = instance;
}
if (visualElement) {
instance ? visualElement.mount(instance) : visualElement.unmount();
}
}, [visualElement]);
}
export { useMotionRef };
//# sourceMappingURL=use-motion-ref.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"use-motion-ref.mjs","sources":["../../../../src/motion/utils/use-motion-ref.ts"],"sourcesContent":["\"use client\"\n\nimport type { VisualElement } from \"motion-dom\"\nimport * as React from \"react\"\nimport { useCallback, useInsertionEffect, useRef } from \"react\"\nimport { VisualState } from \"./use-visual-state\"\n\n/**\n * Creates a ref function that, when called, hydrates the provided\n * external ref and VisualElement.\n */\nexport function useMotionRef<Instance, RenderState>(\n visualState: VisualState<Instance, RenderState>,\n visualElement?: VisualElement<Instance> | null,\n externalRef?: React.Ref<Instance>\n): React.Ref<Instance> {\n /**\n * Store externalRef in a ref to avoid including it in the useCallback\n * dependency array. Including externalRef in dependencies causes issues\n * with libraries like Radix UI that create new callback refs on each render\n * when using asChild - this would cause the callback to be recreated,\n * triggering element remounts and breaking AnimatePresence exit animations.\n */\n const externalRefContainer = useRef(externalRef)\n useInsertionEffect(() => {\n externalRefContainer.current = externalRef\n })\n\n // Store cleanup function returned by callback refs (React 19 feature)\n const refCleanup = useRef<(() => void) | null>(null)\n\n return useCallback(\n (instance: Instance) => {\n if (instance) {\n visualState.onMount?.(instance)\n }\n\n const ref = externalRefContainer.current\n if (typeof ref === \"function\") {\n if (instance) {\n const cleanup = ref(instance)\n if (typeof cleanup === \"function\") {\n refCleanup.current = cleanup\n }\n } else if (refCleanup.current) {\n refCleanup.current()\n refCleanup.current = null\n } else {\n ref(instance)\n }\n } else if (ref) {\n ;(ref as React.MutableRefObject<Instance>).current = instance\n }\n\n if (visualElement) {\n instance ? visualElement.mount(instance) : visualElement.unmount()\n }\n },\n [visualElement]\n )\n}\n"],"names":[],"mappings":";;;AAOA;;;AAGG;;AAMC;;;;;;AAMG;AACH;;AAEI;AACJ;;AAGA;AAEA;;AAGY;;AAGJ;AACA;;AAEQ;AACA;AACI;;;AAED;;AAEH;;;;;;;AAKF;;;AAIF;;AAER;AAGR;;"}

View File

@@ -0,0 +1,166 @@
"use client";
import { optimizedAppearDataAttribute } from 'motion-dom';
import { useContext, useRef, useInsertionEffect, useEffect } from 'react';
import { LazyContext } from '../../context/LazyContext.mjs';
import { MotionConfigContext } from '../../context/MotionConfigContext.mjs';
import { MotionContext } from '../../context/MotionContext/index.mjs';
import { PresenceContext } from '../../context/PresenceContext.mjs';
import { SwitchLayoutGroupContext } from '../../context/SwitchLayoutGroupContext.mjs';
import { isRefObject } from '../../utils/is-ref-object.mjs';
import { useIsomorphicLayoutEffect } from '../../utils/use-isomorphic-effect.mjs';
function useVisualElement(Component, visualState, props, createVisualElement, ProjectionNodeConstructor, isSVG) {
const { visualElement: parent } = useContext(MotionContext);
const lazyContext = useContext(LazyContext);
const presenceContext = useContext(PresenceContext);
const motionConfig = useContext(MotionConfigContext);
const reducedMotionConfig = motionConfig.reducedMotion;
const skipAnimations = motionConfig.skipAnimations;
const visualElementRef = useRef(null);
/**
* Track whether the component has been through React's commit phase.
* Used to detect when LazyMotion features load after the component has mounted.
*/
const hasMountedOnce = useRef(false);
/**
* If we haven't preloaded a renderer, check to see if we have one lazy-loaded
*/
createVisualElement =
createVisualElement ||
lazyContext.renderer;
if (!visualElementRef.current && createVisualElement) {
visualElementRef.current = createVisualElement(Component, {
visualState,
parent,
props,
presenceContext,
blockInitialAnimation: presenceContext
? presenceContext.initial === false
: false,
reducedMotionConfig,
skipAnimations,
isSVG,
});
/**
* If the component has already mounted before features loaded (e.g. via
* LazyMotion with async feature loading), we need to force the initial
* animation to run. Otherwise state changes that occurred before features
* loaded will be lost and the element will snap to its final state.
*/
if (hasMountedOnce.current && visualElementRef.current) {
visualElementRef.current.manuallyAnimateOnMount = true;
}
}
const visualElement = visualElementRef.current;
/**
* Load Motion gesture and animation features. These are rendered as renderless
* components so each feature can optionally make use of React lifecycle methods.
*/
const initialLayoutGroupConfig = useContext(SwitchLayoutGroupContext);
if (visualElement &&
!visualElement.projection &&
ProjectionNodeConstructor &&
(visualElement.type === "html" || visualElement.type === "svg")) {
createProjectionNode(visualElementRef.current, props, ProjectionNodeConstructor, initialLayoutGroupConfig);
}
const isMounted = useRef(false);
useInsertionEffect(() => {
/**
* Check the component has already mounted before calling
* `update` unnecessarily. This ensures we skip the initial update.
*/
if (visualElement && isMounted.current) {
visualElement.update(props, presenceContext);
}
});
/**
* Cache this value as we want to know whether HandoffAppearAnimations
* was present on initial render - it will be deleted after this.
*/
const optimisedAppearId = props[optimizedAppearDataAttribute];
const wantsHandoff = useRef(Boolean(optimisedAppearId) &&
typeof window !== "undefined" &&
!window.MotionHandoffIsComplete?.(optimisedAppearId) &&
window.MotionHasOptimisedAnimation?.(optimisedAppearId));
useIsomorphicLayoutEffect(() => {
/**
* Track that this component has mounted. This is used to detect when
* LazyMotion features load after the component has already committed.
*/
hasMountedOnce.current = true;
if (!visualElement)
return;
isMounted.current = true;
window.MotionIsMounted = true;
visualElement.updateFeatures();
visualElement.scheduleRenderMicrotask();
/**
* Ideally this function would always run in a useEffect.
*
* However, if we have optimised appear animations to handoff from,
* it needs to happen synchronously to ensure there's no flash of
* incorrect styles in the event of a hydration error.
*
* So if we detect a situtation where optimised appear animations
* are running, we use useLayoutEffect to trigger animations.
*/
if (wantsHandoff.current && visualElement.animationState) {
visualElement.animationState.animateChanges();
}
});
useEffect(() => {
if (!visualElement)
return;
if (!wantsHandoff.current && visualElement.animationState) {
visualElement.animationState.animateChanges();
}
if (wantsHandoff.current) {
// This ensures all future calls to animateChanges() in this component will run in useEffect
queueMicrotask(() => {
window.MotionHandoffMarkAsComplete?.(optimisedAppearId);
});
wantsHandoff.current = false;
}
/**
* Now we've finished triggering animations for this element we
* can wipe the enteringChildren set for the next render.
*/
visualElement.enteringChildren = undefined;
});
return visualElement;
}
function createProjectionNode(visualElement, props, ProjectionNodeConstructor, initialPromotionConfig) {
const { layoutId, layout, drag, dragConstraints, layoutScroll, layoutRoot, layoutAnchor, layoutCrossfade, } = props;
visualElement.projection = new ProjectionNodeConstructor(visualElement.latestValues, props["data-framer-portal-id"]
? undefined
: getClosestProjectingNode(visualElement.parent));
visualElement.projection.setOptions({
layoutId,
layout,
alwaysMeasureLayout: Boolean(drag) || (dragConstraints && isRefObject(dragConstraints)),
visualElement,
/**
* TODO: Update options in an effect. This could be tricky as it'll be too late
* to update by the time layout animations run.
* We also need to fix this safeToRemove by linking it up to the one returned by usePresence,
* ensuring it gets called if there's no potential layout animations.
*
*/
animationType: typeof layout === "string" ? layout : "both",
initialPromotionConfig,
crossfade: layoutCrossfade,
layoutScroll,
layoutRoot,
layoutAnchor,
});
}
function getClosestProjectingNode(visualElement) {
if (!visualElement)
return undefined;
return visualElement.options.allowProjection !== false
? visualElement.projection
: getClosestProjectingNode(visualElement.parent);
}
export { useVisualElement };
//# sourceMappingURL=use-visual-element.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,78 @@
"use client";
import { resolveMotionValue, isControllingVariants, isVariantNode, isAnimationControls, resolveVariantFromProps } from 'motion-dom';
import { useContext } from 'react';
import { MotionContext } from '../../context/MotionContext/index.mjs';
import { PresenceContext } from '../../context/PresenceContext.mjs';
import { useConstant } from '../../utils/use-constant.mjs';
function makeState({ scrapeMotionValuesFromProps, createRenderState, }, props, context, presenceContext) {
const state = {
latestValues: makeLatestValues(props, context, presenceContext, scrapeMotionValuesFromProps),
renderState: createRenderState(),
};
return state;
}
function makeLatestValues(props, context, presenceContext, scrapeMotionValues) {
const values = {};
const motionValues = scrapeMotionValues(props, {});
for (const key in motionValues) {
values[key] = resolveMotionValue(motionValues[key]);
}
let { initial, animate } = props;
const isControllingVariants$1 = isControllingVariants(props);
const isVariantNode$1 = isVariantNode(props);
if (context &&
isVariantNode$1 &&
!isControllingVariants$1 &&
props.inherit !== false) {
if (initial === undefined)
initial = context.initial;
if (animate === undefined)
animate = context.animate;
}
let isInitialAnimationBlocked = presenceContext
? presenceContext.initial === false
: false;
isInitialAnimationBlocked = isInitialAnimationBlocked || initial === false;
const variantToSet = isInitialAnimationBlocked ? animate : initial;
if (variantToSet &&
typeof variantToSet !== "boolean" &&
!isAnimationControls(variantToSet)) {
const list = Array.isArray(variantToSet) ? variantToSet : [variantToSet];
for (let i = 0; i < list.length; i++) {
const resolved = resolveVariantFromProps(props, list[i]);
if (resolved) {
const { transitionEnd, transition, ...target } = resolved;
for (const key in target) {
let valueTarget = target[key];
if (Array.isArray(valueTarget)) {
/**
* Take final keyframe if the initial animation is blocked because
* we want to initialise at the end of that blocked animation.
*/
const index = isInitialAnimationBlocked
? valueTarget.length - 1
: 0;
valueTarget = valueTarget[index];
}
if (valueTarget !== null) {
values[key] = valueTarget;
}
}
for (const key in transitionEnd) {
values[key] = transitionEnd[key];
}
}
}
}
return values;
}
const makeUseVisualState = (config) => (props, isStatic) => {
const context = useContext(MotionContext);
const presenceContext = useContext(PresenceContext);
const make = () => makeState(config, props, context, presenceContext);
return isStatic ? make() : useConstant(make);
};
export { makeUseVisualState };
//# sourceMappingURL=use-visual-state.mjs.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,59 @@
/**
* A list of all valid MotionProps.
*
* @privateRemarks
* This doesn't throw if a `MotionProp` name is missing - it should.
*/
const validMotionProps = new Set([
"animate",
"exit",
"variants",
"initial",
"style",
"values",
"variants",
"transition",
"transformTemplate",
"custom",
"inherit",
"onBeforeLayoutMeasure",
"onAnimationStart",
"onAnimationComplete",
"onUpdate",
"onDragStart",
"onDrag",
"onDragEnd",
"onMeasureDragConstraints",
"onDirectionLock",
"onDragTransitionEnd",
"_dragX",
"_dragY",
"onHoverStart",
"onHoverEnd",
"onViewportEnter",
"onViewportLeave",
"globalTapTarget",
"propagate",
"ignoreStrict",
"viewport",
]);
/**
* Check whether a prop name is a valid `MotionProp` key.
*
* @param key - Name of the property to check
* @returns `true` is key is a valid `MotionProp`.
*
* @public
*/
function isValidMotionProp(key) {
return (key.startsWith("while") ||
(key.startsWith("drag") && key !== "draggable") ||
key.startsWith("layout") ||
key.startsWith("onTap") ||
key.startsWith("onPan") ||
key.startsWith("onLayout") ||
validMotionProps.has(key));
}
export { isValidMotionProp };
//# sourceMappingURL=valid-prop.mjs.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"valid-prop.mjs","sources":["../../../../src/motion/utils/valid-prop.ts"],"sourcesContent":["import { MotionProps } from \"../types\"\n\n/**\n * A list of all valid MotionProps.\n *\n * @privateRemarks\n * This doesn't throw if a `MotionProp` name is missing - it should.\n */\nconst validMotionProps = new Set<keyof MotionProps>([\n \"animate\",\n \"exit\",\n \"variants\",\n \"initial\",\n \"style\",\n \"values\",\n \"variants\",\n \"transition\",\n \"transformTemplate\",\n \"custom\",\n \"inherit\",\n \"onBeforeLayoutMeasure\",\n \"onAnimationStart\",\n \"onAnimationComplete\",\n \"onUpdate\",\n \"onDragStart\",\n \"onDrag\",\n \"onDragEnd\",\n \"onMeasureDragConstraints\",\n \"onDirectionLock\",\n \"onDragTransitionEnd\",\n \"_dragX\",\n \"_dragY\",\n \"onHoverStart\",\n \"onHoverEnd\",\n \"onViewportEnter\",\n \"onViewportLeave\",\n \"globalTapTarget\",\n \"propagate\",\n \"ignoreStrict\",\n \"viewport\",\n])\n\n/**\n * Check whether a prop name is a valid `MotionProp` key.\n *\n * @param key - Name of the property to check\n * @returns `true` is key is a valid `MotionProp`.\n *\n * @public\n */\nexport function isValidMotionProp(key: string) {\n return (\n key.startsWith(\"while\") ||\n (key.startsWith(\"drag\") && key !== \"draggable\") ||\n key.startsWith(\"layout\") ||\n key.startsWith(\"onTap\") ||\n key.startsWith(\"onPan\") ||\n key.startsWith(\"onLayout\") ||\n validMotionProps.has(key as keyof MotionProps)\n )\n}\n"],"names":[],"mappings":"AAEA;;;;;AAKG;AACH,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAoB;IAChD,SAAS;IACT,MAAM;IACN,UAAU;IACV,SAAS;IACT,OAAO;IACP,QAAQ;IACR,UAAU;IACV,YAAY;IACZ,mBAAmB;IACnB,QAAQ;IACR,SAAS;IACT,uBAAuB;IACvB,kBAAkB;IAClB,qBAAqB;IACrB,UAAU;IACV,aAAa;IACb,QAAQ;IACR,WAAW;IACX,0BAA0B;IAC1B,iBAAiB;IACjB,qBAAqB;IACrB,QAAQ;IACR,QAAQ;IACR,cAAc;IACd,YAAY;IACZ,iBAAiB;IACjB,iBAAiB;IACjB,iBAAiB;IACjB,WAAW;IACX,cAAc;IACd,UAAU;AACb,CAAA,CAAC;AAEF;;;;;;;AAOG;AACG,SAAU,iBAAiB,CAAC,GAAW,EAAA;AACzC,IAAA,QACI,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC;SACtB,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,GAAG,KAAK,WAAW,CAAC;AAC/C,QAAA,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC;AACxB,QAAA,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC;AACvB,QAAA,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC;AACvB,QAAA,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC;AAC1B,QAAA,gBAAgB,CAAC,GAAG,CAAC,GAAwB,CAAC;AAEtD;;;;"}