Skip to content

Commit 0ee81f3

Browse files
Linting and PR feedback
1 parent ab7593b commit 0ee81f3

File tree

4 files changed

+124
-140
lines changed

4 files changed

+124
-140
lines changed

packages/connect-react/src/components/ControlArray.tsx

Lines changed: 10 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import {
2-
useState, useEffect, type CSSProperties,
2+
useState, useEffect,
33
} from "react";
44
import { useFormFieldContext } from "../hooks/form-field-context";
55
import { useCustomize } from "../hooks/customization-context";
6+
import {
7+
getInputStyles, getButtonStyles, getRemoveButtonStyles, getContainerStyles, getItemStyles,
8+
} from "../styles/control-styles";
69

710
export function ControlArray() {
811
const formFieldContextProps = useFormFieldContext();
@@ -52,7 +55,7 @@ export function ControlArray() {
5255
return;
5356
}
5457

55-
onChange(validValues as any);
58+
onChange(validValues as string[]);
5659
};
5760

5861
const handleValueChange = (index: number, newValue: string) => {
@@ -82,51 +85,11 @@ export function ControlArray() {
8285
updateArray(newValues);
8386
};
8487

85-
const containerStyles: CSSProperties = {
86-
gridArea: "control",
87-
display: "flex",
88-
flexDirection: "column",
89-
gap: "0.5rem",
90-
};
91-
92-
const itemStyles: CSSProperties = {
93-
display: "flex",
94-
gap: "0.5rem",
95-
alignItems: "center",
96-
};
97-
98-
const inputStyles: CSSProperties = {
99-
color: theme.colors.neutral60,
100-
border: "1px solid",
101-
borderColor: theme.colors.neutral20,
102-
padding: 6,
103-
borderRadius: theme.borderRadius,
104-
boxShadow: theme.boxShadow.input,
105-
flex: 1,
106-
};
107-
108-
const buttonStyles: CSSProperties = {
109-
color: theme.colors.neutral60,
110-
display: "inline-flex",
111-
alignItems: "center",
112-
padding: `${theme.spacing.baseUnit}px ${theme.spacing.baseUnit * 1.5}px ${
113-
theme.spacing.baseUnit
114-
}px ${theme.spacing.baseUnit * 2.5}px`,
115-
border: `1px solid ${theme.colors.neutral30}`,
116-
borderRadius: theme.borderRadius,
117-
cursor: "pointer",
118-
fontSize: "0.8125rem",
119-
fontWeight: 450,
120-
gap: theme.spacing.baseUnit * 2,
121-
textWrap: "nowrap",
122-
backgroundColor: "white",
123-
};
124-
125-
const removeButtonStyles: CSSProperties = {
126-
...buttonStyles,
127-
flex: "0 0 auto",
128-
padding: "6px 8px",
129-
};
88+
const containerStyles = getContainerStyles();
89+
const itemStyles = getItemStyles();
90+
const inputStyles = getInputStyles(theme);
91+
const buttonStyles = getButtonStyles(theme);
92+
const removeButtonStyles = getRemoveButtonStyles(theme);
13093

13194
// Show "Add more" button if the last input has content or if there are multiple inputs
13295
const shouldShowAddMoreButton = values[values.length - 1]?.trim() || values.length > 1;

packages/connect-react/src/components/ControlObject.tsx

Lines changed: 13 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import {
2-
useState, useEffect, type CSSProperties,
2+
useState, useEffect,
33
} from "react";
44
import { useFormFieldContext } from "../hooks/form-field-context";
55
import { useCustomize } from "../hooks/customization-context";
6+
import {
7+
getInputStyles, getButtonStyles, getRemoveButtonStyles, getContainerStyles, getItemStyles,
8+
} from "../styles/control-styles";
69

710
type KeyValuePair = {
811
key: string;
@@ -19,7 +22,7 @@ export function ControlObject() {
1922
} = useCustomize();
2023

2124
// Check if the value is a plain object (not Date, Function, etc.)
22-
const isPlainObject = (obj: any): boolean => {
25+
const isPlainObject = (obj: unknown): boolean => {
2326
if (obj === null || typeof obj !== "object") {
2427
return false;
2528
}
@@ -118,7 +121,7 @@ export function ControlObject() {
118121
: (() => {
119122
try {
120123
return JSON.stringify(v);
121-
} catch (error) {
124+
} catch {
122125
// Handle circular references or non-serializable values
123126
return String(v);
124127
}
@@ -147,7 +150,7 @@ export function ControlObject() {
147150
}
148151

149152
// Convert to object
150-
const obj: Record<string, any> = {};
153+
const obj: Record<string, unknown> = {};
151154
validPairs.forEach((pair) => {
152155
if (pair.key.trim()) {
153156
// Try to parse the value as JSON, fallback to string
@@ -159,7 +162,7 @@ export function ControlObject() {
159162
}
160163
});
161164

162-
onChange(obj as any);
165+
onChange(obj as Record<string, unknown>);
163166
};
164167

165168
const handlePairChange = (index: number, field: "key" | "value", newValue: string) => {
@@ -198,51 +201,11 @@ export function ControlObject() {
198201
updateObject(newPairs);
199202
};
200203

201-
const containerStyles: CSSProperties = {
202-
gridArea: "control",
203-
display: "flex",
204-
flexDirection: "column",
205-
gap: "0.5rem",
206-
};
207-
208-
const pairStyles: CSSProperties = {
209-
display: "flex",
210-
gap: "0.5rem",
211-
alignItems: "center",
212-
};
213-
214-
const inputStyles: CSSProperties = {
215-
color: theme.colors.neutral60,
216-
border: "1px solid",
217-
borderColor: theme.colors.neutral20,
218-
padding: 6,
219-
borderRadius: theme.borderRadius,
220-
boxShadow: theme.boxShadow.input,
221-
flex: 1,
222-
};
223-
224-
const buttonStyles: CSSProperties = {
225-
color: theme.colors.neutral60,
226-
display: "inline-flex",
227-
alignItems: "center",
228-
padding: `${theme.spacing.baseUnit}px ${theme.spacing.baseUnit * 1.5}px ${
229-
theme.spacing.baseUnit
230-
}px ${theme.spacing.baseUnit * 2.5}px`,
231-
border: `1px solid ${theme.colors.neutral30}`,
232-
borderRadius: theme.borderRadius,
233-
cursor: "pointer",
234-
fontSize: "0.8125rem",
235-
fontWeight: 450,
236-
gap: theme.spacing.baseUnit * 2,
237-
textWrap: "nowrap",
238-
backgroundColor: "white",
239-
};
240-
241-
const removeButtonStyles: CSSProperties = {
242-
...buttonStyles,
243-
flex: "0 0 auto",
244-
padding: "6px 8px",
245-
};
204+
const containerStyles = getContainerStyles();
205+
const pairStyles = getItemStyles(); // Reuse item styles for pairs
206+
const inputStyles = getInputStyles(theme);
207+
const buttonStyles = getButtonStyles(theme);
208+
const removeButtonStyles = getRemoveButtonStyles(theme);
246209

247210
return (
248211
<div {...getProps("controlObject", containerStyles, formFieldContextProps)}>
Lines changed: 53 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {
2-
useState, type CSSProperties,
2+
useState, useMemo, type CSSProperties,
33
} from "react";
44
import Markdown from "react-markdown";
55
import {
@@ -15,6 +15,45 @@ export type DescriptionProps<T extends ConfigurableProps, U extends Configurable
1515
form: FormContext<T>;
1616
};
1717

18+
// Custom link component extracted outside to avoid recreation on each render
19+
const DescriptionLink = ({ ...linkProps }) => {
20+
const [
21+
isHovered,
22+
setIsHovered,
23+
] = useState(false);
24+
25+
const linkStyles: CSSProperties = {
26+
textDecoration: "underline",
27+
textUnderlineOffset: "3px",
28+
color: "inherit",
29+
transition: "opacity 0.2s ease",
30+
opacity: isHovered
31+
? 0.7
32+
: 1,
33+
};
34+
35+
return (
36+
<span style={{
37+
display: "inline-flex",
38+
alignItems: "center",
39+
gap: "2px",
40+
}}>
41+
<a
42+
{...linkProps}
43+
target="_blank"
44+
rel="noopener noreferrer"
45+
style={linkStyles}
46+
onMouseEnter={() => setIsHovered(true)}
47+
onMouseLeave={() => setIsHovered(false)}
48+
/>
49+
<span style={{
50+
fontSize: "0.7em",
51+
opacity: 0.7,
52+
}}></span>
53+
</span>
54+
);
55+
};
56+
1857
// XXX should we rename to FieldDescription (so shared prefix + clear we need field context
1958
// eg. cannot be used in OptionalFieldButton, or they need to be set up better)
2059
export function Description<T extends ConfigurableProps, U extends ConfigurableProp>(props: DescriptionProps<T, U>) {
@@ -26,61 +65,32 @@ export function Description<T extends ConfigurableProps, U extends ConfigurableP
2665
getClassNames, getStyles, theme,
2766
} = useCustomize();
2867

29-
const baseStyles: CSSProperties = {
68+
const baseStyles: CSSProperties = useMemo(() => ({
3069
color: theme.colors.neutral50,
3170
fontWeight: 400,
3271
fontSize: "0.75rem",
3372
gridArea: "description",
3473
textWrap: "balance",
3574
lineHeight: "1.5",
36-
};
75+
}), [
76+
theme.colors.neutral50,
77+
]);
78+
79+
const markdownComponents = useMemo(() => ({
80+
a: DescriptionLink,
81+
}), []);
82+
83+
// Cast props to the expected type for styling functions
84+
const styleProps = props as unknown as DescriptionProps<readonly ConfigurableProp[], ConfigurableProp>;
3785

3886
if (prop.type === "app") {
3987
// TODO
40-
return <p className={getClassNames("description", props)} style={getStyles("description", baseStyles, props)}>Credentials are encrypted.</p>;
88+
return <p className={getClassNames("description", styleProps)} style={getStyles("description", baseStyles, styleProps)}>Credentials are encrypted.</p>;
4189
}
4290
if (!prop.description) {
4391
return null;
4492
}
45-
return <div className={getClassNames("description", props)} style={getStyles("description", baseStyles, props)}> <Markdown components={{
46-
a: ({ ...linkProps }) => {
47-
const [
48-
isHovered,
49-
setIsHovered,
50-
] = useState(false);
51-
52-
const linkStyles: CSSProperties = {
53-
textDecoration: "underline",
54-
textUnderlineOffset: "3px",
55-
color: "inherit",
56-
transition: "opacity 0.2s ease",
57-
opacity: isHovered
58-
? 0.7
59-
: 1,
60-
};
61-
62-
return (
63-
<span style={{
64-
display: "inline-flex",
65-
alignItems: "center",
66-
gap: "2px",
67-
}}>
68-
<a
69-
{...linkProps}
70-
target="_blank"
71-
rel="noopener noreferrer"
72-
style={linkStyles}
73-
onMouseEnter={() => setIsHovered(true)}
74-
onMouseLeave={() => setIsHovered(false)}
75-
/>
76-
<span style={{
77-
fontSize: "0.7em",
78-
opacity: 0.7,
79-
}}></span>
80-
</span>
81-
);
82-
},
83-
}}>
93+
return <div className={getClassNames("description", styleProps)} style={getStyles("description", baseStyles, styleProps)}> <Markdown components={markdownComponents}>
8494
{markdown}
8595
</Markdown></div>;
8696
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import type { CSSProperties } from "react";
2+
import type { Theme } from "../theme";
3+
4+
export const getInputStyles = (theme: Theme): CSSProperties => ({
5+
color: theme.colors.neutral60,
6+
border: "1px solid",
7+
borderColor: theme.colors.neutral20,
8+
padding: 6,
9+
borderRadius: theme.borderRadius,
10+
boxShadow: theme.boxShadow.input,
11+
flex: 1,
12+
});
13+
14+
export const getButtonStyles = (theme: Theme): CSSProperties => ({
15+
color: theme.colors.neutral60,
16+
display: "inline-flex",
17+
alignItems: "center",
18+
padding: `${theme.spacing.baseUnit}px ${theme.spacing.baseUnit * 1.5}px ${
19+
theme.spacing.baseUnit
20+
}px ${theme.spacing.baseUnit * 2.5}px`,
21+
border: `1px solid ${theme.colors.neutral30}`,
22+
borderRadius: theme.borderRadius,
23+
cursor: "pointer",
24+
fontSize: "0.8125rem",
25+
fontWeight: 450,
26+
gap: theme.spacing.baseUnit * 2,
27+
textWrap: "nowrap",
28+
backgroundColor: "white",
29+
});
30+
31+
export const getRemoveButtonStyles = (theme: Theme): CSSProperties => ({
32+
...getButtonStyles(theme),
33+
flex: "0 0 auto",
34+
padding: "6px 8px",
35+
});
36+
37+
export const getContainerStyles = (): CSSProperties => ({
38+
gridArea: "control",
39+
display: "flex",
40+
flexDirection: "column",
41+
gap: "0.5rem",
42+
});
43+
44+
export const getItemStyles = (): CSSProperties => ({
45+
display: "flex",
46+
gap: "0.5rem",
47+
alignItems: "center",
48+
});

0 commit comments

Comments
 (0)