[eric] windows 1.1.62: cursor and popups follow target on windows via store-driven style.transform

This commit is contained in:
Eric
2026-05-26 02:10:56 -07:00
parent 31a90502c7
commit da61377d8c
3 changed files with 28 additions and 5 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "openswarm",
"version": "1.1.61",
"version": "1.1.62",
"description": "OpenSwarm — AI Agent Orchestrator",
"author": "openswarm-ai",
"main": "main.js",
@@ -24,11 +24,29 @@ const stripFramerProps = (props: any) => {
return out;
};
// Components that drive position via `animate={{ x, y }}` (ACPopup, ACMultiChoice, etc.) would otherwise lose their layout when the animate prop is stripped, because they have no fallback style.transform. We salvage the latest numeric x/y from animate and apply them as a transform so the div lands in the right place; no animation, just static placement.
const motionShim: any = new Proxy({}, {
get: (_target, tag: string) => {
return React.forwardRef((props: any, ref: any) =>
React.createElement(tag, { ...stripFramerProps(props), ref })
);
return React.forwardRef((props: any, ref: any) => {
let translate = '';
const a = props.animate;
if (a && typeof a === 'object' && !Array.isArray(a)) {
const ax = typeof a.x === 'number' ? a.x : null;
const ay = typeof a.y === 'number' ? a.y : null;
if (ax !== null || ay !== null) {
translate = `translate(${ax ?? 0}px, ${ay ?? 0}px)`;
}
}
const stripped = stripFramerProps(props);
if (translate) {
const existing = stripped.style && stripped.style.transform;
stripped.style = {
...(stripped.style || {}),
transform: existing ? `${existing} ${translate}` : translate,
};
}
return React.createElement(tag, { ...stripped, ref });
});
},
});
@@ -8,7 +8,7 @@ import React, {
import { createPortal } from 'react-dom';
import { motion, useAnimationControls, AnimatePresence } from '../_motionWin';
import { useClaudeTokens } from '@/shared/styles/ThemeContext';
import { cursorStore } from './cursorStore';
import { cursorStore, useCursorPosition } from './cursorStore';
import { resolveSelector } from '../selectors';
import ACPopup from './ACPopup';
import ACMultiChoice from './ACMultiChoice';
@@ -53,9 +53,13 @@ interface MultiChoiceState {
// Snappy 260/26 spring; calm comes from popup cadence + 3s dwell, not cursor delay.
const SPRING = { type: 'spring' as const, stiffness: 260, damping: 26 };
// On Windows the motionWin shim strips Framer Motion's animate prop, so controls.set({x,y}) never moves the wrapper. We bypass by reading the same store the popups read and applying style.transform directly; Mac is unaffected since Framer's own transform writes win the cascade.
const IS_WIN = typeof navigator !== 'undefined' && navigator.userAgent.includes('Windows');
const AgenticCursor = forwardRef<AgenticCursorHandle>((_props, ref) => {
const c = useClaudeTokens();
const controls = useAnimationControls();
const storePos = useCursorPosition();
const posRef = useRef({ x: 0, y: 0 });
const [visible, setVisible] = useState(false);
const [popup, setPopup] = useState<PopupState | null>(null);
@@ -255,6 +259,7 @@ const AgenticCursor = forwardRef<AgenticCursorHandle>((_props, ref) => {
zIndex: 10500,
pointerEvents: 'none',
transformOrigin: 'top left',
...(IS_WIN ? { transform: `translate(${storePos.x}px, ${storePos.y}px)` } : null),
}}
>
{visible && (