Skip to content

Commit 6527908

Browse files
committed
Polish simulator client panels and toolbar
1 parent 4f9f49f commit 6527908

12 files changed

Lines changed: 350 additions & 214 deletions

File tree

client/package-lock.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"test": "vitest run"
1313
},
1414
"dependencies": {
15+
"@radix-ui/react-icons": "^1.3.2",
1516
"react": "^19.2.0",
1617
"react-dom": "^19.2.0"
1718
},

client/src/app/AppShell.tsx

Lines changed: 71 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -357,10 +357,10 @@ export function AppShell({
357357
);
358358
const [selectedUDID, setSelectedUDID] = useState(initialSelectedUDID ?? "");
359359
const [search, setSearch] = useState("");
360-
const [openURLValue, setOpenURLValue] = useState(
360+
const openURLValueRef = useRef(
361361
initialUiState.openURLValue ?? "https://example.com",
362362
);
363-
const [bundleIDValue, setBundleIDValue] = useState(
363+
const bundleIDValueRef = useRef(
364364
initialUiState.bundleIDValue ?? "com.apple.Preferences",
365365
);
366366
const [menuOpen, setMenuOpen] = useState(false);
@@ -795,11 +795,11 @@ export function AppShell({
795795
useEffect(() => {
796796
writePersistedUiState((current) => ({
797797
...current,
798-
bundleIDValue,
799-
openURLValue,
798+
bundleIDValue: bundleIDValueRef.current,
799+
openURLValue: openURLValueRef.current,
800800
selectedUDID,
801801
}));
802-
}, [bundleIDValue, openURLValue, selectedUDID]);
802+
}, [selectedUDID]);
803803

804804
useEffect(() => {
805805
if (search && simulators.length > 0 && filteredSimulators.length === 0) {
@@ -851,9 +851,29 @@ export function AppShell({
851851
}, [fixedSimulatorUDID, selectedSimulator, selectedUDID]);
852852

853853
useEffect(() => {
854-
const nextViewportState = selectedSimulator
855-
? viewportStateForUDID(readPersistedUiState(), selectedSimulator.udid)
856-
: DEFAULT_VIEWPORT_STATE;
854+
if (!selectedSimulator) {
855+
setStreamStamp(Date.now());
856+
setChromeProfile(null);
857+
setChromeProfileReady(false);
858+
setLocalError("");
859+
setAccessibilityRoots([]);
860+
setAccessibilitySelectedId("");
861+
setAccessibilityHoveredId(null);
862+
setAccessibilityPickerActive(false);
863+
setAccessibilityError("");
864+
setAccessibilitySource("");
865+
setAccessibilityAvailableSources([]);
866+
accessibilityRequestIdRef.current += 1;
867+
accessibilityLoadingRef.current = false;
868+
setAccessibilityLoading(false);
869+
return;
870+
}
871+
872+
const persistedState = readPersistedUiState();
873+
const nextViewportState = viewportStateForUDID(
874+
persistedState,
875+
selectedSimulator.udid,
876+
);
857877
setStreamStamp(Date.now());
858878
setChromeProfile(null);
859879
setChromeProfileReady(false);
@@ -864,11 +884,8 @@ export function AppShell({
864884
setLocalError("");
865885
setAccessibilityRoots([]);
866886
setAccessibilitySelectedId(
867-
selectedSimulator
868-
? (readPersistedUiState().accessibilitySelectedByUDID?.[
869-
selectedSimulator.udid
870-
] ?? "")
871-
: "",
887+
persistedState.accessibilitySelectedByUDID?.[selectedSimulator.udid] ??
888+
"",
872889
);
873890
setAccessibilityHoveredId(null);
874891
setAccessibilityPickerActive(false);
@@ -927,7 +944,9 @@ export function AppShell({
927944
setAccessibilityAvailableSources(availableSources);
928945
setAccessibilitySource(snapshot.source);
929946
setAccessibilityError(
930-
roots.length === 0 ? (snapshot.fallbackReason ?? "") : "",
947+
roots.length === 0
948+
? userFacingAccessibilityError(snapshot.fallbackReason ?? "")
949+
: "",
931950
);
932951
const nextPreferredSource = nextAccessibilitySourcePreference(
933952
accessibilityPreferredSource,
@@ -946,7 +965,7 @@ export function AppShell({
946965
}
947966
setAccessibilityError(
948967
snapshotError instanceof Error
949-
? snapshotError.message
968+
? userFacingAccessibilityError(snapshotError.message)
950969
: "Failed to load accessibility hierarchy.",
951970
);
952971
setAccessibilityRoots([]);
@@ -1648,7 +1667,7 @@ export function AppShell({
16481667
}
16491668
const nextValue = window.prompt(
16501669
`Open URL on ${selectedSimulator.name}`,
1651-
openURLValue,
1670+
openURLValueRef.current,
16521671
);
16531672
if (nextValue == null) {
16541673
return;
@@ -1657,7 +1676,11 @@ export function AppShell({
16571676
if (!trimmed) {
16581677
return;
16591678
}
1660-
setOpenURLValue(trimmed);
1679+
openURLValueRef.current = trimmed;
1680+
writePersistedUiState((current) => ({
1681+
...current,
1682+
openURLValue: trimmed,
1683+
}));
16611684
setMenuOpen(false);
16621685
void runAction(() =>
16631686
openSimulatorUrl(selectedSimulator.udid, { url: trimmed }),
@@ -1670,7 +1693,7 @@ export function AppShell({
16701693
}
16711694
const nextValue = window.prompt(
16721695
`Launch bundle on ${selectedSimulator.name}`,
1673-
bundleIDValue,
1696+
bundleIDValueRef.current,
16741697
);
16751698
if (nextValue == null) {
16761699
return;
@@ -1679,7 +1702,11 @@ export function AppShell({
16791702
if (!trimmed) {
16801703
return;
16811704
}
1682-
setBundleIDValue(trimmed);
1705+
bundleIDValueRef.current = trimmed;
1706+
writePersistedUiState((current) => ({
1707+
...current,
1708+
bundleIDValue: trimmed,
1709+
}));
16831710
setMenuOpen(false);
16841711
void runAction(() =>
16851712
launchSimulatorBundle(selectedSimulator.udid, { bundleId: trimmed }),
@@ -2014,12 +2041,11 @@ export function AppShell({
20142041
touchOverlayVisible={touchOverlayVisible}
20152042
viewMode={viewMode}
20162043
devtoolsPanel={
2017-
devToolsVisible ? (
2018-
<DevToolsPanel
2019-
onClose={() => setDevToolsVisible(false)}
2020-
selectedSimulator={selectedSimulator}
2021-
/>
2022-
) : null
2044+
<DevToolsPanel
2045+
onClose={() => setDevToolsVisible(false)}
2046+
selectedSimulator={selectedSimulator}
2047+
visible={devToolsVisible}
2048+
/>
20232049
}
20242050
zoomDockRef={handleZoomDockRef}
20252051
zoomAnimating={zoomAnimating}
@@ -2073,6 +2099,26 @@ function friendlyStreamError(
20732099
return friendlyClientError(normalized);
20742100
}
20752101

2102+
function userFacingAccessibilityError(message: string): string {
2103+
const normalized = message.trim();
2104+
if (!normalized) {
2105+
return "";
2106+
}
2107+
2108+
const lower = normalized.toLowerCase();
2109+
if (
2110+
lower.includes("no app inspector found") ||
2111+
lower.includes("no connected websocket inspector found") ||
2112+
lower.includes("no published app inspector found") ||
2113+
lower.includes("no in-app inspector found") ||
2114+
lower.includes("first probe error:")
2115+
) {
2116+
return "";
2117+
}
2118+
2119+
return normalized;
2120+
}
2121+
20762122
function mergeStreamQualityResponse(
20772123
current: StreamConfig,
20782124
response: StreamQualityResponse,

client/src/features/accessibility/AccessibilityInspector.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useEffect, useRef, useState } from "react";
2-
import type { FormEvent } from "react";
2+
import type { CSSProperties, FormEvent } from "react";
33

44
import { sendInspectorRequest } from "../../api/simulators";
55
import type {
@@ -21,6 +21,7 @@ import {
2121
validFrame,
2222
visibleAccessibilityTreeItems,
2323
} from "./accessibilityTree";
24+
import { usePanelPresence } from "../../shared/hooks/usePanelPresence";
2425

2526
interface AccessibilityInspectorProps {
2627
availableSources: AccessibilitySource[];
@@ -70,6 +71,7 @@ export function AccessibilityInspector({
7071
const resizeStateRef = useRef<ResizeState | null>(null);
7172
const panelWidthRef = useRef(panelWidth);
7273
const detailsHeightRef = useRef(detailsHeight);
74+
const { isPresent, panelState } = usePanelPresence(visible);
7375

7476
useEffect(() => {
7577
panelWidthRef.current = panelWidth;
@@ -197,7 +199,7 @@ export function AccessibilityInspector({
197199
});
198200
}, [selectedId]);
199201

200-
if (!visible) {
202+
if (!isPresent) {
201203
return null;
202204
}
203205

@@ -209,7 +211,11 @@ export function AccessibilityInspector({
209211
const sourceOptions = hierarchySourceOptions(availableSources, source);
210212

211213
return (
212-
<aside className="hierarchy-panel" style={{ width: `${panelWidth}px` }}>
214+
<aside
215+
className="hierarchy-panel"
216+
data-state={panelState}
217+
style={{ "--hierarchy-panel-width": `${panelWidth}px` } as CSSProperties}
218+
>
213219
<div className="hierarchy-tools">
214220
<button
215221
aria-label="Pick element from simulator"

0 commit comments

Comments
 (0)