Files
stack/apps/web/src/components/ui/select.tsx
Jason Woltje ac1f2c176f
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
fix: Resolve all ESLint errors and warnings in web package
Fixes all 542 ESLint problems in the web package to achieve 0 errors and 0 warnings.

Changes:
- Fixed 144 issues: nullish coalescing, return types, unused variables
- Fixed 118 issues: unnecessary conditions, type safety, template literals
- Fixed 79 issues: non-null assertions, unsafe assignments, empty functions
- Fixed 67 issues: explicit return types, promise handling, enum comparisons
- Fixed 45 final warnings: missing return types, optional chains
- Fixed 25 typecheck-related issues: async/await, type assertions, formatting
- Fixed JSX.Element namespace errors across 90+ files

All Quality Rails violations resolved. Lint and typecheck both pass with 0 problems.

Files modified: 118 components, tests, hooks, and utilities

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-31 00:10:03 -06:00

131 lines
3.0 KiB
TypeScript

import * as React from "react";
export interface SelectProps {
value?: string;
onValueChange?: (value: string) => void;
defaultValue?: string;
disabled?: boolean;
children?: React.ReactNode;
}
export interface SelectTriggerProps {
id?: string;
className?: string;
children?: React.ReactNode;
}
export interface SelectContentProps {
children?: React.ReactNode;
}
export interface SelectItemProps {
value: string;
children?: React.ReactNode;
}
export interface SelectValueProps {
placeholder?: string;
}
const SelectContext = React.createContext<{
value?: string;
onValueChange?: (value: string) => void;
isOpen: boolean;
setIsOpen: (open: boolean) => void;
}>({
isOpen: false,
setIsOpen: () => {
// Default no-op
},
});
export function Select({
value,
onValueChange,
defaultValue,
children,
}: SelectProps): React.JSX.Element {
const [isOpen, setIsOpen] = React.useState(false);
const [internalValue, setInternalValue] = React.useState(defaultValue);
const currentValue = value ?? internalValue;
const handleValueChange = (newValue: string): void => {
if (value === undefined) {
setInternalValue(newValue);
}
onValueChange?.(newValue);
setIsOpen(false);
};
const contextValue: {
value?: string;
onValueChange?: (value: string) => void;
isOpen: boolean;
setIsOpen: (open: boolean) => void;
} = { isOpen, setIsOpen };
if (currentValue !== undefined) {
contextValue.value = currentValue;
}
contextValue.onValueChange = handleValueChange;
return (
<SelectContext.Provider value={contextValue}>
<div className="relative">{children}</div>
</SelectContext.Provider>
);
}
export function SelectTrigger({
id,
className = "",
children,
}: SelectTriggerProps): React.JSX.Element {
const { isOpen, setIsOpen } = React.useContext(SelectContext);
return (
<button
id={id}
type="button"
onClick={() => {
setIsOpen(!isOpen);
}}
className={`flex h-10 w-full items-center justify-between rounded-md border border-gray-300 bg-white px-3 py-2 text-sm ${className}`}
>
{children}
</button>
);
}
export function SelectValue({ placeholder }: SelectValueProps): React.JSX.Element {
const { value } = React.useContext(SelectContext);
return <span>{value ?? placeholder}</span>;
}
export function SelectContent({ children }: SelectContentProps): React.JSX.Element | null {
const { isOpen } = React.useContext(SelectContext);
if (!isOpen) return null;
return (
<div className="absolute z-50 mt-1 max-h-60 w-full overflow-auto rounded-md border border-gray-300 bg-white shadow-lg">
{children}
</div>
);
}
export function SelectItem({ value, children }: SelectItemProps): React.JSX.Element {
const { onValueChange } = React.useContext(SelectContext);
return (
<div
onClick={() => onValueChange?.(value)}
className="cursor-pointer px-3 py-2 text-sm hover:bg-gray-100"
>
{children}
</div>
);
}