Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix UrlSelect trigger value reset for non expo router projects #873

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions packages/vscode-extension/src/webview/components/UrlBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useProject } from "../providers/ProjectProvider";
import UrlSelect, { UrlItem } from "./UrlSelect";
import { IconButtonWithOptions } from "./IconButtonWithOptions";
import IconButton from "./shared/IconButton";
import { useDependencies } from "../providers/DependenciesProvider";

function ReloadButton({ disabled }: { disabled: boolean }) {
const { project } = useProject();
Expand All @@ -29,6 +30,7 @@ function ReloadButton({ disabled }: { disabled: boolean }) {

function UrlBar({ disabled }: { disabled?: boolean }) {
const { project, projectState } = useProject();
const { dependencies } = useDependencies();

const MAX_URL_HISTORY_SIZE = 20;
const MAX_RECENT_URL_SIZE = 5;
Expand All @@ -37,6 +39,8 @@ function UrlBar({ disabled }: { disabled?: boolean }) {
const [urlList, setUrlList] = useState<UrlItem[]>([]);
const [recentUrlList, setRecentUrlList] = useState<UrlItem[]>([]);
const [urlHistory, setUrlHistory] = useState<string[]>([]);
const [urlSelectKey, setUrlSelectKey] = useState<number>(0);
const [urlSelectValue, setUrlSelectValue] = useState<string>(urlList[0]?.id);

useEffect(() => {
function moveAsMostRecent(urls: UrlItem[], newUrl: UrlItem) {
Expand Down Expand Up @@ -76,10 +80,13 @@ function UrlBar({ disabled }: { disabled?: boolean }) {
}, [recentUrlList, urlHistory, backNavigationPath]);

const sortedUrlList = useMemo(() => {
return [...urlList].sort((a, b) => a.name.localeCompare(b.name));
const sorted = [...urlList].sort((a, b) => a.name.localeCompare(b.name));
setUrlSelectValue(urlList[0]?.id);
return sorted;
}, [urlList]);

const disabledAlsoWhenStarting = disabled || projectState.status === "starting";
const isExpoRouterProject = !dependencies.expoRouter?.isOptional;

return (
<>
Expand All @@ -88,7 +95,7 @@ function UrlBar({ disabled }: { disabled?: boolean }) {
label: "Go back",
side: "bottom",
}}
disabled={disabledAlsoWhenStarting || urlHistory.length < 2}
disabled={disabledAlsoWhenStarting || !isExpoRouterProject || urlHistory.length < 2}
onClick={() => {
setUrlHistory((prevUrlHistory) => {
const newUrlHistory = prevUrlHistory.slice(1);
Expand All @@ -103,6 +110,12 @@ function UrlBar({ disabled }: { disabled?: boolean }) {
<IconButton
onClick={() => {
project.goHome("/{}");
if (!isExpoRouterProject) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this being placed as a dependency of a user action as we'll have to remember to update it every time we add a new navigation option I would much rather have wrapper.js send an event every time application is loaded and then some global logic would handle setting the correct navigation state to the url bar.

Having said that I think we should move most of the logic in this file to the extension code to allow passing state between diffrent panel locations any wayand my suggestion will be easier to active then.

// this sets the trigger value of UrlSelect to a placeholder,
// forcing the Radix Select component to fully re-render
setUrlSelectKey(urlSelectKey + 1);
setUrlSelectValue("");
}
}}
tooltip={{
label: "Go to main screen",
Expand All @@ -117,8 +130,9 @@ function UrlBar({ disabled }: { disabled?: boolean }) {
}}
recentItems={recentUrlList}
items={sortedUrlList}
value={urlList[0]?.id}
disabled={disabledAlsoWhenStarting || urlList.length < 2}
key={urlSelectKey}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setting this here is enough to re-mount the whole component. It doesn't have to be accessed in the underlying component

value={urlSelectValue}
disabled={disabledAlsoWhenStarting || urlList.length < (isExpoRouterProject ? 2 : 1)}
/>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@ const SelectItem = React.forwardRef<HTMLDivElement, PropsWithChildren<Select.Sel
);

interface UrlSelectProps {
key: number;
value: string;
onValueChange: (newValue: string) => void;
recentItems: UrlItem[];
items: UrlItem[];
disabled?: boolean;
}

function UrlSelect({ onValueChange, recentItems, items, value, disabled }: UrlSelectProps) {
function UrlSelect({ onValueChange, recentItems, items, key, value, disabled }: UrlSelectProps) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that it only has been added in React 19 that you can receive key prop like this. I don't think in the current version in propagates down to the component

// We use two lists for URL selection: one with recently used URLs and another
// with all available URLs. Since recentItems is a subset of items, each recentItems's
// value is prefixed to differentiate their origins when presented in the Select
Expand All @@ -35,7 +36,7 @@ function UrlSelect({ onValueChange, recentItems, items, value, disabled }: UrlSe
};

return (
<Select.Root onValueChange={handleValueChange} value={value} disabled={disabled}>
<Select.Root onValueChange={handleValueChange} key={key} value={value} disabled={disabled}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be enough to do something along these lines, instead of having the whole logic for urlSelectKey in the parent component:

<Select.root key={value ? "has-value : "no-value"}>

<Select.Trigger className="url-select-trigger">
<Select.Value placeholder="/" aria-label={value} />
</Select.Trigger>
Expand Down
Loading