@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.
- package/CHANGELOG.md +8 -0
- package/lib/commonjs/capabilities/configuration/src/brands/checkVisualEligibility.js +13 -11
- package/lib/commonjs/capabilities/configuration/src/brands/checkVisualEligibility.js.map +1 -1
- package/lib/commonjs/capabilities/configuration/src/brands/createDerivedBrands.js +8 -19
- package/lib/commonjs/capabilities/configuration/src/brands/createDerivedBrands.js.map +1 -1
- package/lib/commonjs/capabilities/offer-catalog/src/utils/formatUtils.js +36 -21
- package/lib/commonjs/capabilities/offer-catalog/src/utils/formatUtils.js.map +1 -1
- package/lib/commonjs/capabilities/offer-catalog/src/utils/stats/formatters/annualFee.js +7 -30
- package/lib/commonjs/capabilities/offer-catalog/src/utils/stats/formatters/annualFee.js.map +1 -1
- package/lib/commonjs/capabilities/offer-catalog/src/utils/stats/formatters/purchaseApr.js +15 -17
- package/lib/commonjs/capabilities/offer-catalog/src/utils/stats/formatters/purchaseApr.js.map +1 -1
- package/lib/commonjs/capabilities/offer-catalog/src/utils/stats/formatters/recommendedCredit.js +8 -2
- package/lib/commonjs/capabilities/offer-catalog/src/utils/stats/formatters/recommendedCredit.js.map +1 -1
- package/lib/commonjs/capabilities/offer-catalog/src/utils/stats/index.js +40 -38
- package/lib/commonjs/capabilities/offer-catalog/src/utils/stats/index.js.map +1 -1
- package/lib/commonjs/capabilities/offers/pipeline/src/sources/ratetables/withDeviceSignals.js +22 -12
- package/lib/commonjs/capabilities/offers/pipeline/src/sources/ratetables/withDeviceSignals.js.map +1 -1
- package/lib/commonjs/capabilities/ui/elements/src/components/MarkdownText/components.js +120 -116
- package/lib/commonjs/capabilities/ui/elements/src/components/MarkdownText/components.js.map +1 -1
- package/lib/commonjs/capabilities/ui/elements/src/components/MarkdownText/index.js +8 -30
- package/lib/commonjs/capabilities/ui/elements/src/components/MarkdownText/index.js.map +1 -1
- package/lib/commonjs/components/DynamicOffers/Render/Offer.js +51 -49
- package/lib/commonjs/components/DynamicOffers/Render/Offer.js.map +1 -1
- package/lib/commonjs/version.js +1 -1
- package/lib/module/capabilities/configuration/src/brands/checkVisualEligibility.js +13 -11
- package/lib/module/capabilities/configuration/src/brands/checkVisualEligibility.js.map +1 -1
- package/lib/module/capabilities/configuration/src/brands/createDerivedBrands.js +7 -19
- package/lib/module/capabilities/configuration/src/brands/createDerivedBrands.js.map +1 -1
- package/lib/module/capabilities/offer-catalog/src/utils/formatUtils.js +35 -20
- package/lib/module/capabilities/offer-catalog/src/utils/formatUtils.js.map +1 -1
- package/lib/module/capabilities/offer-catalog/src/utils/stats/formatters/annualFee.js +7 -30
- package/lib/module/capabilities/offer-catalog/src/utils/stats/formatters/annualFee.js.map +1 -1
- package/lib/module/capabilities/offer-catalog/src/utils/stats/formatters/purchaseApr.js +15 -17
- package/lib/module/capabilities/offer-catalog/src/utils/stats/formatters/purchaseApr.js.map +1 -1
- package/lib/module/capabilities/offer-catalog/src/utils/stats/formatters/recommendedCredit.js +8 -2
- package/lib/module/capabilities/offer-catalog/src/utils/stats/formatters/recommendedCredit.js.map +1 -1
- package/lib/module/capabilities/offer-catalog/src/utils/stats/index.js +40 -38
- package/lib/module/capabilities/offer-catalog/src/utils/stats/index.js.map +1 -1
- package/lib/module/capabilities/offers/pipeline/src/sources/ratetables/withDeviceSignals.js +22 -11
- package/lib/module/capabilities/offers/pipeline/src/sources/ratetables/withDeviceSignals.js.map +1 -1
- package/lib/module/capabilities/ui/elements/src/components/MarkdownText/components.js +120 -115
- package/lib/module/capabilities/ui/elements/src/components/MarkdownText/components.js.map +1 -1
- package/lib/module/capabilities/ui/elements/src/components/MarkdownText/index.js +9 -31
- package/lib/module/capabilities/ui/elements/src/components/MarkdownText/index.js.map +1 -1
- package/lib/module/components/DynamicOffers/Render/Offer.js +51 -49
- package/lib/module/components/DynamicOffers/Render/Offer.js.map +1 -1
- package/lib/module/version.js +1 -1
- package/lib/typescript/capabilities/configuration/src/brands/checkVisualEligibility.d.ts.map +1 -1
- package/lib/typescript/capabilities/configuration/src/brands/createDerivedBrands.d.ts.map +1 -1
- package/lib/typescript/capabilities/offer-catalog/src/utils/formatUtils.d.ts.map +1 -1
- package/lib/typescript/capabilities/offer-catalog/src/utils/stats/formatters/annualFee.d.ts.map +1 -1
- package/lib/typescript/capabilities/offer-catalog/src/utils/stats/formatters/purchaseApr.d.ts.map +1 -1
- package/lib/typescript/capabilities/offer-catalog/src/utils/stats/formatters/recommendedCredit.d.ts.map +1 -1
- package/lib/typescript/capabilities/offer-catalog/src/utils/stats/index.d.ts.map +1 -1
- package/lib/typescript/capabilities/offers/pipeline/src/sources/ratetables/withDeviceSignals.d.ts +4 -192
- package/lib/typescript/capabilities/offers/pipeline/src/sources/ratetables/withDeviceSignals.d.ts.map +1 -1
- package/lib/typescript/capabilities/ui/elements/src/components/MarkdownText/components.d.ts +12 -3
- package/lib/typescript/capabilities/ui/elements/src/components/MarkdownText/components.d.ts.map +1 -1
- package/lib/typescript/capabilities/ui/elements/src/components/MarkdownText/index.d.ts.map +1 -1
- package/lib/typescript/components/DynamicOffers/Render/Offer.d.ts.map +1 -1
- package/lib/typescript/version.d.ts +1 -1
- package/package.json +3 -8
- package/src/capabilities/configuration/src/brands/checkVisualEligibility.ts +22 -16
- package/src/capabilities/configuration/src/brands/createDerivedBrands.ts +10 -23
- package/src/capabilities/offer-catalog/src/utils/formatUtils.ts +38 -19
- package/src/capabilities/offer-catalog/src/utils/stats/formatters/annualFee.ts +19 -46
- package/src/capabilities/offer-catalog/src/utils/stats/formatters/purchaseApr.ts +17 -21
- package/src/capabilities/offer-catalog/src/utils/stats/formatters/recommendedCredit.ts +11 -8
- package/src/capabilities/offer-catalog/src/utils/stats/index.ts +40 -109
- package/src/capabilities/offers/pipeline/src/sources/ratetables/withDeviceSignals.ts +26 -17
- package/src/capabilities/ui/elements/src/components/MarkdownText/components.tsx +157 -142
- package/src/capabilities/ui/elements/src/components/MarkdownText/index.tsx +11 -33
- package/src/components/DynamicOffers/Render/Offer.tsx +34 -33
- 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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
75
|
-
|
|
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 = ({
|
|
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
|
|
35
|
+
return <Text testID={testID}>{processChildren(children)}</Text>;
|
|
34
36
|
};
|
|
35
37
|
|
|
36
|
-
|
|
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
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
<
|
|
88
|
-
key={
|
|
89
|
-
|
|
85
|
+
<Text
|
|
86
|
+
key={key}
|
|
87
|
+
variant={variant}
|
|
88
|
+
testID={`heading${token.depth}-${id}`}
|
|
90
89
|
>
|
|
91
|
-
{
|
|
92
|
-
</
|
|
90
|
+
{renderTokens(childTokens)}
|
|
91
|
+
</Text>
|
|
93
92
|
);
|
|
94
93
|
}
|
|
95
94
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
key={
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
<
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
-
<
|
|
49
|
-
{
|
|
50
|
-
|
|
21
|
+
<View style={{ flexShrink: 1 }}>
|
|
22
|
+
{renderMarkdown(preparedContent, {
|
|
23
|
+
numberOfLines,
|
|
24
|
+
color,
|
|
25
|
+
weight,
|
|
26
|
+
variant,
|
|
27
|
+
})}
|
|
28
|
+
</View>
|
|
51
29
|
);
|
|
52
30
|
};
|