@moneylion/react-native-offer-carousel 1.10.1 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/lib/commonjs/capabilities/configuration/src/brands/checkVisualEligibility.js +13 -11
  3. package/lib/commonjs/capabilities/configuration/src/brands/checkVisualEligibility.js.map +1 -1
  4. package/lib/commonjs/capabilities/configuration/src/brands/createDerivedBrands.js +8 -19
  5. package/lib/commonjs/capabilities/configuration/src/brands/createDerivedBrands.js.map +1 -1
  6. package/lib/commonjs/capabilities/offer-catalog/src/utils/formatUtils.js +36 -21
  7. package/lib/commonjs/capabilities/offer-catalog/src/utils/formatUtils.js.map +1 -1
  8. package/lib/commonjs/capabilities/offer-catalog/src/utils/stats/formatters/annualFee.js +7 -30
  9. package/lib/commonjs/capabilities/offer-catalog/src/utils/stats/formatters/annualFee.js.map +1 -1
  10. package/lib/commonjs/capabilities/offer-catalog/src/utils/stats/formatters/purchaseApr.js +15 -17
  11. package/lib/commonjs/capabilities/offer-catalog/src/utils/stats/formatters/purchaseApr.js.map +1 -1
  12. package/lib/commonjs/capabilities/offer-catalog/src/utils/stats/formatters/recommendedCredit.js +8 -2
  13. package/lib/commonjs/capabilities/offer-catalog/src/utils/stats/formatters/recommendedCredit.js.map +1 -1
  14. package/lib/commonjs/capabilities/offer-catalog/src/utils/stats/index.js +40 -38
  15. package/lib/commonjs/capabilities/offer-catalog/src/utils/stats/index.js.map +1 -1
  16. package/lib/commonjs/capabilities/offers/pipeline/src/sources/ratetables/withDeviceSignals.js +22 -12
  17. package/lib/commonjs/capabilities/offers/pipeline/src/sources/ratetables/withDeviceSignals.js.map +1 -1
  18. package/lib/commonjs/capabilities/ui/elements/src/components/MarkdownText/components.js +120 -116
  19. package/lib/commonjs/capabilities/ui/elements/src/components/MarkdownText/components.js.map +1 -1
  20. package/lib/commonjs/capabilities/ui/elements/src/components/MarkdownText/index.js +8 -30
  21. package/lib/commonjs/capabilities/ui/elements/src/components/MarkdownText/index.js.map +1 -1
  22. package/lib/commonjs/components/DynamicOffers/Render/Offer.js +51 -49
  23. package/lib/commonjs/components/DynamicOffers/Render/Offer.js.map +1 -1
  24. package/lib/commonjs/version.js +1 -1
  25. package/lib/module/capabilities/configuration/src/brands/checkVisualEligibility.js +13 -11
  26. package/lib/module/capabilities/configuration/src/brands/checkVisualEligibility.js.map +1 -1
  27. package/lib/module/capabilities/configuration/src/brands/createDerivedBrands.js +7 -19
  28. package/lib/module/capabilities/configuration/src/brands/createDerivedBrands.js.map +1 -1
  29. package/lib/module/capabilities/offer-catalog/src/utils/formatUtils.js +35 -20
  30. package/lib/module/capabilities/offer-catalog/src/utils/formatUtils.js.map +1 -1
  31. package/lib/module/capabilities/offer-catalog/src/utils/stats/formatters/annualFee.js +7 -30
  32. package/lib/module/capabilities/offer-catalog/src/utils/stats/formatters/annualFee.js.map +1 -1
  33. package/lib/module/capabilities/offer-catalog/src/utils/stats/formatters/purchaseApr.js +15 -17
  34. package/lib/module/capabilities/offer-catalog/src/utils/stats/formatters/purchaseApr.js.map +1 -1
  35. package/lib/module/capabilities/offer-catalog/src/utils/stats/formatters/recommendedCredit.js +8 -2
  36. package/lib/module/capabilities/offer-catalog/src/utils/stats/formatters/recommendedCredit.js.map +1 -1
  37. package/lib/module/capabilities/offer-catalog/src/utils/stats/index.js +40 -38
  38. package/lib/module/capabilities/offer-catalog/src/utils/stats/index.js.map +1 -1
  39. package/lib/module/capabilities/offers/pipeline/src/sources/ratetables/withDeviceSignals.js +22 -11
  40. package/lib/module/capabilities/offers/pipeline/src/sources/ratetables/withDeviceSignals.js.map +1 -1
  41. package/lib/module/capabilities/ui/elements/src/components/MarkdownText/components.js +120 -115
  42. package/lib/module/capabilities/ui/elements/src/components/MarkdownText/components.js.map +1 -1
  43. package/lib/module/capabilities/ui/elements/src/components/MarkdownText/index.js +9 -31
  44. package/lib/module/capabilities/ui/elements/src/components/MarkdownText/index.js.map +1 -1
  45. package/lib/module/components/DynamicOffers/Render/Offer.js +51 -49
  46. package/lib/module/components/DynamicOffers/Render/Offer.js.map +1 -1
  47. package/lib/module/version.js +1 -1
  48. package/lib/typescript/capabilities/configuration/src/brands/checkVisualEligibility.d.ts.map +1 -1
  49. package/lib/typescript/capabilities/configuration/src/brands/createDerivedBrands.d.ts.map +1 -1
  50. package/lib/typescript/capabilities/offer-catalog/src/utils/formatUtils.d.ts.map +1 -1
  51. package/lib/typescript/capabilities/offer-catalog/src/utils/stats/formatters/annualFee.d.ts.map +1 -1
  52. package/lib/typescript/capabilities/offer-catalog/src/utils/stats/formatters/purchaseApr.d.ts.map +1 -1
  53. package/lib/typescript/capabilities/offer-catalog/src/utils/stats/formatters/recommendedCredit.d.ts.map +1 -1
  54. package/lib/typescript/capabilities/offer-catalog/src/utils/stats/index.d.ts.map +1 -1
  55. package/lib/typescript/capabilities/offers/pipeline/src/sources/ratetables/withDeviceSignals.d.ts +4 -192
  56. package/lib/typescript/capabilities/offers/pipeline/src/sources/ratetables/withDeviceSignals.d.ts.map +1 -1
  57. package/lib/typescript/capabilities/ui/elements/src/components/MarkdownText/components.d.ts +12 -3
  58. package/lib/typescript/capabilities/ui/elements/src/components/MarkdownText/components.d.ts.map +1 -1
  59. package/lib/typescript/capabilities/ui/elements/src/components/MarkdownText/index.d.ts.map +1 -1
  60. package/lib/typescript/components/DynamicOffers/Render/Offer.d.ts.map +1 -1
  61. package/lib/typescript/version.d.ts +1 -1
  62. package/package.json +3 -8
  63. package/src/capabilities/configuration/src/brands/checkVisualEligibility.ts +22 -16
  64. package/src/capabilities/configuration/src/brands/createDerivedBrands.ts +10 -23
  65. package/src/capabilities/offer-catalog/src/utils/formatUtils.ts +38 -19
  66. package/src/capabilities/offer-catalog/src/utils/stats/formatters/annualFee.ts +19 -46
  67. package/src/capabilities/offer-catalog/src/utils/stats/formatters/purchaseApr.ts +17 -21
  68. package/src/capabilities/offer-catalog/src/utils/stats/formatters/recommendedCredit.ts +11 -8
  69. package/src/capabilities/offer-catalog/src/utils/stats/index.ts +40 -109
  70. package/src/capabilities/offers/pipeline/src/sources/ratetables/withDeviceSignals.ts +26 -17
  71. package/src/capabilities/ui/elements/src/components/MarkdownText/components.tsx +157 -142
  72. package/src/capabilities/ui/elements/src/components/MarkdownText/index.tsx +11 -33
  73. package/src/components/DynamicOffers/Render/Offer.tsx +34 -33
  74. package/src/version.ts +1 -1
@@ -1,5 +1,4 @@
1
1
  import { get } from "radash";
2
- import { P, match } from "ts-pattern";
3
2
  import type { StatElementProps } from "../types";
4
3
  import { formatStringListWithAnd } from "../../formatUtils";
5
4
  import type { BaseOffer } from "../../../types/offerCatalogSchema";
@@ -28,13 +27,17 @@ export const recommendedCredit =
28
27
  ({ label, fieldName }: RecommendedCreditStat): StatElementProps => {
29
28
  const recommendedCreditValue = get<string[]>(offer, fieldName);
30
29
 
31
- const content = match(recommendedCreditValue)
32
- .with(P.array(), (value) =>
33
- hasAllRecommendedRatings(value)
34
- ? "Any"
35
- : formatStringListWithAnd(orderRecommendedRatings(value))
36
- )
37
- .otherwise(() => "See Terms");
30
+ let content = "See Terms";
31
+
32
+ if (Array.isArray(recommendedCreditValue)) {
33
+ if (hasAllRecommendedRatings(recommendedCreditValue)) {
34
+ content = "Any";
35
+ } else {
36
+ content = formatStringListWithAnd(
37
+ orderRecommendedRatings(recommendedCreditValue)
38
+ );
39
+ }
40
+ }
38
41
 
39
42
  return {
40
43
  label,
@@ -1,5 +1,3 @@
1
- import { match } from "ts-pattern";
2
-
3
1
  import {
4
2
  annualFee,
5
3
  creditBureaus,
@@ -29,113 +27,46 @@ export const statsToElementPropsBuilder = (
29
27
  offer: BaseOffer
30
28
  ): StatElementProps[] =>
31
29
  stats
32
- .map((stat) =>
33
- match(stat)
34
- .with(
35
- {
36
- format: "rangeCurrency",
37
- },
38
- fromRangeCurrencyStat(offer)
39
- )
40
- .with(
41
- {
42
- format: "rangeCurrencyUnabbreviated",
43
- },
44
- fromRangeCurrencyUnabbreviatedStat(offer)
45
- )
46
- .with(
47
- {
48
- format: "BureausStat",
49
- },
50
- creditBureaus(offer)
51
- )
52
- .with(
53
- {
54
- format: "rangePercent",
55
- },
56
- fromRangePercentStat(offer)
57
- )
58
- .with(
59
- {
60
- format: "rangeCurrencyOrBasis",
61
- },
62
- fromRangeCurrencyOrBasisStat(offer)
63
- )
64
- .with(
65
- {
66
- format: "common",
67
- },
68
- fromCommonStat(offer)
69
- )
70
- .with(
71
- {
72
- format: "rangeCurrencyByTime",
73
- },
74
- fromRangeCurrencyByTimeStat(offer)
75
- )
76
- .with(
77
- {
78
- format: "freeTrial",
79
- },
80
- fromFreeTrialStat(offer)
81
- )
82
- .with(
83
- {
84
- format: "monthlyOrAnnualCurrency",
85
- },
86
- fromMonthlyOrAnnualCurrencyStat(offer)
87
- )
88
- .with(
89
- {
90
- format: "boolean",
91
- },
92
- fromBooleanStat(offer)
93
- )
94
- .with({ format: "rangeMonths" }, fromRangeMonthsStat(offer))
95
- .with(
96
- {
97
- format: "listStringWithAnd",
98
- },
99
- fromListStringWithAnd(offer)
100
- )
101
- .with(
102
- {
103
- format: "currency",
104
- },
105
- fromCurrencyStat(offer)
106
- )
107
- .with(
108
- {
109
- format: "percentage",
110
- },
111
- fromPercentageStat(offer)
112
- )
113
- .with(
114
- {
115
- format: "recommendedCredit",
116
- },
117
- recommendedCredit(offer)
118
- )
119
- .with(
120
- {
121
- format: "rewardsDisplay",
122
- },
123
- rewardsDisplay(offer)
124
- )
125
- .with(
126
- {
127
- format: "purchaseApr",
128
- },
129
- purchaseApr(offer)
130
- )
131
- .with(
132
- {
133
- format: "annualFee",
134
- },
135
- annualFee(offer)
136
- )
137
- .exhaustive()
138
- )
30
+ .map((stat): StatElementProps => {
31
+ switch (stat.format) {
32
+ case "rangeCurrency":
33
+ return fromRangeCurrencyStat(offer)(stat);
34
+ case "rangeCurrencyUnabbreviated":
35
+ return fromRangeCurrencyUnabbreviatedStat(offer)(stat);
36
+ case "BureausStat":
37
+ return creditBureaus(offer)(stat);
38
+ case "rangePercent":
39
+ return fromRangePercentStat(offer)(stat);
40
+ case "rangeCurrencyOrBasis":
41
+ return fromRangeCurrencyOrBasisStat(offer)(stat);
42
+ case "common":
43
+ return fromCommonStat(offer)(stat);
44
+ case "rangeCurrencyByTime":
45
+ return fromRangeCurrencyByTimeStat(offer)(stat);
46
+ case "freeTrial":
47
+ return fromFreeTrialStat(offer)(stat);
48
+ case "monthlyOrAnnualCurrency":
49
+ return fromMonthlyOrAnnualCurrencyStat(offer)(stat);
50
+ case "boolean":
51
+ return fromBooleanStat(offer)(stat);
52
+ case "rangeMonths":
53
+ return fromRangeMonthsStat(offer)(stat);
54
+ case "listStringWithAnd":
55
+ return fromListStringWithAnd(offer)(stat);
56
+ case "currency":
57
+ return fromCurrencyStat(offer)(stat);
58
+ case "percentage":
59
+ return fromPercentageStat(offer)(stat);
60
+ case "recommendedCredit":
61
+ return recommendedCredit(offer)(stat);
62
+ case "rewardsDisplay":
63
+ return rewardsDisplay(offer)(stat);
64
+ case "purchaseApr":
65
+ return purchaseApr(offer)(stat);
66
+ case "annualFee":
67
+ return annualFee(offer)(stat);
68
+ }
69
+ })
139
70
  .filter((stat) => stat !== null);
140
71
 
141
72
  export type { Stat, StatElementProps } from "./types";
@@ -1,4 +1,3 @@
1
- import defu from "defu";
2
1
  import { get, mapValues } from "radash";
3
2
  import { createDerivedBrands } from "../../../../../configuration/src/brands/createDerivedBrands";
4
3
  import type { CnfContext } from "../../../../../core/src/system/cnfContext/CnfContext";
@@ -63,21 +62,31 @@ export function withDeviceSignals<
63
62
  cnfEnvironment,
64
63
  };
65
64
 
66
- return defu(payload, {
67
- /**
68
- * The leads API required device ID's be in the UUID format. If the string
69
- * we receive here is not in the expected format, we will create an error
70
- * passing it to the API.
71
- */
65
+ // all clientTag values must be arrays of strings
66
+ const toStringArray = (value: unknown): string[] =>
67
+ Array.isArray(value) ? value.map(String) : [String(value)];
68
+
69
+ const defaultClientTags = mapValues(clientTags, toStringArray);
70
+ const payloadClientTags = mapValues(
71
+ (payload.clientTags ?? {}) as Record<string, unknown>,
72
+ toStringArray
73
+ );
74
+
75
+ const mergedClientTags: Record<string, string[]> = { ...defaultClientTags };
76
+ for (const [key, value] of Object.entries(payloadClientTags)) {
77
+ const existing = mergedClientTags[key];
78
+ mergedClientTags[key] = existing ? [...value, ...existing] : value;
79
+ }
80
+
81
+ /**
82
+ * The leads API requires device IDs be in the UUID format. If the string
83
+ * we receive here is not in the expected format, we omit it so the API can
84
+ * reject the request explicitly.
85
+ */
86
+ return {
72
87
  deviceId: isUUIDv4(maybeDeviceId) ? maybeDeviceId : undefined,
73
- sessionInformation: {
74
- ipAddress,
75
- userAgent,
76
- },
77
- clientTags: mapValues(
78
- clientTags,
79
- // all values must be arrays of strings
80
- (value) => (Array.isArray(value) ? value.map(String) : [String(value)])
81
- ),
82
- });
88
+ sessionInformation: { ipAddress, userAgent },
89
+ ...payload,
90
+ clientTags: mergedClientTags,
91
+ };
83
92
  }
@@ -1,18 +1,21 @@
1
1
  import React from "react";
2
- import { StyleSheet } from "react-native";
2
+ import { Linking, StyleSheet } from "react-native";
3
3
  import { Abbreviation } from "./Abbreviation";
4
- import {
5
- openUrl,
6
- type ASTNode,
7
- type RenderRules,
8
- } from "react-native-markdown-display";
4
+ import { lexer } from "marked";
9
5
  import Text, {
6
+ type TextProps,
10
7
  type TextWeight,
11
8
  type Variant,
12
9
  } from "../../../../../../components/Text";
13
10
  import type { ThemeColors } from "../../../../../../context/ThemeProvider";
14
11
 
15
- const BoldText = ({ children }: { children: React.ReactNode }) => {
12
+ const BoldText = ({
13
+ children,
14
+ testID,
15
+ }: {
16
+ children: React.ReactNode;
17
+ testID: TextProps["testID"];
18
+ }) => {
16
19
  const processChildren = (_children: React.ReactNode) => {
17
20
  return React.Children.map(_children, (child) => {
18
21
  if (typeof child === "string") {
@@ -20,7 +23,6 @@ const BoldText = ({ children }: { children: React.ReactNode }) => {
20
23
  }
21
24
 
22
25
  if (React.isValidElement(child) && child.type === Text) {
23
- // Use a properly typed props object
24
26
  const newProps = {
25
27
  weight: "bold" as TextWeight,
26
28
  style: child.props.style,
@@ -30,140 +32,164 @@ const BoldText = ({ children }: { children: React.ReactNode }) => {
30
32
  return child;
31
33
  });
32
34
  };
33
- return <>{processChildren(children)}</>;
35
+ return <Text testID={testID}>{processChildren(children)}</Text>;
34
36
  };
35
37
 
36
- // Helper to create text variants
37
- const createTextVariant =
38
- (props: any) => (_node: ASTNode, children: React.ReactNode) => {
39
- return <Text {...props}>{children}</Text>;
40
- };
41
-
42
- export const createMarkdownComponents = ({
43
- numberOfLines,
44
- variant,
45
- weight,
46
- color,
47
- }: {
38
+ export type RenderProps = {
48
39
  numberOfLines?: number;
49
40
  variant?: Variant;
50
41
  weight?: TextWeight;
51
42
  color?: keyof ThemeColors;
52
- }): RenderRules => {
53
- // Keep track of the first list item
54
- let isFirstListItem = true;
55
-
56
- return {
57
- // Headings
58
- heading1: createTextVariant({ variant: "title-1" }),
59
- heading2: createTextVariant({ variant: "title-2" }),
60
- heading3: createTextVariant({ variant: "title-3" }),
61
- heading4: createTextVariant({ variant: "title-4" }),
62
- heading5: createTextVariant({ variant: "title-5" }),
63
-
64
- // Lists
65
- bullet_list: (node: ASTNode, children: React.ReactNode) => {
66
- // Reset the flag when a new list starts
67
- isFirstListItem = true;
68
- return (
69
- <Text
70
- key={node.key || `${node.type}-${node.index}`}
71
- variant={variant}
72
- weight={weight}
73
- color={color}
74
- numberOfLines={numberOfLines}
75
- style={styles.bulletList}
76
- >
77
- {children}
78
- </Text>
79
- );
80
- },
81
-
82
- // Links - Add detection for abbreviations in the text content
83
- link: (node: ASTNode, children: React.ReactNode) => {
84
- // Check if this link has a title attribute - if so, treat it as an abbreviation
85
- if (node.attributes && node.attributes.title) {
43
+ };
44
+
45
+ // infer the type based on our entry point for rendering tokens
46
+ type AssumedTokenType = ReturnType<typeof lexer>[number];
47
+
48
+ /**
49
+ * Parses `content` and renders the marked token tree to React Native
50
+ * components.
51
+ *
52
+ * Recursively renders a marked token tree to React Native components. Other
53
+ * methods from marked are not suitable, as we need to build a component node
54
+ * and thread all the children into the parent element.
55
+ */
56
+ export function renderMarkdown(
57
+ content: string,
58
+ { numberOfLines, ...props }: RenderProps
59
+ ): React.ReactNode {
60
+ const tokens = lexer(content, { gfm: false });
61
+ let nodeIdx = 0;
62
+
63
+ function renderTokens(
64
+ tokenList: AssumedTokenType[] | undefined
65
+ ): React.ReactNode {
66
+ if (!tokenList || tokenList.length === 0) {
67
+ return null;
68
+ }
69
+ return tokenList.map((token) => renderToken(token));
70
+ }
71
+
72
+ function renderToken(token: AssumedTokenType): React.ReactNode {
73
+ const id = nodeIdx++;
74
+ const key = `${token.type}-${id}`;
75
+
76
+ // general reference to child tokens for DRY-ness
77
+ const childTokens =
78
+ "tokens" in token && token.tokens ? token.tokens : undefined;
79
+
80
+ switch (token.type) {
81
+ case "heading": {
82
+ const variant = `title-${token.depth}` as Variant;
83
+
86
84
  return (
87
- <Abbreviation
88
- key={node.key || `${node.type}-${node.index}`}
89
- title={node.attributes.title}
85
+ <Text
86
+ key={key}
87
+ variant={variant}
88
+ testID={`heading${token.depth}-${id}`}
90
89
  >
91
- {children}
92
- </Abbreviation>
90
+ {renderTokens(childTokens)}
91
+ </Text>
93
92
  );
94
93
  }
95
94
 
96
- return (
97
- <Text
98
- key={node.key || `${node.type}-${node.index}`}
99
- variant={variant}
100
- weight={weight}
101
- color={color}
102
- style={styles.linkText}
103
- onPress={() => openUrl(node.attributes.href || "")}
104
- >
105
- {children}
106
- </Text>
107
- );
108
- },
109
-
110
- // Custom parser for text to find potential abbreviation patterns
111
- text: (node: ASTNode) => {
112
- // If this implementation doesn't catch abbreviations, we'll need to
113
- // pre-process the markdown before passing it to the renderer
114
- return (
115
- <Text
116
- key={node.key || `${node.type}-${node.index}`}
117
- variant={variant}
118
- weight={weight}
119
- color={color}
120
- >
121
- {node.content}
122
- </Text>
123
- );
124
- },
125
-
126
- // List items
127
- list_item: (node: ASTNode, children: React.ReactNode) => {
128
- // Only add \n if this is not the first item
129
- const prefix = isFirstListItem ? "" : "\n";
130
- // Set flag to false after the first item
131
- isFirstListItem = false;
132
-
133
- return (
134
- <Text
135
- key={node.key || `${node.type}-${node.index}`}
136
- variant={variant || "body-3"}
137
- weight={weight}
138
- color={color}
139
- >
140
- <Text variant={"body-1"}>{prefix}• </Text>
141
- {children}
142
- </Text>
143
- );
144
- },
145
-
146
- // Paragraphs
147
- paragraph: (node: ASTNode, children: React.ReactNode) => {
148
- return (
149
- <Text
150
- key={node.key || `${node.type}-${node.index}`}
151
- variant={variant}
152
- weight={weight}
153
- color={color}
154
- >
155
- {children}
156
- </Text>
157
- );
158
- },
159
-
160
- strong: (node, children) => (
161
- <BoldText key={node.key || `${node.type}-${node.index}`}>
162
- {children}
163
- </BoldText>
164
- ),
165
- };
166
- };
95
+ case "paragraph":
96
+ return (
97
+ <Text key={key} {...props} testID={`paragraph-${id}`}>
98
+ {renderTokens(childTokens)}
99
+ </Text>
100
+ );
101
+
102
+ case "list": {
103
+ // attempt to assert child items as an array, since it is typed as any
104
+ const tokenItems: AssumedTokenType[] =
105
+ token.items && Array.isArray(token.items) ? token.items : [];
106
+
107
+ const renderedItems = tokenItems.map((item, i) => {
108
+ const itemId = nodeIdx++;
109
+ const prefix = i === 0 ? "" : "\n";
110
+
111
+ return (
112
+ <Text
113
+ key={`list_item-${itemId}`}
114
+ {...props}
115
+ variant={props.variant || "body-3"}
116
+ testID={`list_item-${itemId}`}
117
+ >
118
+ <Text variant="body-1">{prefix}• </Text>
119
+ {"tokens" in item ? renderTokens(item.tokens) : null}
120
+ </Text>
121
+ );
122
+ });
123
+
124
+ return (
125
+ <Text
126
+ key={key}
127
+ {...props}
128
+ numberOfLines={numberOfLines}
129
+ style={styles.bulletList}
130
+ testID={`bullet_list-${id}`}
131
+ >
132
+ {renderedItems}
133
+ </Text>
134
+ );
135
+ }
136
+
137
+ case "strong":
138
+ return (
139
+ <BoldText key={key} testID={`strong-${id}`}>
140
+ {renderTokens(childTokens)}
141
+ </BoldText>
142
+ );
143
+
144
+ case "text": {
145
+ const inlineChildren = renderTokens(childTokens);
146
+ if (inlineChildren) {
147
+ return <React.Fragment key={key}>{inlineChildren}</React.Fragment>;
148
+ }
149
+
150
+ return (
151
+ <Text key={key} {...props}>
152
+ {token.text}
153
+ </Text>
154
+ );
155
+ }
156
+
157
+ case "escape":
158
+ return (
159
+ <Text key={key} {...props}>
160
+ {token.text}
161
+ </Text>
162
+ );
163
+
164
+ case "link": {
165
+ if (token.title) {
166
+ return (
167
+ <Abbreviation key={key} title={token.title}>
168
+ {renderTokens(childTokens)}
169
+ </Abbreviation>
170
+ );
171
+ }
172
+
173
+ return (
174
+ <Text
175
+ key={key}
176
+ {...props}
177
+ style={styles.linkText}
178
+ onPress={() => Linking.openURL(token.href)}
179
+ testID={`link-${id}`}
180
+ >
181
+ {renderTokens(childTokens)}
182
+ </Text>
183
+ );
184
+ }
185
+
186
+ default:
187
+ return null;
188
+ }
189
+ }
190
+
191
+ return renderTokens(tokens);
192
+ }
167
193
 
168
194
  const styles = StyleSheet.create({
169
195
  bulletList: {
@@ -171,17 +197,6 @@ const styles = StyleSheet.create({
171
197
  flexDirection: "column",
172
198
  alignItems: "flex-start",
173
199
  },
174
- bulletPoint: {
175
- width: 6,
176
- height: 6,
177
- borderRadius: 3,
178
- backgroundColor: "black",
179
- marginTop: 8,
180
- marginRight: 8,
181
- },
182
- listItemText: {
183
- marginBottom: 4,
184
- },
185
200
  linkText: {
186
201
  textDecorationLine: "underline",
187
202
  },
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
- import { createMarkdownComponents } from "./components";
2
+ import { View } from "react-native";
3
+ import { renderMarkdown } from "./components";
3
4
  import { preprocessMarkdown } from "./markdownPreprocessor";
4
- import Markdown from "react-native-markdown-display";
5
5
  import type { TextProps } from "../../../../../../components/Text";
6
6
 
7
7
  export interface Props extends TextProps {
@@ -15,38 +15,16 @@ export const MarkdownText = ({
15
15
  weight,
16
16
  variant,
17
17
  }: Props) => {
18
- // Create style object for text properties
19
- const textStyle = {
20
- color: color,
21
- };
18
+ const preparedContent = preprocessMarkdown(content);
22
19
 
23
- // Prepare styles for markdown
24
- const markdownStyles = {
25
- body: {
26
- ...textStyle,
27
- flexShrink: 1,
28
- },
29
- paragraph: {
30
- flexShrink: 1,
31
- },
32
- // Include styles for all markdown elements that need to respect text properties
33
- text: {
34
- ...textStyle,
35
- },
36
- };
37
-
38
- // Use the factory function to create components with numberOfLines support
39
- const customRules = createMarkdownComponents({
40
- numberOfLines,
41
- variant,
42
- weight,
43
- color,
44
- });
45
- // Preprocess the markdown to handle abbreviations
46
- const processedContent = preprocessMarkdown(content);
47
20
  return (
48
- <Markdown rules={customRules} style={markdownStyles}>
49
- {processedContent}
50
- </Markdown>
21
+ <View style={{ flexShrink: 1 }}>
22
+ {renderMarkdown(preparedContent, {
23
+ numberOfLines,
24
+ color,
25
+ weight,
26
+ variant,
27
+ })}
28
+ </View>
51
29
  );
52
30
  };