Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/connect-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"dist"
],
"type": "module",
"main": "./dist/connect-react.umd.js",
"browser": "./dist/connect-react.umd.js",
"module": "./dist/connect-react.es.js",
"types": "./dist/connect-react.umd.d.ts",
Expand Down
39 changes: 34 additions & 5 deletions packages/connect-react/src/components/ControlApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@ import { useFrontendClient } from "../hooks/frontend-client-context";
import { useAccounts } from "../hooks/use-accounts";
import { useFormFieldContext } from "../hooks/form-field-context";
import { useFormContext } from "../hooks/form-context";
import { useCustomize } from "../hooks/customization-context";
import type { BaseReactSelectProps } from "../hooks/customization-context";
import {
useCustomize,
type BaseReactSelectProps,
} from "../hooks/customization-context";
import {
createBaseSelectStyles,
resolveSelectColors,
} from "../utils/select-styles";
import { useMemo } from "react";
import type { CSSProperties } from "react";
import type { OptionProps } from "react-select";
Expand Down Expand Up @@ -49,6 +55,16 @@ export function ControlApp({ app }: ControlAppProps) {
getProps, select, theme,
} = useCustomize();

const {
surface,
border,
text,
textStrong,
hoverBg,
selectedBg,
selectedHoverBg,
} = resolveSelectColors(theme.colors);

const baseStyles: CSSProperties = {
color: theme.colors.neutral60,
gridArea: "control",
Expand All @@ -63,15 +79,28 @@ export function ControlApp({ app }: ControlAppProps) {
gridArea: "control",
};

const selectStyles = createBaseSelectStyles<SelectValue>({
colors: {
surface,
border,
text,
textStrong,
hoverBg,
selectedBg,
selectedHoverBg,
},
boxShadow: theme.boxShadow,
});

const baseSelectProps: BaseReactSelectProps<SelectValue> = {
components: {
Option: BaseOption,
},
styles: {
control: (base) => ({
...base,
...selectStyles,
control: (base, state) => ({
...(selectStyles.control?.(base, state) ?? base),
gridArea: "control",
boxShadow: theme.boxShadow.input,
}),
},
};
Expand Down
53 changes: 52 additions & 1 deletion packages/connect-react/src/components/SelectApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ import type {
MenuListProps, OptionProps, SingleValueProps,
} from "react-select";
import { useApps } from "../hooks/use-apps";
import {
useCustomize,
type BaseReactSelectProps,
} from "../hooks/customization-context";
import {
createBaseSelectStyles,
resolveSelectColors,
} from "../utils/select-styles";
import type {
App,
AppsListRequest,
Expand Down Expand Up @@ -62,6 +70,9 @@ export function SelectApp({
SingleValue,
MenuList,
} = components;
const {
select, theme,
} = useCustomize();
const isLoadingMoreRef = useRef(isLoadingMore);
isLoadingMoreRef.current = isLoadingMore;

Expand All @@ -87,6 +98,34 @@ export function SelectApp({
loadMore,
]);

const {
surface,
border,
text,
textStrong,
hoverBg,
selectedBg,
selectedHoverBg,
appIconBg,
} = resolveSelectColors(theme.colors);

const baseSelectProps: BaseReactSelectProps<App> = {
styles: createBaseSelectStyles<App>({
colors: {
surface,
border,
text,
textStrong,
hoverBg,
selectedBg,
selectedHoverBg,
},
boxShadow: theme.boxShadow,
}),
};

const selectProps = select.getProps("selectApp", baseSelectProps);

// Memoize custom components to prevent remounting
const customComponents = useMemo(() => ({
Option: (optionProps: OptionProps<App>) => (
Expand All @@ -100,6 +139,9 @@ export function SelectApp({
style={{
height: 24,
width: 24,
backgroundColor: appIconBg,
borderRadius: 6,
padding: 2,
}}
alt={optionProps.data.name}
/>
Expand All @@ -121,6 +163,9 @@ export function SelectApp({
style={{
height: 24,
width: 24,
backgroundColor: appIconBg,
borderRadius: 6,
padding: 2,
}}
alt={singleValueProps.data.name}
/>
Expand Down Expand Up @@ -152,13 +197,18 @@ export function SelectApp({
Option,
SingleValue,
MenuList,
appIconBg,
]);
return (
<Select
instanceId={instanceId}
className="react-select-container text-sm"
{...selectProps}
classNamePrefix="react-select"
components={customComponents}
components={{
...selectProps.components,
...customComponents,
}}
options={apps || []}
getOptionLabel={(o: App) => o.name || o.nameSlug}
getOptionValue={(o: App) => o.nameSlug}
Expand All @@ -179,6 +229,7 @@ export function SelectApp({
}
menuPosition="fixed"
styles={{
...(selectProps.styles ?? {}),
menuPortal: (base) => ({
...base,
zIndex: 99999,
Expand Down
46 changes: 45 additions & 1 deletion packages/connect-react/src/components/SelectComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ import {
import Select, { components } from "react-select";
import type { MenuListProps } from "react-select";
import { useComponents } from "../hooks/use-components";
import {
useCustomize,
type BaseReactSelectProps,
} from "../hooks/customization-context";
import {
createBaseSelectStyles,
resolveSelectColors,
} from "../utils/select-styles";

type SelectComponentProps = {
app?: Partial<App> & { nameSlug: string; };
Expand Down Expand Up @@ -38,6 +46,20 @@ export function SelectComponent({
});

const { MenuList } = components;
const {
select, theme,
} = useCustomize();

const {
surface,
border,
text,
textStrong,
hoverBg,
selectedBg,
selectedHoverBg,
} = resolveSelectColors(theme.colors);

const isLoadingMoreRef = useRef(isLoadingMore);
isLoadingMoreRef.current = isLoadingMore;

Expand All @@ -60,6 +82,23 @@ export function SelectComponent({
loadMore,
]);

const baseSelectProps: BaseReactSelectProps<Component> = {
styles: createBaseSelectStyles<Component>({
colors: {
surface,
border,
text,
textStrong,
hoverBg,
selectedBg,
selectedHoverBg,
},
boxShadow: theme.boxShadow,
}),
};

const selectProps = select.getProps("selectComponent", baseSelectProps);

// Memoize custom components to prevent remounting
const customComponents = useMemo(() => ({
MenuList: (props: MenuListProps<Component>) => (
Expand Down Expand Up @@ -89,6 +128,7 @@ export function SelectComponent({
<Select
instanceId={instanceId}
className="react-select-container text-sm"
{...selectProps}
classNamePrefix="react-select"
options={componentsList}
getOptionLabel={(o) => o.name || o.key}
Expand All @@ -97,14 +137,18 @@ export function SelectComponent({
onChange={(o) => onChange?.((o as Component) || undefined)}
onMenuScrollToBottom={handleMenuScrollToBottom}
isLoading={isLoading}
components={customComponents}
components={{
...selectProps.components,
...customComponents,
}}
menuPortalTarget={
typeof document !== "undefined"
? document.body
: null
}
menuPosition="fixed"
styles={{
...(selectProps.styles ?? {}),
menuPortal: (base) => ({
...base,
zIndex: 99999,
Expand Down
2 changes: 2 additions & 0 deletions packages/connect-react/src/hooks/customization-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ export const defaultComponents = {
export type ReactSelectComponents = {
controlAppSelect: typeof ControlApp;
controlSelect: typeof ControlSelect;
selectApp: typeof ControlApp;
selectComponent: typeof ControlSelect;
};

export type CustomComponents<Option, IsMulti extends boolean, Group extends GroupBase<Option>> = {
Expand Down
11 changes: 11 additions & 0 deletions packages/connect-react/src/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,17 @@ export type Colors = {
// select.singleValue:color
neutral80: string;
neutral90: string;

// Option state backgrounds (dark mode friendly)
// select.option:hover:backgroundColor
optionHover?: string;
// select.option:selected:backgroundColor
optionSelected?: string;
// select.option:selected:hover:backgroundColor
optionSelectedHover?: string;

// App icon background color (for visibility in dark mode)
appIconBackground?: string;
};
Comment on lines +62 to 73
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

LGTM! New color tokens are well-documented.

The new optional color tokens (optionHover, optionSelected, optionSelectedHover, appIconBackground) extend the theming system appropriately for dark mode support. The inline comments clearly document their purpose.

Consider adding default values for these tokens in defaultTheme (lines 106-128) to provide light-mode defaults, ensuring components don't need to rely solely on hardcoded fallbacks.

 export const defaultTheme: Theme = {
   // ...existing colors...
   colors: {
     // ...existing...
     neutral90: "hsl(0, 0%, 10%)",
+
+    // Option state backgrounds (light mode defaults)
+    optionHover: "hsl(0, 0%, 95%)",
+    optionSelected: "rgba(38, 132, 255, 0.1)",
+    optionSelectedHover: "rgba(38, 132, 255, 0.2)",
+    appIconBackground: "#fff",
   },
   // ...
 };

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/connect-react/src/theme.ts around lines 62-73 (and add defaults in
defaultTheme at lines ~106-128), the new optional color tokens optionHover,
optionSelected, optionSelectedHover, and appIconBackground need light-mode
default values so components don't rely on hardcoded fallbacks; add these four
keys to the defaultTheme object with sensible CSS color strings (matching the
existing token naming and value format used in that file), ensure types remain
compatible (no breaking changes), and run a quick build/test to confirm no type
or import errors.


export type Shadows = {
Expand Down
Loading
Loading