chore(lint): hoist/memoize inline styles in plan-card

Extracts markdown rule style arrays into dedicated MarkdownInlineText,
MarkdownListItemContent, and MarkdownParagraph subcomponents that
memoize their own style arrays. Memoizes PlanCard container/title/
description styles.
This commit is contained in:
Mohamed Boudra
2026-04-24 01:57:23 +07:00
parent 0e837fe4f3
commit c8474385ff

View File

@@ -1,10 +1,62 @@
import type { ReactNode } from "react";
import { useMemo, type ReactNode } from "react";
import { Text, View } from "react-native";
import Markdown from "react-native-markdown-display";
import { StyleSheet, useUnistyles } from "react-native-unistyles";
import { createMarkdownStyles } from "@/styles/markdown-styles";
import { getMarkdownListMarker } from "@/utils/markdown-list";
function MarkdownInlineText({
textKey,
inheritedStyle,
ruleStyle,
children,
}: {
textKey: string;
inheritedStyle: any;
ruleStyle: any;
children: ReactNode;
}) {
const style = useMemo(() => [inheritedStyle, ruleStyle], [inheritedStyle, ruleStyle]);
return (
<Text key={textKey} style={style}>
{children}
</Text>
);
}
function MarkdownListItemContent({
contentStyle,
children,
}: {
contentStyle: any;
children: ReactNode;
}) {
const style = useMemo(() => [contentStyle, LIST_ITEM_CONTENT_INNER], [contentStyle]);
return <View style={style}>{children}</View>;
}
function MarkdownParagraph({
textKey,
paragraphStyle,
isLastChild,
children,
}: {
textKey: string;
paragraphStyle: any;
isLastChild: boolean;
children: ReactNode;
}) {
const style = useMemo(
() => [paragraphStyle, isLastChild ? PARAGRAPH_LAST_CHILD : false],
[paragraphStyle, isLastChild],
);
return (
<View key={textKey} style={style}>
{children}
</View>
);
}
function createPlanMarkdownRules() {
return {
text: (
@@ -14,9 +66,13 @@ function createPlanMarkdownRules() {
styles: any,
inheritedStyles: any = {},
) => (
<Text key={node.key} style={[inheritedStyles, styles.text]}>
<MarkdownInlineText
textKey={node.key}
inheritedStyle={inheritedStyles}
ruleStyle={styles.text}
>
{node.content}
</Text>
</MarkdownInlineText>
),
textgroup: (
node: any,
@@ -25,9 +81,13 @@ function createPlanMarkdownRules() {
styles: any,
inheritedStyles: any = {},
) => (
<Text key={node.key} style={[inheritedStyles, styles.textgroup]}>
<MarkdownInlineText
textKey={node.key}
inheritedStyle={inheritedStyles}
ruleStyle={styles.textgroup}
>
{children}
</Text>
</MarkdownInlineText>
),
code_block: (
node: any,
@@ -36,9 +96,13 @@ function createPlanMarkdownRules() {
styles: any,
inheritedStyles: any = {},
) => (
<Text key={node.key} style={[inheritedStyles, styles.code_block]}>
<MarkdownInlineText
textKey={node.key}
inheritedStyle={inheritedStyles}
ruleStyle={styles.code_block}
>
{node.content}
</Text>
</MarkdownInlineText>
),
fence: (
node: any,
@@ -47,9 +111,13 @@ function createPlanMarkdownRules() {
styles: any,
inheritedStyles: any = {},
) => (
<Text key={node.key} style={[inheritedStyles, styles.fence]}>
<MarkdownInlineText
textKey={node.key}
inheritedStyle={inheritedStyles}
ruleStyle={styles.fence}
>
{node.content}
</Text>
</MarkdownInlineText>
),
code_inline: (
node: any,
@@ -58,9 +126,13 @@ function createPlanMarkdownRules() {
styles: any,
inheritedStyles: any = {},
) => (
<Text key={node.key} style={[inheritedStyles, styles.code_inline]}>
<MarkdownInlineText
textKey={node.key}
inheritedStyle={inheritedStyles}
ruleStyle={styles.code_inline}
>
{node.content}
</Text>
</MarkdownInlineText>
),
bullet_list: (node: any, children: ReactNode[], _parent: any, styles: any) => (
<View key={node.key} style={styles.bullet_list}>
@@ -80,16 +152,20 @@ function createPlanMarkdownRules() {
return (
<View key={node.key} style={styles.list_item}>
<Text style={iconStyle}>{marker}</Text>
<View style={[contentStyle, { flex: 1, flexShrink: 1, minWidth: 0 }]}>{children}</View>
<MarkdownListItemContent contentStyle={contentStyle}>{children}</MarkdownListItemContent>
</View>
);
},
paragraph: (node: any, children: ReactNode[], parent: any, styles: any) => {
const isLastChild = parent[0]?.children?.at(-1)?.key === node.key;
return (
<View key={node.key} style={[styles.paragraph, isLastChild && { marginBottom: 0 }]}>
<MarkdownParagraph
textKey={node.key}
paragraphStyle={styles.paragraph}
isLastChild={isLastChild}
>
{children}
</View>
</MarkdownParagraph>
);
},
};
@@ -112,23 +188,30 @@ export function PlanCard({
const markdownStyles = createMarkdownStyles(theme);
const markdownRules = createPlanMarkdownRules();
const containerStyle = useMemo(
() => [
styles.container,
disableOuterSpacing && styles.containerCompact,
{
backgroundColor: theme.colors.surface1,
borderColor: theme.colors.border,
},
],
[disableOuterSpacing, theme.colors.surface1, theme.colors.border],
);
const titleStyle = useMemo(
() => [styles.title, { color: theme.colors.foreground }],
[theme.colors.foreground],
);
const descriptionStyle = useMemo(
() => [styles.description, { color: theme.colors.foregroundMuted }],
[theme.colors.foregroundMuted],
);
return (
<View
style={[
styles.container,
disableOuterSpacing && styles.containerCompact,
{
backgroundColor: theme.colors.surface1,
borderColor: theme.colors.border,
},
]}
>
<Text style={[styles.title, { color: theme.colors.foreground }]}>{title}</Text>
{description ? (
<Text style={[styles.description, { color: theme.colors.foregroundMuted }]}>
{description}
</Text>
) : null}
<View style={containerStyle}>
<Text style={titleStyle}>{title}</Text>
{description ? <Text style={descriptionStyle}>{description}</Text> : null}
<Markdown style={markdownStyles} rules={markdownRules}>
{text}
</Markdown>
@@ -160,3 +243,6 @@ const styles = StyleSheet.create((theme) => ({
gap: theme.spacing[2],
},
}));
const LIST_ITEM_CONTENT_INNER = { flex: 1, flexShrink: 1, minWidth: 0 };
const PARAGRAPH_LAST_CHILD = { marginBottom: 0 };