mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
chore(lint): hoist jsx-as-prop in app components batch 3
Memoize inline JSX passed as props across combined-model-selector, draggable-list.native, provider-diagnostic-sheet, and workspace-setup-dialog to satisfy react-perf/jsx-no-jsx-as-prop.
This commit is contained in:
@@ -202,6 +202,49 @@ function ModelRow({
|
||||
[onToggleFavorite, row.modelId, row.provider],
|
||||
);
|
||||
|
||||
const leadingSlot = useMemo(
|
||||
() => <ProviderIcon size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />,
|
||||
[ProviderIcon, theme.iconSize.sm, theme.colors.foregroundMuted],
|
||||
);
|
||||
const trailingSlot = useMemo(
|
||||
() =>
|
||||
onToggleFavorite && !disabled ? (
|
||||
<Pressable
|
||||
onPress={handleToggleFavorite}
|
||||
hitSlop={8}
|
||||
style={favoriteButtonStyle}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={isFavorite ? "Unfavorite model" : "Favorite model"}
|
||||
testID={`favorite-model-${row.provider}-${row.modelId}`}
|
||||
>
|
||||
{({ hovered }) => (
|
||||
<Star
|
||||
size={16}
|
||||
color={
|
||||
isFavorite
|
||||
? theme.colors.palette.amber[500]
|
||||
: hovered
|
||||
? theme.colors.foregroundMuted
|
||||
: theme.colors.border
|
||||
}
|
||||
fill={isFavorite ? theme.colors.palette.amber[500] : "transparent"}
|
||||
/>
|
||||
)}
|
||||
</Pressable>
|
||||
) : null,
|
||||
[
|
||||
onToggleFavorite,
|
||||
disabled,
|
||||
handleToggleFavorite,
|
||||
isFavorite,
|
||||
row.provider,
|
||||
row.modelId,
|
||||
theme.colors.palette.amber,
|
||||
theme.colors.foregroundMuted,
|
||||
theme.colors.border,
|
||||
],
|
||||
);
|
||||
|
||||
const showDescription = row.description && PROVIDERS_WITH_MODEL_DESCRIPTIONS.has(row.provider);
|
||||
|
||||
return (
|
||||
@@ -212,33 +255,8 @@ function ModelRow({
|
||||
disabled={disabled}
|
||||
elevated={elevated}
|
||||
onPress={onPress}
|
||||
leadingSlot={<ProviderIcon size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />}
|
||||
trailingSlot={
|
||||
onToggleFavorite && !disabled ? (
|
||||
<Pressable
|
||||
onPress={handleToggleFavorite}
|
||||
hitSlop={8}
|
||||
style={favoriteButtonStyle}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={isFavorite ? "Unfavorite model" : "Favorite model"}
|
||||
testID={`favorite-model-${row.provider}-${row.modelId}`}
|
||||
>
|
||||
{({ hovered }) => (
|
||||
<Star
|
||||
size={16}
|
||||
color={
|
||||
isFavorite
|
||||
? theme.colors.palette.amber[500]
|
||||
: hovered
|
||||
? theme.colors.foregroundMuted
|
||||
: theme.colors.border
|
||||
}
|
||||
fill={isFavorite ? theme.colors.palette.amber[500] : "transparent"}
|
||||
/>
|
||||
)}
|
||||
</Pressable>
|
||||
) : null
|
||||
}
|
||||
leadingSlot={leadingSlot}
|
||||
trailingSlot={trailingSlot}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -719,6 +737,27 @@ export function CombinedModelSelector({
|
||||
setView({ kind: "provider", providerId, providerLabel });
|
||||
}, []);
|
||||
|
||||
const stickyHeader = useMemo(
|
||||
() =>
|
||||
view.kind === "provider" ? (
|
||||
<View style={styles.level2Header}>
|
||||
{!singleProviderView ? (
|
||||
<ProviderBackButton
|
||||
providerId={view.providerId}
|
||||
providerLabel={view.providerLabel}
|
||||
onBack={handleBackToAll}
|
||||
/>
|
||||
) : null}
|
||||
<ProviderSearchInput
|
||||
value={searchQuery}
|
||||
onChangeText={setSearchQuery}
|
||||
autoFocus={platformIsWeb}
|
||||
/>
|
||||
</View>
|
||||
) : undefined,
|
||||
[view, singleProviderView, handleBackToAll, searchQuery],
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Pressable
|
||||
@@ -761,24 +800,7 @@ export function CombinedModelSelector({
|
||||
desktopMinWidth={360}
|
||||
desktopFixedHeight={desktopFixedHeight}
|
||||
title="Select model"
|
||||
stickyHeader={
|
||||
view.kind === "provider" ? (
|
||||
<View style={styles.level2Header}>
|
||||
{!singleProviderView ? (
|
||||
<ProviderBackButton
|
||||
providerId={view.providerId}
|
||||
providerLabel={view.providerLabel}
|
||||
onBack={handleBackToAll}
|
||||
/>
|
||||
) : null}
|
||||
<ProviderSearchInput
|
||||
value={searchQuery}
|
||||
onChangeText={setSearchQuery}
|
||||
autoFocus={platformIsWeb}
|
||||
/>
|
||||
</View>
|
||||
) : undefined
|
||||
}
|
||||
stickyHeader={stickyHeader}
|
||||
>
|
||||
{isContentReady ? (
|
||||
<SelectorContent
|
||||
|
||||
@@ -88,6 +88,19 @@ export function DraggableList<T>({
|
||||
nestable ? (NestableDraggableFlatList as any) : DraggableFlatList
|
||||
) as any;
|
||||
|
||||
const refreshControl = useMemo(
|
||||
() =>
|
||||
shouldShowRefreshControl ? (
|
||||
<RefreshControl
|
||||
refreshing={refreshing ?? false}
|
||||
onRefresh={onRefresh}
|
||||
tintColor={theme.colors.foregroundMuted}
|
||||
colors={refreshColors}
|
||||
/>
|
||||
) : undefined,
|
||||
[shouldShowRefreshControl, refreshing, onRefresh, theme.colors.foregroundMuted, refreshColors],
|
||||
);
|
||||
|
||||
return (
|
||||
<ListComponent
|
||||
testID={testID}
|
||||
@@ -111,16 +124,7 @@ export function DraggableList<T>({
|
||||
onRelease={handleRelease}
|
||||
// @ts-ignore - waitFor is supported by RNGH FlatList but missing from DraggableFlatList types
|
||||
waitFor={waitFor}
|
||||
refreshControl={
|
||||
shouldShowRefreshControl ? (
|
||||
<RefreshControl
|
||||
refreshing={refreshing ?? false}
|
||||
onRefresh={onRefresh}
|
||||
tintColor={theme.colors.foregroundMuted}
|
||||
colors={refreshColors}
|
||||
/>
|
||||
) : undefined
|
||||
}
|
||||
refreshControl={refreshControl}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -123,6 +123,35 @@ export function ProviderDiagnosticSheet({
|
||||
});
|
||||
}, [fetchDiagnostic, provider, refresh]);
|
||||
|
||||
const headerActions = useMemo(
|
||||
() => (
|
||||
<Pressable
|
||||
onPress={handleRefresh}
|
||||
disabled={refreshInFlight}
|
||||
hitSlop={8}
|
||||
style={refreshButtonStyle}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={
|
||||
refreshInFlight ? `Refreshing ${providerLabel}` : `Refresh ${providerLabel}`
|
||||
}
|
||||
>
|
||||
{refreshInFlight ? (
|
||||
<LoadingSpinner size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />
|
||||
) : (
|
||||
<RotateCw size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />
|
||||
)}
|
||||
</Pressable>
|
||||
),
|
||||
[
|
||||
handleRefresh,
|
||||
refreshInFlight,
|
||||
refreshButtonStyle,
|
||||
providerLabel,
|
||||
theme.iconSize.sm,
|
||||
theme.colors.foregroundMuted,
|
||||
],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
fetchDiagnostic();
|
||||
@@ -176,24 +205,7 @@ export function ProviderDiagnosticSheet({
|
||||
onClose={onClose}
|
||||
snapPoints={DIAGNOSTIC_SHEET_SNAP_POINTS}
|
||||
scrollable={false}
|
||||
headerActions={
|
||||
<Pressable
|
||||
onPress={handleRefresh}
|
||||
disabled={refreshInFlight}
|
||||
hitSlop={8}
|
||||
style={refreshButtonStyle}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={
|
||||
refreshInFlight ? `Refreshing ${providerLabel}` : `Refresh ${providerLabel}`
|
||||
}
|
||||
>
|
||||
{refreshInFlight ? (
|
||||
<LoadingSpinner size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />
|
||||
) : (
|
||||
<RotateCw size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />
|
||||
)}
|
||||
</Pressable>
|
||||
}
|
||||
headerActions={headerActions}
|
||||
>
|
||||
<View style={sheetStyles.section}>
|
||||
<Text style={sheetStyles.sectionTitle}>Diagnostic</Text>
|
||||
|
||||
@@ -272,25 +272,28 @@ export function WorkspaceSetupDialog() {
|
||||
[composerState, pendingAction],
|
||||
);
|
||||
|
||||
const subtitleContent = useMemo(
|
||||
() => (
|
||||
<View style={styles.subtitleRow}>
|
||||
{iconSource ? (
|
||||
<Image source={iconSource} style={styles.projectIcon} />
|
||||
) : (
|
||||
<View style={styles.projectIconFallback}>
|
||||
<Text style={styles.projectIconFallbackText}>{placeholderInitial}</Text>
|
||||
</View>
|
||||
)}
|
||||
<Text style={styles.projectTitle} numberOfLines={1}>
|
||||
{workspaceTitle}
|
||||
</Text>
|
||||
</View>
|
||||
),
|
||||
[iconSource, placeholderInitial, workspaceTitle],
|
||||
);
|
||||
|
||||
if (!pendingWorkspaceSetup || !sourceDirectory) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const subtitleContent = (
|
||||
<View style={styles.subtitleRow}>
|
||||
{iconSource ? (
|
||||
<Image source={iconSource} style={styles.projectIcon} />
|
||||
) : (
|
||||
<View style={styles.projectIconFallback}>
|
||||
<Text style={styles.projectIconFallbackText}>{placeholderInitial}</Text>
|
||||
</View>
|
||||
)}
|
||||
<Text style={styles.projectTitle} numberOfLines={1}>
|
||||
{workspaceTitle}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
return (
|
||||
<AdaptiveModalSheet
|
||||
title="Create workspace"
|
||||
|
||||
Reference in New Issue
Block a user