CustomSelect Component
Relevant source files
The following files were used as context for generating this wiki page:The CustomSelect component is a reusable, custom-styled dropdown menu built with React and TypeScript. It is designed to replace the native browser <select> element to provide a consistent, dark-themed user interface that aligns with the application's overall aesthetic. It is used throughout the application, notably in the main controls panel for selecting the AI model and image aspect ratio, making it a fundamental part of the user's configuration experience.
Sources: components/CustomSelect.tsx, App.tsx:550-593
Component API & Props
The component's behavior and appearance are controlled through a set of props defined in its interface.
Sources: components/CustomSelect.tsx:12-18
| Prop | Type | Description |
|---|---|---|
label | string | The text label displayed above the select input. |
value | string | The currently selected value. Must correspond to an option.value. |
onChange | (value: string) => void | A callback function that is executed when a new option is selected. It receives the new value as an argument. |
options | Option[] | An array of objects, where each object has a value and label property. |
icon | React.ReactNode | (Optional) A React node (typically an icon) to display inside the select button before the label. |
headerContent | React.ReactNode | (Optional) A React node to display on the right side of the label, often used for supplementary controls. |
The Option interface is a simple key-value pair structure.
// From components/CustomSelect.tsx
interface Option {
value: string;
label: string;
}
Sources: components/CustomSelect.tsx:5-8
Internal State and Logic
The component manages its open/closed state internally using a React useState hook. It also utilizes a useRef and a useEffect hook to detect clicks outside of the component, allowing it to automatically close the dropdown menu.
Sources: components/CustomSelect.tsx:20-34
State Management Flow
The following diagram illustrates how the component's isOpen state is managed.
This diagram shows the user interactions that toggle the visibility of the dropdown options.
Sources: components/CustomSelect.tsx:20-34, components/CustomSelect.tsx:52, components/CustomSelect.tsx:89-92
Rendering and Styling
The component is styled using Tailwind CSS classes, ensuring it matches the application's dark theme defined in index.html. It consists of a main button that displays the current value and an icon, and a dropdown panel that appears when the button is clicked.
- Button: The main button displays an optional icon, the selected option's label, and a
ChevronsUpDownicon to indicate it's a dropdown. It has focus and open states styled with a purple ring, consistent with the app's primary color. - Dropdown Panel: The list of options appears in a floating panel with a blurred backdrop effect (
bg-[#1A1625]). - Options: Each option is a button. The currently selected option is highlighted with a different background color and a
Checkicon.
The base theme colors and fonts are configured in the <script> tag within index.html.
Sources: components/CustomSelect.tsx:40-100, index.html:43-66
Integration and Usage
The CustomSelect component is integrated into the main App.tsx to allow users to select the image generation model and the desired aspect ratio.
Data Flow for Options
The options for the CustomSelect components are dynamically constructed in App.tsx. For aspect ratios, the labels are pulled from the internationalization file (translations.ts) to support multiple languages.
The diagram below shows the data flow from source files to the rendered component.
This diagram illustrates how types.ts and translations.ts provide the necessary data structures and labels, which are then formatted in App.tsx and passed as props to the CustomSelect instances.
Sources: App.tsx:30-33, App.tsx:50-63, types.ts:13-15, translations.ts:25-33
Usage Example
Here is how CustomSelect is used in App.tsx for model selection. Note the use of the icon and headerContent props. The headerContent is used to render a toggle switch for "HD" mode directly in the component's header.
// From App.tsx
<CustomSelect
label={t.model}
value={model}
onChange={(val) => setModel(val as ModelOption)}
options={MODEL_OPTIONS}
icon={<Cpu className="w-5 h-5" />}
headerContent={
model === 'z-image-turbo' && (
<div className="flex items-center gap-2 animate-in fade-in duration-300">
<span className="text-xs font-medium text-white/50">{t.hd}</span>
<button
onClick={() => setEnableHD(!enableHD)}
className={`relative inline-flex h-5 w-9 items-center rounded-full ...`}
>
<span
className={`${enableHD ? 'translate-x-4' : 'translate-x-1'} ...`}
/>
</button>
</div>
)
}
/>
Sources: App.tsx:550-578
This demonstrates the flexibility of the component, allowing for complex, interactive elements to be injected into its layout via props.