@@ -5,15 +5,12 @@ import {
55 useState ,
66 useRef ,
77} from "react" ;
8- import type {
9- CSSObjectWithLabel , MenuListProps ,
10- } from "react-select" ;
8+ import type { MenuListProps } from "react-select" ;
119import Select , {
1210 components ,
1311 Props as ReactSelectProps ,
1412} from "react-select" ;
1513import CreatableSelect from "react-select/creatable" ;
16- import type { BaseReactSelectProps } from "../hooks/customization-context" ;
1714import { useCustomize } from "../hooks/customization-context" ;
1815import { useFormFieldContext } from "../hooks/form-field-context" ;
1916import type {
@@ -28,6 +25,10 @@ import {
2825 isArrayOfLabelValueWrapped ,
2926 isLabelValueWrapped ,
3027} from "../utils/label-value" ;
28+ import {
29+ createBaseSelectStyles ,
30+ resolveSelectColors ,
31+ } from "../utils/select-styles" ;
3132import { LoadMoreButton } from "./LoadMoreButton" ;
3233
3334// XXX T and ConfigurableProp should be related
@@ -55,6 +56,29 @@ export function ControlSelect<T extends PropOptionValue>({
5556 const {
5657 select, theme,
5758 } = useCustomize ( ) ;
59+
60+ // Memoize color resolution to avoid recalculating on every render
61+ const resolvedColors = useMemo ( ( ) => resolveSelectColors ( theme . colors ) , [
62+ theme . colors ,
63+ ] ) ;
64+
65+ // Memoize base select styles - only recalculate when colors or boxShadow change
66+ const baseSelectStyles = useMemo ( ( ) => createBaseSelectStyles < LabelValueOption < T > , boolean > ( {
67+ colors : {
68+ surface : resolvedColors . surface ,
69+ border : resolvedColors . border ,
70+ text : resolvedColors . text ,
71+ textStrong : resolvedColors . textStrong ,
72+ hoverBg : resolvedColors . hoverBg ,
73+ selectedBg : resolvedColors . selectedBg ,
74+ selectedHoverBg : resolvedColors . selectedHoverBg ,
75+ } ,
76+ boxShadow : theme . boxShadow ,
77+ } ) , [
78+ resolvedColors ,
79+ theme . boxShadow ,
80+ ] ) ;
81+
5882 const [
5983 selectOptions ,
6084 setSelectOptions ,
@@ -77,16 +101,6 @@ export function ControlSelect<T extends PropOptionValue>({
77101 value ,
78102 ] )
79103
80- const baseSelectProps : BaseReactSelectProps < LabelValueOption < T > , boolean > = {
81- styles : {
82- container : ( base ) : CSSObjectWithLabel => ( {
83- ...base ,
84- gridArea : "control" ,
85- boxShadow : theme . boxShadow . input ,
86- } ) ,
87- } ,
88- } ;
89-
90104 const selectValue : LabelValueOption < T > | LabelValueOption < T > [ ] | null = useMemo ( ( ) => {
91105 if ( rawValue == null ) {
92106 return null ;
@@ -130,7 +144,15 @@ export function ControlSelect<T extends PropOptionValue>({
130144 selectOptions ,
131145 ] ) ;
132146
133- const props = select . getProps ( "controlSelect" , baseSelectProps )
147+ // Get customization props from context
148+ // We pass our dark mode base styles as the base, so user customizations merge on top
149+ const customizationProps = select . getProps <
150+ "controlSelect" ,
151+ LabelValueOption < T > ,
152+ boolean
153+ > ( "controlSelect" , {
154+ styles : baseSelectStyles ,
155+ } )
134156
135157 // Use ref to store latest onLoadMore callback
136158 // This allows stable component reference while calling current callback
@@ -145,10 +167,10 @@ export function ControlSelect<T extends PropOptionValue>({
145167 showLoadMoreButtonRef . current = showLoadMoreButton ;
146168
147169 // Memoize custom components to prevent remounting
148- // Recompute when caller/customizer supplies new component overrides
170+ // Merge: customization context components -> caller overrides -> our MenuList wrapper
149171 const finalComponents = useMemo ( ( ) => {
150172 const mergedComponents = {
151- ...( props . components ?? { } ) ,
173+ ...( customizationProps . components ?? { } ) ,
152174 ...( componentsOverride ?? { } ) ,
153175 } ;
154176 const ParentMenuList = mergedComponents . MenuList ?? components . MenuList ;
@@ -174,8 +196,8 @@ export function ControlSelect<T extends PropOptionValue>({
174196 MenuList : CustomMenuList ,
175197 } ;
176198 } , [
177- props . components ,
178199 componentsOverride ,
200+ customizationProps . components ,
179201 ] ) ;
180202
181203 const handleCreate = ( inputValue : string ) => {
@@ -254,21 +276,26 @@ export function ControlSelect<T extends PropOptionValue>({
254276 getOptionLabel = { ( option ) => sanitizeOption ( option ) . label }
255277 getOptionValue = { ( option ) => String ( sanitizeOption ( option ) . value ) }
256278 onChange = { handleChange }
257- { ...props }
279+ // Apply customization context values as defaults
280+ classNamePrefix = { customizationProps . classNamePrefix || "react-select" }
281+ classNames = { customizationProps . classNames }
282+ theme = { customizationProps . theme }
283+ // Spread selectProps after defaults so callers can override theme/classNames/classNamePrefix
258284 { ...selectProps }
259285 { ...additionalProps }
260- // These must come AFTER spreads to avoid being overridden
261- classNamePrefix = "react-select"
262286 menuPortalTarget = {
263287 typeof document !== "undefined"
264288 ? document . body
265289 : null
266290 }
267291 menuPosition = "fixed"
268292 styles = { {
269- // eslint-disable-next-line react/prop-types
270- ...props . styles ,
271- ...selectProps ?. styles ,
293+ ...customizationProps . styles ,
294+ ...( selectProps ?. styles ?? { } ) ,
295+ container : ( base ) => ( {
296+ ...base ,
297+ gridArea : "control" ,
298+ } ) ,
272299 menuPortal : ( base ) => ( {
273300 ...base ,
274301 zIndex : 99999 ,
0 commit comments