[eric] windows 1.1.59: production webpack and framer-motion shim

This commit is contained in:
Eric
2026-05-26 00:29:17 -07:00
parent 7407e6cb37
commit bb2de72f6f
38 changed files with 66 additions and 171 deletions
@@ -1,7 +1,7 @@
// Docked onboarding home: a small, quiet handle on the right edge that reopens the tour.
import React, { useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { motion, AnimatePresence } from './_motionWin';
import { Box, IconButton, Typography, CircularProgress } from '@mui/material';
import CloseIcon from '@mui/icons-material/Close';
import { useClaudeTokens } from '@/shared/styles/ThemeContext';
@@ -2,7 +2,7 @@
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import { motion, AnimatePresence } from 'framer-motion';
import { motion, AnimatePresence } from './_motionWin';
import { Box, Typography, IconButton, Button, ButtonBase } from '@mui/material';
import RemoveIcon from '@mui/icons-material/Remove';
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
@@ -2,7 +2,7 @@
import React from 'react';
import { Modal, Box, Typography, IconButton, Button } from '@mui/material';
import { motion, AnimatePresence } from 'framer-motion';
import { motion, AnimatePresence } from './_motionWin';
import RadioButtonUncheckedIcon from '@mui/icons-material/RadioButtonUnchecked';
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
import LockIcon from '@mui/icons-material/Lock';
@@ -24,10 +24,6 @@ import { report } from './telemetry';
const PERSIST_DEBOUNCE_MS = 200;
const OnboardingRoot: React.FC = () => {
// Windows nuclear ablation v1.1.58: the AgenticCursor motion.div gate in 1.1.57 was not sufficient — OnboardingPanel / OnboardingDirector / popups have additional Framer Motion + portal subtrees that segfault on commit. Return null on Windows so the entire onboarding UI is suppressed; user can still use the app normally without the guided tour. Mac unchanged.
if (typeof navigator !== 'undefined' && navigator.userAgent.includes('Windows')) {
return null;
}
const acRef = useRef<AgenticCursorHandle | null>(null);
const dispatch = useAppDispatch();
const store = useStore<RootState>() as Store<RootState>;
@@ -0,0 +1,48 @@
// Windows-aware shim for framer-motion. On Mac, re-exports the real library; on Windows, motion.* becomes a plain HTML element (no animation, no Framer runtime, no segfault). AnimatePresence passes children through. Onboarding files import from here so a single Mac/Windows fork lives in one place.
import React from 'react';
import * as fm from 'framer-motion';
const IS_WIN = typeof navigator !== 'undefined' && navigator.userAgent.includes('Windows');
const FRAMER_ONLY_PROPS = new Set([
'initial', 'animate', 'exit', 'transition', 'variants', 'layoutId', 'layout',
'drag', 'dragConstraints', 'dragElastic', 'dragMomentum', 'dragControls',
'dragDirectionLock', 'dragListener', 'dragTransition', 'dragSnapToOrigin', 'dragPropagation',
'onDragStart', 'onDragEnd', 'onDrag', 'onDirectionLock',
'onAnimationStart', 'onAnimationComplete', 'onUpdate',
'onLayoutAnimationStart', 'onLayoutAnimationComplete',
'whileHover', 'whileTap', 'whileFocus', 'whileDrag', 'whileInView',
'viewport', 'transformTemplate', 'custom', 'inherit',
]);
const stripFramerProps = (props: any) => {
const out: any = {};
for (const k in props) {
if (!FRAMER_ONLY_PROPS.has(k)) out[k] = props[k];
}
return out;
};
const motionShim: any = new Proxy({}, {
get: (_target, tag: string) => {
return React.forwardRef((props: any, ref: any) =>
React.createElement(tag, { ...stripFramerProps(props), ref })
);
},
});
export const motion: typeof fm.motion = IS_WIN ? motionShim : fm.motion;
export const AnimatePresence: typeof fm.AnimatePresence = IS_WIN
? (({ children }: any) => children) as any
: fm.AnimatePresence;
const animationControlsStub = {
start: () => Promise.resolve(),
stop: () => {},
set: () => {},
mount: () => () => {},
};
export const useAnimationControls: typeof fm.useAnimationControls = IS_WIN
? (() => animationControlsStub as any) as any
: fm.useAnimationControls;
@@ -1,6 +1,6 @@
import React, { useLayoutEffect, useRef, useState } from 'react';
import { Box, Typography, ButtonBase } from '@mui/material';
import { motion } from 'framer-motion';
import { motion } from '../_motionWin';
import { useClaudeTokens } from '@/shared/styles/ThemeContext';
import { useCursorPosition } from './cursorStore';
import type { ACMultiChoiceOption } from '../steps/types';
@@ -1,6 +1,6 @@
import React, { useEffect, useLayoutEffect, useRef, useState } from 'react';
import { Box, Typography } from '@mui/material';
import { motion } from 'framer-motion';
import { motion } from '../_motionWin';
import { useClaudeTokens } from '@/shared/styles/ThemeContext';
import { useCursorPosition } from './cursorStore';
@@ -6,7 +6,7 @@ import React, {
useState,
} from 'react';
import { createPortal } from 'react-dom';
import { motion, useAnimationControls, AnimatePresence } from 'framer-motion';
import { motion, useAnimationControls, AnimatePresence } from '../_motionWin';
import { useClaudeTokens } from '@/shared/styles/ThemeContext';
import { cursorStore } from './cursorStore';
import { resolveSelector } from '../selectors';
@@ -2,8 +2,6 @@ import React from 'react';
/** Slime illustration with X eyes and red badge for errors/warnings. */
export const ErrorSlime: React.FC<{ size?: number }> = ({ size = 22 }) => {
// eslint-disable-next-line no-console
console.log('[diag][ErrorSlime:render]', 'size=', size);
return (
<svg width={size} height={size} viewBox="0 0 28 28" fill="none" style={{ flexShrink: 0 }}>
<path