fix(builder): preserve explicit HTTP URLs (#3403)

This commit is contained in:
Amruth Pillai
2026-09-05 07:29:20 -07:00
committed by GitHub
parent 00a1357deb
commit 2cbb0f63e7
2 changed files with 46 additions and 7 deletions
@@ -56,6 +56,43 @@ describe("URLInput", () => {
});
});
it.each(["http://other.example/path", "HTTP://other.example/path"])(
"preserves an explicitly pasted HTTP URL: %s",
(url) => {
const onChange = vi.fn();
renderInput({ url: "https://example.com", label: "Company" }, onChange);
fireEvent.change(screen.getByRole("textbox"), { target: { value: url } });
expect(onChange).toHaveBeenCalledWith({ url, label: "Company" });
},
);
it("shows an existing HTTP URL with its matching prefix", () => {
renderInput({ url: "http://example.com/path", label: "" });
expect((screen.getByRole("textbox") as HTMLInputElement).value).toBe("example.com/path");
expect(screen.getByText("http://")).toBeDefined();
});
it("preserves HTTP while editing the host or path", () => {
const onChange = vi.fn();
renderInput({ url: "http://example.com/path", label: "Company" }, onChange);
fireEvent.change(screen.getByRole("textbox"), { target: { value: "example.com/new-path" } });
expect(onChange).toHaveBeenCalledWith({ url: "http://example.com/new-path", label: "Company" });
});
it("allows switching an existing HTTP URL to HTTPS by pasting", () => {
const onChange = vi.fn();
renderInput({ url: "http://example.com", label: "" }, onChange);
fireEvent.change(screen.getByRole("textbox"), { target: { value: "https://example.com" } });
expect(onChange).toHaveBeenCalledWith({ url: "https://example.com", label: "" });
});
it("emits an empty url string when cleared", () => {
const onChange = vi.fn();
renderInput({ url: "https://example.com", label: "" }, onChange);
+9 -7
View File
@@ -15,15 +15,16 @@ import { Label } from "@reactive-resume/ui/components/label";
import { Popover, PopoverContent, PopoverTrigger } from "@reactive-resume/ui/components/popover";
import { cn } from "@reactive-resume/utils/style";
const PREFIX = "https://";
const DEFAULT_PREFIX = "https://";
const HTTP_PREFIX = /^https?:\/\//i;
function stripPrefix(url: string) {
return url.startsWith(PREFIX) ? url.slice(PREFIX.length) : url;
return url.replace(HTTP_PREFIX, "");
}
function ensurePrefix(url: string) {
function ensurePrefix(url: string, prefix: string) {
if (url === "") return "";
return url.startsWith(PREFIX) ? url : PREFIX + url;
return HTTP_PREFIX.test(url) ? url : prefix + url;
}
type Props<TValue extends Website = Website> = Omit<React.ComponentProps<"input">, "value" | "onChange"> & {
@@ -33,14 +34,15 @@ type Props<TValue extends Website = Website> = Omit<React.ComponentProps<"input"
};
export function URLInput<TValue extends Website>({ value, onChange, hideLabelButton, ...props }: Props<TValue>) {
const prefix = value.url.match(HTTP_PREFIX)?.[0] ?? DEFAULT_PREFIX;
const handleUrlChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
onChange({
...value,
url: ensurePrefix(e.target.value),
url: ensurePrefix(e.target.value, prefix),
});
},
[onChange, value],
[onChange, value, prefix],
);
const handleLabelChange = useCallback(
@@ -55,7 +57,7 @@ export function URLInput<TValue extends Website>({ value, onChange, hideLabelBut
return (
<InputGroup>
<InputGroupAddon align="inline-start">
<InputGroupText>{PREFIX}</InputGroupText>
<InputGroupText>{prefix}</InputGroupText>
</InputGroupAddon>
<InputGroupInput