diff --git a/apps/web/src/components/ui/combobox.test.tsx b/apps/web/src/components/ui/combobox.test.tsx
index 7c89366f7..461fde40f 100644
--- a/apps/web/src/components/ui/combobox.test.tsx
+++ b/apps/web/src/components/ui/combobox.test.tsx
@@ -2,7 +2,6 @@
import type { ComboboxOption } from "./combobox";
import { render, screen } from "@testing-library/react";
-import userEvent from "@testing-library/user-event";
import { beforeAll, describe, expect, it } from "vitest";
import { i18n } from "@lingui/core";
import { I18nProvider } from "@lingui/react";
@@ -47,26 +46,6 @@ describe("Combobox", () => {
expect(screen.getAllByText(/Gamma/).length).toBeGreaterThan(0);
});
- it("renders grouped options with group labels", async () => {
- const user = userEvent.setup();
- const groupedOptions: ComboboxOption[] = [
- { value: "alpha", label: "Alpha", group: "Primary" },
- { value: "beta", label: "Beta", group: { value: "secondary", label: "Secondary" } },
- { value: "gamma", label: "Gamma", group: { value: "secondary", label: "Secondary" } },
- ];
-
- wrap();
-
- await user.click(screen.getByRole("combobox"));
-
- expect(screen.getByText("Primary")).toBeInTheDocument();
- expect(screen.getByText("Secondary")).toBeInTheDocument();
- expect(screen.getByText("Alpha")).toBeInTheDocument();
- expect(screen.getByText("Beta")).toBeInTheDocument();
- expect(screen.getByText("Gamma")).toBeInTheDocument();
- expect(document.querySelectorAll("[data-slot=combobox-group]")).toHaveLength(2);
- });
-
it("renders nothing extra when given an empty options array (no crash)", () => {
expect(() => wrap()).not.toThrow();
expect(screen.getByText("Empty")).toBeInTheDocument();
diff --git a/apps/web/src/components/ui/combobox.tsx b/apps/web/src/components/ui/combobox.tsx
index e148b8c00..47f34541f 100644
--- a/apps/web/src/components/ui/combobox.tsx
+++ b/apps/web/src/components/ui/combobox.tsx
@@ -5,13 +5,10 @@ import React from "react";
import { Button } from "@reactive-resume/ui/components/button";
import {
ComboboxClear,
- ComboboxCollection,
ComboboxContent,
ComboboxEmpty,
- ComboboxGroup,
ComboboxInput,
ComboboxItem,
- ComboboxLabel,
ComboboxList,
ComboboxRoot,
ComboboxTrigger,
@@ -28,21 +25,10 @@ type ComboboxOption = {
// Plain-text label used for the collapsed trigger and filtering when `label` is a ReactNode.
// Without it, a JSX label falls back to String(value) (e.g. a raw enum or locale code) in the trigger.
textValue?: string;
- group?: string | ComboboxOptionGroup;
keywords?: string[];
disabled?: boolean;
};
-type ComboboxOptionGroup = {
- value: string;
- label: React.ReactNode;
-};
-
-type GroupedComboboxOption = ComboboxOptionGroup & {
- key: string;
- items: ComboboxOption[];
-};
-
type SingleComboboxProps = {
options: ComboboxOption[];
value?: TValue | null;
@@ -52,7 +38,6 @@ type SingleComboboxProps = {
disabled?: boolean;
showClear?: boolean;
placeholder?: string;
- searchPlaceholder?: string;
emptyMessage?: React.ReactNode;
className?: string;
id?: string;
@@ -69,7 +54,6 @@ type MultiComboboxProps = {
disabled?: boolean;
showClear?: boolean;
placeholder?: string;
- searchPlaceholder?: string;
emptyMessage?: React.ReactNode;
className?: string;
id?: string;
@@ -85,13 +69,6 @@ const listContent = (item: ComboboxOption
);
-const groupedListContent = (group: GroupedComboboxOption) => (
-
- {group.label !== null && group.label !== undefined ? {group.label} : null}
- {listContent}
-
-);
-
function Combobox(props: ComboboxProps) {
const {
options,
@@ -99,7 +76,6 @@ function Combobox(props: ComboboxProps<
disabled = false,
showClear = false,
placeholder,
- searchPlaceholder,
emptyMessage,
className,
id,
@@ -111,40 +87,6 @@ function Combobox(props: ComboboxProps<
const optionMap = React.useMemo(() => new Map(options.map((opt) => [String(opt.value), opt])), [options]);
- const optionGroups = React.useMemo(() => {
- const groups: GroupedComboboxOption[] = [];
- const groupMap = new Map>();
- let ungroupedGroup: GroupedComboboxOption | null = null;
- let hasGroupedOptions = false;
-
- for (const option of options) {
- if (option.group === undefined) {
- if (!ungroupedGroup) {
- ungroupedGroup = { key: "ungrouped", value: "", label: null, items: [] };
- groups.push(ungroupedGroup);
- }
-
- ungroupedGroup.items.push(option);
- continue;
- }
-
- hasGroupedOptions = true;
-
- const group = typeof option.group === "string" ? { value: option.group, label: option.group } : option.group;
- let optionGroup = groupMap.get(group.value);
-
- if (!optionGroup) {
- optionGroup = { ...group, key: `group:${group.value}`, items: [] };
- groupMap.set(group.value, optionGroup);
- groups.push(optionGroup);
- }
-
- optionGroup.items.push(option);
- }
-
- return hasGroupedOptions ? groups : null;
- }, [options]);
-
const findOption = React.useCallback(
(v: TValue | TValue[] | null | undefined) => {
if (multiple) {
@@ -238,7 +180,7 @@ function Combobox(props: ComboboxProps<
return (
[] & ComboboxOption}
@@ -265,11 +207,11 @@ function Combobox(props: ComboboxProps<
}
/>
{emptyMessage ?? t`No results found.`}
- {optionGroups ? groupedListContent : listContent}
+ {listContent}
);
diff --git a/apps/web/src/hooks/use-form-blocker.tsx b/apps/web/src/hooks/use-form-blocker.tsx
index 5aa2fd0ee..b9c0621e2 100644
--- a/apps/web/src/hooks/use-form-blocker.tsx
+++ b/apps/web/src/hooks/use-form-blocker.tsx
@@ -1,3 +1,4 @@
+import type { AnyFormApi } from "@tanstack/react-form";
import { t } from "@lingui/core/macro";
import { useStore } from "@tanstack/react-form";
import { useCallback, useEffect, useRef } from "react";
@@ -8,29 +9,7 @@ interface UseFormBlockerOptions {
shouldBlock?: () => boolean;
}
-type BlockableFormStore = {
- get: () => {
- isDirty: boolean;
- isSubmitting: boolean;
- };
- subscribe: {
- (observer: {
- next?: (value: { isDirty: boolean; isSubmitting: boolean }) => void;
- error?: (error: unknown) => void;
- complete?: () => void;
- }): { unsubscribe: () => void };
- (
- next: (value: { isDirty: boolean; isSubmitting: boolean }) => void,
- error?: (error: unknown) => void,
- complete?: () => void,
- ): { unsubscribe: () => void };
- };
-};
-
-export function useFormBlocker(
- form: { store: TStore },
- options?: UseFormBlockerOptions,
-) {
+export function useFormBlocker(form: Pick, options?: UseFormBlockerOptions) {
const confirm = useConfirm();
const closeDialog = useDialogStore((state) => state.closeDialog);
const setOnBeforeClose = useDialogStore((state) => state.setOnBeforeClose);
diff --git a/apps/web/src/libs/query/client.test.ts b/apps/web/src/libs/query/client.test.ts
index ddff476df..ea4aecfa0 100644
--- a/apps/web/src/libs/query/client.test.ts
+++ b/apps/web/src/libs/query/client.test.ts
@@ -29,21 +29,4 @@ describe("getQueryClient", () => {
// json/meta envelope is included
expect(hashA).toContain('"json"');
});
-
- it("round-trips data through dehydrate/hydrate via oRPC serializer", () => {
- const client = getQueryClient();
- const serializeData = client.getDefaultOptions().dehydrate?.serializeData;
- const deserializeData = client.getDefaultOptions().hydrate?.deserializeData;
-
- expect(serializeData).toBeTypeOf("function");
- expect(deserializeData).toBeTypeOf("function");
-
- const original = { id: "x", count: 3, when: new Date("2024-01-01T00:00:00Z") };
- const serialized = serializeData?.(original);
- const restored = deserializeData?.(serialized) as typeof original;
-
- expect(restored.id).toBe(original.id);
- expect(restored.count).toBe(original.count);
- expect(restored.when.getTime()).toBe(original.when.getTime());
- });
});
diff --git a/apps/web/src/libs/query/client.ts b/apps/web/src/libs/query/client.ts
index d72e33dfb..f00b1c007 100644
--- a/apps/web/src/libs/query/client.ts
+++ b/apps/web/src/libs/query/client.ts
@@ -14,17 +14,6 @@ export const getQueryClient = () => {
return JSON.stringify({ json, meta });
},
},
- dehydrate: {
- serializeData(data) {
- const [json, meta] = serializer.serialize(data);
- return { json, meta };
- },
- },
- hydrate: {
- deserializeData(data) {
- return serializer.deserialize(data.json, data.meta);
- },
- },
},
mutationCache: new MutationCache({
onSettled: (_1, _2, _3, _4, _5, context) => {
diff --git a/packages/ui/src/components/combobox.test.tsx b/packages/ui/src/components/combobox.test.tsx
index 5ea6c4b52..33a9e4c56 100644
--- a/packages/ui/src/components/combobox.test.tsx
+++ b/packages/ui/src/components/combobox.test.tsx
@@ -3,13 +3,10 @@ import { describe, expect, it } from "vitest";
import {
ComboboxChips,
ComboboxChipsInput,
- ComboboxCollection,
ComboboxContent,
ComboboxEmpty,
- ComboboxGroup,
ComboboxInput,
ComboboxItem,
- ComboboxLabel,
ComboboxList,
ComboboxRoot,
ComboboxSeparator,
@@ -74,29 +71,11 @@ describe("ComboboxItem", () => {
});
});
-describe("ComboboxList / ComboboxGroup / ComboboxLabel", () => {
+describe("ComboboxList", () => {
it("ComboboxList renders with data-slot='combobox-list'", () => {
renderCombobox({ open: true });
expect(document.querySelector("[data-slot=combobox-list]")).toBeInTheDocument();
});
-
- it("ComboboxGroup and ComboboxLabel render with their slots", () => {
- render(
-
-
-
-
-
- Fruits
- Apple
-
-
-
- ,
- );
- expect(document.querySelector("[data-slot=combobox-group]")).toBeInTheDocument();
- expect(document.querySelector("[data-slot=combobox-label]")).toBeInTheDocument();
- });
});
describe("ComboboxSeparator and ComboboxEmpty", () => {
@@ -129,29 +108,6 @@ describe("ComboboxSeparator and ComboboxEmpty", () => {
});
});
-describe("ComboboxCollection", () => {
- it("renders without throwing", () => {
- expect(() =>
- render(
-
-
-
-
-
- {(item) => (
-
- {item}
-
- )}
-
-
-
- ,
- ),
- ).not.toThrow();
- });
-});
-
describe("ComboboxClear", () => {
it("renders inside ComboboxInput when showClear=true", () => {
const { container } = render(
diff --git a/packages/ui/src/components/combobox.tsx b/packages/ui/src/components/combobox.tsx
index a0d8c743c..b46668873 100644
--- a/packages/ui/src/components/combobox.tsx
+++ b/packages/ui/src/components/combobox.tsx
@@ -7,7 +7,7 @@ import {
InputGroupButton,
InputGroupInput,
} from "@reactive-resume/ui/components/input-group";
-import { menuLabelClassName, menuSeparatorClassName } from "@reactive-resume/ui/components/menu-styles";
+import { menuSeparatorClassName } from "@reactive-resume/ui/components/menu-styles";
import { cn } from "@reactive-resume/utils/style";
const ComboboxRoot = ComboboxPrimitive.Root;
@@ -145,20 +145,6 @@ function ComboboxItem({ className, children, ...props }: ComboboxPrimitive.Item.
);
}
-function ComboboxGroup({ className, ...props }: ComboboxPrimitive.Group.Props) {
- return ;
-}
-
-function ComboboxLabel({ className, ...props }: ComboboxPrimitive.GroupLabel.Props) {
- return (
-
- );
-}
-
-function ComboboxCollection({ ...props }: ComboboxPrimitive.Collection.Props) {
- return ;
-}
-
function ComboboxEmpty({ className, ...props }: ComboboxPrimitive.Empty.Props) {
return (