Track pills became menu surfaces when the trackers moved out of stacked cards, but ComposerTrackRow kept the raw Pressable it had as an inline card row. Nothing in that path reaches selectItem, so the popover or sheet stayed parked over the transcript after opening a subagent, and on iOS the action fired while UIKit was still tearing the sheet down. Rows now hand the press to the engine and take closeOnSelect, as MenuItem does; bulk archive opts out because its progress lands in the panel. The running mark is the shared StatusRing rather than a still dot the pill drew for itself, and the remaining dots read their colour from the one bucket-to-colour map. The slot is sized for the ring in every state so the label does not step sideways when the last child finishes. Mounting the real menu engine in a test needed harness work: stubs for two packages that ship untranspiled Flow, reanimated left out of Vite's prebundle so its .web files win, and the gaps filled in the unistyles test theme.
101 lines
2.2 KiB
TypeScript
101 lines
2.2 KiB
TypeScript
const testTheme = {
|
|
colorScheme: "light",
|
|
colors: {
|
|
foreground: "#111111",
|
|
foregroundMuted: "#666666",
|
|
statusSuccess: "#15803d",
|
|
statusDanger: "#b91c1c",
|
|
statusWarning: "#d97706",
|
|
statusMerged: "#7c3aed",
|
|
// The light band's values, so a test can name the colour it expects.
|
|
statusDotSuccess: "#299f51",
|
|
statusDotDanger: "#f12e2f",
|
|
statusDotWarning: "#b37824",
|
|
statusDotRunning: "#268ae0",
|
|
accent: "#2563eb",
|
|
accentForeground: "#ffffff",
|
|
destructive: "#dc2626",
|
|
destructiveForeground: "#ffffff",
|
|
surface1: "#fafafa",
|
|
surface2: "#f4f4f5",
|
|
surface3: "#e4e4e7",
|
|
border: "#e4e4e7",
|
|
borderAccent: "#a1a1aa",
|
|
palette: {
|
|
amber: { 500: "#f59e0b" },
|
|
blue: { 300: "#93c5fd" },
|
|
green: { 500: "#22c55e" },
|
|
red: { 300: "#fca5a5" },
|
|
white: "#ffffff",
|
|
},
|
|
},
|
|
borderWidth: { 1: 1 },
|
|
spacing: [0, 4, 8, 12, 16, 20, 24, 28, 32],
|
|
fontSize: {
|
|
xs: 12,
|
|
sm: 14,
|
|
base: 16,
|
|
},
|
|
fontFamily: {
|
|
ui: "sans-serif",
|
|
mono: "monospace",
|
|
},
|
|
fontWeight: {
|
|
normal: "400",
|
|
medium: "500",
|
|
},
|
|
borderRadius: {
|
|
base: 4,
|
|
md: 6,
|
|
lg: 8,
|
|
xl: 12,
|
|
full: 9999,
|
|
},
|
|
iconSize: { sm: 16, md: 20 },
|
|
opacity: { 50: 0.5 },
|
|
shadow: {
|
|
sm: {
|
|
shadowColor: "rgba(0, 0, 0, 0.02)",
|
|
shadowOffset: { width: 0, height: 2 },
|
|
shadowRadius: 8,
|
|
elevation: 2,
|
|
},
|
|
md: {
|
|
shadowColor: "rgba(0, 0, 0, 0.04)",
|
|
shadowOffset: { width: 0, height: 4 },
|
|
shadowRadius: 16,
|
|
elevation: 4,
|
|
},
|
|
lg: {
|
|
shadowColor: "rgba(0, 0, 0, 0.08)",
|
|
shadowOffset: { width: 0, height: 8 },
|
|
shadowRadius: 24,
|
|
elevation: 8,
|
|
},
|
|
},
|
|
};
|
|
|
|
type StyleFactory<T> = (theme: typeof testTheme) => T;
|
|
|
|
function isStyleFactory<T>(styles: T | StyleFactory<T>): styles is StyleFactory<T> {
|
|
return typeof styles === "function";
|
|
}
|
|
|
|
export const StyleSheet = {
|
|
create: <T>(styles: T | StyleFactory<T>): T =>
|
|
isStyleFactory(styles) ? styles(testTheme) : styles,
|
|
};
|
|
|
|
export const withUnistyles = <T>(Component: T): T => Component;
|
|
|
|
export const useUnistyles = () => ({
|
|
theme: testTheme,
|
|
rt: {},
|
|
breakpoint: undefined,
|
|
});
|
|
|
|
export const UnistylesRuntime = {
|
|
setTheme: () => undefined,
|
|
themeName: "light",
|
|
};
|