use vite+

This commit is contained in:
Amruth Pillai
2026-03-18 22:03:24 +01:00
parent d1dac8aeca
commit 192880e416
427 changed files with 58915 additions and 58759 deletions
+67 -67
View File
@@ -1,99 +1,99 @@
import * as React from "react";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { cn } from "@/utils/style";
interface ConfirmOptions {
description?: string;
confirmText?: string;
cancelText?: string;
description?: string;
confirmText?: string;
cancelText?: string;
}
interface ConfirmState extends ConfirmOptions {
open: boolean;
title: string;
resolve: ((value: boolean) => void) | null;
open: boolean;
title: string;
resolve: ((value: boolean) => void) | null;
}
type ConfirmContextType = {
confirm: (title: string, options?: ConfirmOptions) => Promise<boolean>;
confirm: (title: string, options?: ConfirmOptions) => Promise<boolean>;
};
const ConfirmContext = React.createContext<ConfirmContextType | null>(null);
export function ConfirmDialogProvider({ children }: { children: React.ReactNode }) {
const [state, setState] = React.useState<ConfirmState>({
open: false,
resolve: null,
title: "",
description: undefined,
confirmText: undefined,
cancelText: undefined,
});
const [state, setState] = React.useState<ConfirmState>({
open: false,
resolve: null,
title: "",
description: undefined,
confirmText: undefined,
cancelText: undefined,
});
const confirm = React.useCallback(async (title: string, options?: ConfirmOptions): Promise<boolean> => {
return new Promise<boolean>((resolve) => {
setState({
open: true,
resolve,
title,
description: options?.description,
confirmText: options?.confirmText,
cancelText: options?.cancelText,
});
});
}, []);
const confirm = React.useCallback(async (title: string, options?: ConfirmOptions): Promise<boolean> => {
return new Promise<boolean>((resolve) => {
setState({
open: true,
resolve,
title,
description: options?.description,
confirmText: options?.confirmText,
cancelText: options?.cancelText,
});
});
}, []);
const handleConfirm = React.useCallback(() => {
if (state.resolve) state.resolve(true);
const handleConfirm = React.useCallback(() => {
if (state.resolve) state.resolve(true);
setState((prev) => ({ ...prev, open: false, resolve: null }));
}, [state.resolve]);
setState((prev) => ({ ...prev, open: false, resolve: null }));
}, [state.resolve]);
const handleCancel = React.useCallback(() => {
if (state.resolve) state.resolve(false);
const handleCancel = React.useCallback(() => {
if (state.resolve) state.resolve(false);
setState((prev) => ({ ...prev, open: false, resolve: null }));
}, [state.resolve]);
setState((prev) => ({ ...prev, open: false, resolve: null }));
}, [state.resolve]);
return (
<ConfirmContext.Provider value={{ confirm }}>
{children}
return (
<ConfirmContext.Provider value={{ confirm }}>
{children}
<AlertDialog open={state.open} onOpenChange={(open) => !open && handleCancel()}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{state.title}</AlertDialogTitle>
<AlertDialogDescription className={cn(!state.description && "sr-only")}>
{state.description}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialog open={state.open} onOpenChange={(open) => !open && handleCancel()}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{state.title}</AlertDialogTitle>
<AlertDialogDescription className={cn(!state.description && "sr-only")}>
{state.description}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel onClick={handleCancel}>{state.cancelText ?? "Cancel"}</AlertDialogCancel>
<AlertDialogAction onClick={handleConfirm}>{state.confirmText ?? "Confirm"}</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</ConfirmContext.Provider>
);
<AlertDialogFooter>
<AlertDialogCancel onClick={handleCancel}>{state.cancelText ?? "Cancel"}</AlertDialogCancel>
<AlertDialogAction onClick={handleConfirm}>{state.confirmText ?? "Confirm"}</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</ConfirmContext.Provider>
);
}
export function useConfirm() {
const context = React.useContext(ConfirmContext);
const context = React.useContext(ConfirmContext);
if (!context) {
throw new Error("useConfirm must be used within a <ConfirmDialogProvider />.");
}
if (!context) {
throw new Error("useConfirm must be used within a <ConfirmDialogProvider />.");
}
return context.confirm;
return context.confirm;
}
+17 -17
View File
@@ -1,32 +1,32 @@
import { useCallback, useEffect, useState } from "react";
interface CommonControlledStateProps<T> {
value?: T;
defaultValue?: T;
value?: T;
defaultValue?: T;
}
type UseControlledStateProps<T, Rest extends any[] = []> = CommonControlledStateProps<T> & {
onChange?: (value: T, ...args: Rest) => void;
onChange?: (value: T, ...args: Rest) => void;
};
export function useControlledState<T, Rest extends any[] = []>(
props: UseControlledStateProps<T, Rest>,
props: UseControlledStateProps<T, Rest>,
): readonly [T, (next: T, ...args: Rest) => void] {
const { value, defaultValue, onChange } = props;
const { value, defaultValue, onChange } = props;
const [state, setInternalState] = useState<T>(value !== undefined ? value : (defaultValue as T));
const [state, setInternalState] = useState<T>(value !== undefined ? value : (defaultValue as T));
useEffect(() => {
if (value !== undefined) setInternalState(value);
}, [value]);
useEffect(() => {
if (value !== undefined) setInternalState(value);
}, [value]);
const setState = useCallback(
(next: T, ...args: Rest) => {
setInternalState(next);
onChange?.(next, ...args);
},
[onChange],
);
const setState = useCallback(
(next: T, ...args: Rest) => {
setInternalState(next);
onChange?.(next, ...args);
},
[onChange],
);
return [state, setState] as const;
return [state, setState] as const;
}
+44 -44
View File
@@ -1,63 +1,63 @@
import type { FieldValues, UseFormReturn } from "react-hook-form";
import { t } from "@lingui/core/macro";
import React, { useCallback } from "react";
import { useCallback } from "react";
import { useDialogStore } from "@/dialogs/store";
import { useConfirm } from "@/hooks/use-confirm";
interface UseFormBlockerOptions {
shouldBlock?: () => boolean;
shouldBlock?: () => boolean;
}
export function useFormBlocker<T extends FieldValues>(form: UseFormReturn<T>, options?: UseFormBlockerOptions) {
const confirm = useConfirm();
const closeDialog = useDialogStore((state) => state.closeDialog);
const confirm = useConfirm();
const closeDialog = useDialogStore((state) => state.closeDialog);
// Subscribe to formState changes by reading during render (react-hook-form requirement)
const { isDirty, isSubmitting } = form.formState;
// Subscribe to formState changes by reading during render (react-hook-form requirement)
const { isDirty, isSubmitting } = form.formState;
const shouldBlock = useCallback(() => {
// Use custom shouldBlock if provided, otherwise use default form state check
if (options?.shouldBlock) return options.shouldBlock();
return isDirty && !isSubmitting;
}, [options, isDirty, isSubmitting]);
const shouldBlock = useCallback(() => {
// Use custom shouldBlock if provided, otherwise use default form state check
if (options?.shouldBlock) return options.shouldBlock();
return isDirty && !isSubmitting;
}, [options, isDirty, isSubmitting]);
const requestClose = useCallback(async () => {
if (!shouldBlock()) {
closeDialog();
return;
}
const requestClose = useCallback(async () => {
if (!shouldBlock()) {
closeDialog();
return;
}
const confirmed = await confirm(t`Are you sure you want to close this dialog?`, {
description: t`You have unsaved changes that will be lost.`,
confirmText: t`Leave`,
cancelText: t`Stay`,
});
const confirmed = await confirm(t`Are you sure you want to close this dialog?`, {
description: t`You have unsaved changes that will be lost.`,
confirmText: t`Leave`,
cancelText: t`Stay`,
});
if (confirmed) closeDialog();
}, [shouldBlock, closeDialog, confirm]);
if (confirmed) closeDialog();
}, [shouldBlock, closeDialog, confirm]);
const blockEvents = {
onEscapeKeyDown: (event: KeyboardEvent) => {
if (shouldBlock()) {
event.preventDefault();
void requestClose();
}
},
onPointerDownOutside: (event: Event) => {
if (shouldBlock()) {
event.preventDefault();
void requestClose();
}
},
onInteractOutside: (event: Event) => {
if (shouldBlock()) {
event.preventDefault();
void requestClose();
}
},
};
const blockEvents = {
onEscapeKeyDown: (event: KeyboardEvent) => {
if (shouldBlock()) {
event.preventDefault();
void requestClose();
}
},
onPointerDownOutside: (event: Event) => {
if (shouldBlock()) {
event.preventDefault();
void requestClose();
}
},
onInteractOutside: (event: Event) => {
if (shouldBlock()) {
event.preventDefault();
void requestClose();
}
},
};
return { requestClose, blockEvents };
return { requestClose, blockEvents };
}
+11 -11
View File
@@ -4,17 +4,17 @@ const MOBILE_BREAKPOINT = 768;
const MOBILE_QUERY = `(max-width: ${MOBILE_BREAKPOINT - 1}px)`;
export function useIsMobile() {
const [isMobile, setIsMobile] = useState<boolean | undefined>(undefined);
const [isMobile, setIsMobile] = useState<boolean | undefined>(undefined);
useEffect(() => {
const mql = window.matchMedia(MOBILE_QUERY);
const onChange = (e: MediaQueryListEvent) => {
setIsMobile(e.matches);
};
mql.addEventListener("change", onChange);
setIsMobile(mql.matches);
return () => mql.removeEventListener("change", onChange);
}, []);
useEffect(() => {
const mql = window.matchMedia(MOBILE_QUERY);
const onChange = (e: MediaQueryListEvent) => {
setIsMobile(e.matches);
};
mql.addEventListener("change", onChange);
setIsMobile(mql.matches);
return () => mql.removeEventListener("change", onChange);
}, []);
return !!isMobile;
return !!isMobile;
}
+102 -102
View File
@@ -2,142 +2,142 @@ import { t } from "@lingui/core/macro";
import * as React from "react";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { Input } from "@/components/ui/input";
import { cn } from "@/utils/style";
type PromptOptions = {
description?: string;
defaultValue?: string;
confirmText?: string;
cancelText?: string;
inputProps?: Omit<React.ComponentProps<typeof Input>, "value" | "onChange" | "onKeyDown">;
description?: string;
defaultValue?: string;
confirmText?: string;
cancelText?: string;
inputProps?: Omit<React.ComponentProps<typeof Input>, "value" | "onChange" | "onKeyDown">;
};
type PromptState = PromptOptions & {
open: boolean;
title: string;
value: string;
resolve: ((value: string | null) => void) | null;
open: boolean;
title: string;
value: string;
resolve: ((value: string | null) => void) | null;
};
type PromptContextType = {
prompt: (title: string, options?: PromptOptions) => Promise<string | null>;
prompt: (title: string, options?: PromptOptions) => Promise<string | null>;
};
const PromptContext = React.createContext<PromptContextType | null>(null);
export function PromptDialogProvider({ children }: { children: React.ReactNode }) {
const inputRef = React.useRef<HTMLInputElement>(null);
const inputRef = React.useRef<HTMLInputElement>(null);
const [state, setState] = React.useState<PromptState>({
open: false,
resolve: null,
title: "",
value: "",
description: undefined,
defaultValue: undefined,
confirmText: undefined,
cancelText: undefined,
inputProps: undefined,
});
const [state, setState] = React.useState<PromptState>({
open: false,
resolve: null,
title: "",
value: "",
description: undefined,
defaultValue: undefined,
confirmText: undefined,
cancelText: undefined,
inputProps: undefined,
});
const cancelText = state.cancelText ?? t`Cancel`;
const confirmText = state.confirmText ?? t`Confirm`;
const cancelText = state.cancelText ?? t`Cancel`;
const confirmText = state.confirmText ?? t`Confirm`;
React.useEffect(() => {
if (!state.open) return;
React.useEffect(() => {
if (!state.open) return;
setTimeout(() => {
if (!inputRef.current) return;
inputRef.current.focus();
}, 0);
}, [state.open]);
setTimeout(() => {
if (!inputRef.current) return;
inputRef.current.focus();
}, 0);
}, [state.open]);
const prompt = React.useCallback(async (title: string, options?: PromptOptions): Promise<string | null> => {
return new Promise<string | null>((resolve) => {
setState({
open: true,
resolve,
title,
value: options?.defaultValue ?? "",
description: options?.description,
defaultValue: options?.defaultValue,
confirmText: options?.confirmText,
cancelText: options?.cancelText,
inputProps: options?.inputProps,
});
});
}, []);
const prompt = React.useCallback(async (title: string, options?: PromptOptions): Promise<string | null> => {
return new Promise<string | null>((resolve) => {
setState({
open: true,
resolve,
title,
value: options?.defaultValue ?? "",
description: options?.description,
defaultValue: options?.defaultValue,
confirmText: options?.confirmText,
cancelText: options?.cancelText,
inputProps: options?.inputProps,
});
});
}, []);
const handleConfirm = React.useCallback(() => {
if (state.resolve) state.resolve(state.value);
const handleConfirm = React.useCallback(() => {
if (state.resolve) state.resolve(state.value);
setState((prev) => ({ ...prev, open: false, resolve: null }));
}, [state.resolve, state.value]);
setState((prev) => ({ ...prev, open: false, resolve: null }));
}, [state.resolve, state.value]);
const handleCancel = React.useCallback(() => {
if (state.resolve) state.resolve(null);
const handleCancel = React.useCallback(() => {
if (state.resolve) state.resolve(null);
setState((prev) => ({ ...prev, open: false, resolve: null }));
}, [state.resolve]);
setState((prev) => ({ ...prev, open: false, resolve: null }));
}, [state.resolve]);
const handleValueChange = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
setState((prev) => ({ ...prev, value: e.target.value }));
}, []);
const handleValueChange = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
setState((prev) => ({ ...prev, value: e.target.value }));
}, []);
const handleKeyDown = React.useCallback(
(e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") handleConfirm();
},
[handleConfirm],
);
const handleKeyDown = React.useCallback(
(e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") handleConfirm();
},
[handleConfirm],
);
return (
<PromptContext.Provider value={{ prompt }}>
{children}
return (
<PromptContext.Provider value={{ prompt }}>
{children}
<AlertDialog open={state.open} onOpenChange={(open) => !open && handleCancel()}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{state.title}</AlertDialogTitle>
<AlertDialogDescription className={cn(!state.description && "sr-only")}>
{state.description}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialog open={state.open} onOpenChange={(open) => !open && handleCancel()}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{state.title}</AlertDialogTitle>
<AlertDialogDescription className={cn(!state.description && "sr-only")}>
{state.description}
</AlertDialogDescription>
</AlertDialogHeader>
<Input
ref={inputRef}
value={state.value}
onKeyDown={handleKeyDown}
onChange={handleValueChange}
{...state.inputProps}
/>
<Input
ref={inputRef}
value={state.value}
onKeyDown={handleKeyDown}
onChange={handleValueChange}
{...state.inputProps}
/>
<AlertDialogFooter>
<AlertDialogCancel onClick={handleCancel}>{cancelText}</AlertDialogCancel>
<AlertDialogAction onClick={handleConfirm}>{confirmText}</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</PromptContext.Provider>
);
<AlertDialogFooter>
<AlertDialogCancel onClick={handleCancel}>{cancelText}</AlertDialogCancel>
<AlertDialogAction onClick={handleConfirm}>{confirmText}</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</PromptContext.Provider>
);
}
export function usePrompt() {
const context = React.useContext(PromptContext);
const context = React.useContext(PromptContext);
if (!context) {
throw new Error("usePrompt must be used within a <PromptDialogProvider />.");
}
if (!context) {
throw new Error("usePrompt must be used within a <PromptDialogProvider />.");
}
return context.prompt;
return context.prompt;
}