Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement markdown in the prompt #258

Merged
merged 2 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,21 @@ const logout = useCallback(() => {
}, []);
```

## Supporting Markdown in the prompt

To support Markdown in the prompt, you'll need to provide a Markdown renderer. We recommend you use [react-native-markdown-display](https://github.com/iamacup/react-native-markdown-display), however you can provide your own component that is an `React.ElementType` and accepts the markdown string as it's children.


```JSX
import Markdown from 'react-native-markdown-display';

Iterate.init({
apiKey: apiKey,
safeArea: useSafeAreaInsets,
storage: SecureStorage,
markdown: Markdown
});
```

## Survey eligibility and frequency

Expand Down
1 change: 1 addition & 0 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"react-dom": "18.2.0",
"react-native": "0.72.6",
"react-native-encrypted-storage": "^4.0.3",
"react-native-markdown-display": "^7.0.0-alpha.2",
"react-native-safe-area-context": "^4.7.4",
"react-native-web": "~0.19.6",
"react-native-webview": "^13.6.2"
Expand Down
10 changes: 2 additions & 8 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,15 @@ import {
useSafeAreaInsets,
} from 'react-native-safe-area-context';
import SecureStorage from 'react-native-encrypted-storage';
import Markdown from 'react-native-markdown-display';

const App = () => {
React.useEffect(() => {
Iterate.init({
apiKey: apiKey,
safeArea: useSafeAreaInsets,
storage: SecureStorage,
buttonFont: {
filename: 'WorkSans-Regular.ttf',
postscriptName: 'WorkSans-Regular',
},
surveyTextFont: {
filename: 'Merriweather-Regular.ttf',
postscriptName: 'Merriweather-Regular',
},
markdown: Markdown,
});

Iterate.onResponse((response, question, survey) => {
Expand Down
40 changes: 31 additions & 9 deletions src/components/Prompt/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type { Survey } from '../../types';
import PromptButton from './Button';
import type { Dispatch } from '../../iterate';
import Iterate from '../../iterate';
import markdown from '../../markdown';
import { InteractionEvents } from '../../interaction-events';
import type { InteractionEventSource } from '../../interaction-events';

Expand Down Expand Up @@ -114,6 +115,19 @@ const Prompt: (Props: Props) => JSX.Element = ({

const paddingBottom = safeAreaInsets.bottom > 0 ? safeAreaInsets.bottom : 20;

const promptTextStyle = [
styles.promptText,
{
color: promptTextColor,
},
// To correctly render markdown, only set the fontFamily if it's not null
Iterate.surveyTextFont?.postscriptName != null
? {
fontFamily: Iterate.surveyTextFont?.postscriptName,
}
: null,
];

return (
<Animated.View
style={{
Expand All @@ -137,17 +151,25 @@ const Prompt: (Props: Props) => JSX.Element = ({
>
<View style={{ paddingBottom }}>
<CloseButton onPress={onDismissAnimated} />
<Text
style={[
styles.promptText,
{markdown.Render(survey?.prompt?.message ?? '', {
body: [
promptTextStyle,
{
color: promptTextColor,
fontFamily: Iterate.surveyTextFont?.postscriptName,
marginBottom: styles.promptText.marginBottom - 7, // Account for the bottom margin in the last paragraph
},
]}
>
{survey?.prompt?.message}
</Text>
],
paragraph: {
justifyContent: 'center',
marginTop: 0,
marginBottom: 7,
},
link: {
textDecorationLine: 'none',
color: survey?.color ?? '#7457be',
},
}) || (
<Text style={promptTextStyle}>{survey?.prompt?.message ?? ''}</Text>
)}
<PromptButton
text={`${survey?.prompt?.button_text || ''}`}
color={`${survey?.color || '#7457be'}`}
Expand Down
5 changes: 5 additions & 0 deletions src/iterate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import type {
Question,
UserTraits,
} from './types';
import Markdown from './markdown';
import type { MarkdownInterface } from './markdown';
import Storage, { Keys } from './storage';
import type { StorageInterface } from './storage';
import SafeArea from './safearea';
Expand Down Expand Up @@ -60,6 +62,7 @@ class Iterate {
apiKey,
safeArea,
storage,
markdown,
// Allow the presentation style of the survey modal to be overridden,
// this is a temporary solution to a bug in react-navigation that causes
// the app to crash when swiping down on a modal in the pageSheet presentation style.
Expand All @@ -70,13 +73,15 @@ class Iterate {
apiKey: string;
safeArea: () => EdgeInsets;
storage: StorageInterface;
markdown?: MarkdownInterface;
presentationStyle?: PresentationStyle;
buttonFont?: FontData;
surveyTextFont?: FontData;
}) => {
this.apiKey = apiKey;
SafeArea.provider = safeArea;
Storage.provider = storage;
Markdown.provider = markdown;

if (presentationStyle != null) {
store.dispatch(setPresentationStyle(presentationStyle));
Expand Down
29 changes: 29 additions & 0 deletions src/markdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';

export type MarkdownInterfacePropsStyle = {
body?: {};
link?: {};
paragraph?: {};
};

export type MarkdownInterface = React.ElementType;

class Markdown {
// A user-provided markdown provider
provider?: MarkdownInterface;

Render(
value: string,
style: MarkdownInterfacePropsStyle
): JSX.Element | null {
const MarkdownProvider = this.provider;

if (MarkdownProvider != null) {
return <MarkdownProvider style={style}>{value}</MarkdownProvider>;
} else {
return null;
}
}
}

export default new Markdown();
99 changes: 97 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5707,6 +5707,13 @@ __metadata:
languageName: node
linkType: hard

"camelize@npm:^1.0.0":
version: 1.0.1
resolution: "camelize@npm:1.0.1"
checksum: 91d8611d09af725e422a23993890d22b2b72b4cabf7239651856950c76b4bf53fe0d0da7c5e4db05180e898e4e647220e78c9fbc976113bd96d603d1fcbfcb99
languageName: node
linkType: hard

"caniuse-api@npm:^3.0.0":
version: 3.0.0
resolution: "caniuse-api@npm:3.0.0"
Expand Down Expand Up @@ -6678,6 +6685,13 @@ __metadata:
languageName: node
linkType: hard

"css-color-keywords@npm:^1.0.0":
version: 1.0.0
resolution: "css-color-keywords@npm:1.0.0"
checksum: 8f125e3ad477bd03c77b533044bd9e8a6f7c0da52d49bbc0bbe38327b3829d6ba04d368ca49dd9ff3b667d2fc8f1698d891c198bbf8feade1a5501bf5a296408
languageName: node
linkType: hard

"css-declaration-sorter@npm:^6.3.1":
version: 6.4.1
resolution: "css-declaration-sorter@npm:6.4.1"
Expand Down Expand Up @@ -6752,6 +6766,17 @@ __metadata:
languageName: node
linkType: hard

"css-to-react-native@npm:^3.0.0":
version: 3.2.0
resolution: "css-to-react-native@npm:3.2.0"
dependencies:
camelize: ^1.0.0
css-color-keywords: ^1.0.0
postcss-value-parser: ^4.0.2
checksum: 263be65e805aef02c3f20c064665c998a8c35293e1505dbe6e3054fb186b01a9897ac6cf121f9840e5a9dfe3fb3994f6fcd0af84a865f1df78ba5bf89e77adce
languageName: node
linkType: hard

"css-tree@npm:^1.1.2, css-tree@npm:^1.1.3":
version: 1.1.3
resolution: "css-tree@npm:1.1.3"
Expand Down Expand Up @@ -7466,6 +7491,13 @@ __metadata:
languageName: node
linkType: hard

"entities@npm:~2.0.0":
version: 2.0.3
resolution: "entities@npm:2.0.3"
checksum: 5a7899fcc622e0d76afdeafe4c58a6b40ae3a8ee4772e5825a648c11a2ca324a9a02515386f512e466baac4aeb551f3d3b79eaece5cd98369b9f8601be336b1a
languageName: node
linkType: hard

"env-editor@npm:^0.4.1":
version: 0.4.2
resolution: "env-editor@npm:0.4.2"
Expand Down Expand Up @@ -11678,6 +11710,15 @@ __metadata:
languageName: node
linkType: hard

"linkify-it@npm:^2.0.0":
version: 2.2.0
resolution: "linkify-it@npm:2.2.0"
dependencies:
uc.micro: ^1.0.1
checksum: d198871d0b3f3cfdb745dae564bfd6743474f20cd0ef1057e6ca29451834749e7f3da52b59b4de44e98f31a1e5c71bdad160490d4ae54de251cbcde57e4d7837
languageName: node
linkType: hard

"load-json-file@npm:^4.0.0":
version: 4.0.0
resolution: "load-json-file@npm:4.0.0"
Expand Down Expand Up @@ -12066,6 +12107,21 @@ __metadata:
languageName: node
linkType: hard

"markdown-it@npm:^10.0.0":
version: 10.0.0
resolution: "markdown-it@npm:10.0.0"
dependencies:
argparse: ^1.0.7
entities: ~2.0.0
linkify-it: ^2.0.0
mdurl: ^1.0.1
uc.micro: ^1.0.5
bin:
markdown-it: bin/markdown-it.js
checksum: 69f5ee640cbebb451b80d3cce308fff7230767e05c0f8c206a1e413775b7a6e5a08e91e9f3ec59f9b5c5a45493f9ce7ac089379cffb60c9d3e6677ed9d535086
languageName: node
linkType: hard

"md5-file@npm:^3.2.3":
version: 3.2.3
resolution: "md5-file@npm:3.2.3"
Expand Down Expand Up @@ -12113,6 +12169,13 @@ __metadata:
languageName: node
linkType: hard

"mdurl@npm:^1.0.1":
version: 1.0.1
resolution: "mdurl@npm:1.0.1"
checksum: 71731ecba943926bfbf9f9b51e28b5945f9411c4eda80894221b47cc105afa43ba2da820732b436f0798fd3edbbffcd1fc1415843c41a87fea08a41cc1e3d02b
languageName: node
linkType: hard

"media-typer@npm:0.3.0":
version: 0.3.0
resolution: "media-typer@npm:0.3.0"
Expand Down Expand Up @@ -14291,7 +14354,7 @@ __metadata:
languageName: node
linkType: hard

"postcss-value-parser@npm:^4.1.0, postcss-value-parser@npm:^4.2.0":
"postcss-value-parser@npm:^4.0.2, postcss-value-parser@npm:^4.1.0, postcss-value-parser@npm:^4.2.0":
version: 4.2.0
resolution: "postcss-value-parser@npm:4.2.0"
checksum: 819ffab0c9d51cf0acbabf8996dffbfafbafa57afc0e4c98db88b67f2094cb44488758f06e5da95d7036f19556a4a732525e84289a425f4f6fd8e412a9d7442f
Expand Down Expand Up @@ -14473,7 +14536,7 @@ __metadata:
languageName: node
linkType: hard

"prop-types@npm:*, prop-types@npm:^15.8.1":
"prop-types@npm:*, prop-types@npm:^15.5.10, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
version: 15.8.1
resolution: "prop-types@npm:15.8.1"
dependencies:
Expand Down Expand Up @@ -14755,6 +14818,15 @@ __metadata:
languageName: node
linkType: hard

"react-native-fit-image@npm:^1.5.5":
version: 1.5.5
resolution: "react-native-fit-image@npm:1.5.5"
dependencies:
prop-types: ^15.5.10
checksum: 2f3ce06b43191efe3a4bd0698a4117342d821455c96433e9561d50f156ee446d2c449bf9e0908f9a8b7bbb8f95c02478d4fca8d8d103f38b6ce3b8b75557af15
languageName: node
linkType: hard

"react-native-iterate-example@workspace:example":
version: 0.0.0-use.local
resolution: "react-native-iterate-example@workspace:example"
Expand All @@ -14771,6 +14843,7 @@ __metadata:
react-dom: 18.2.0
react-native: 0.72.6
react-native-encrypted-storage: ^4.0.3
react-native-markdown-display: ^7.0.0-alpha.2
react-native-safe-area-context: ^4.7.4
react-native-web: ~0.19.6
react-native-webview: ^13.6.2
Expand Down Expand Up @@ -14810,6 +14883,21 @@ __metadata:
languageName: unknown
linkType: soft

"react-native-markdown-display@npm:^7.0.0-alpha.2":
version: 7.0.0-alpha.2
resolution: "react-native-markdown-display@npm:7.0.0-alpha.2"
dependencies:
css-to-react-native: ^3.0.0
markdown-it: ^10.0.0
prop-types: ^15.7.2
react-native-fit-image: ^1.5.5
peerDependencies:
react: ^16.2.0
react-native: ">=0.50.4"
checksum: 9f8f7a9ae165e6964719dc16a79d254e1ce7febc9938ebf035f1194f3cda3154eb6c7efd622de1b92b9c01704aad88c0501e64c00a0a2439331c44a039929db4
languageName: node
linkType: hard

"react-native-safe-area-context@npm:^4.7.4":
version: 4.7.4
resolution: "react-native-safe-area-context@npm:4.7.4"
Expand Down Expand Up @@ -17251,6 +17339,13 @@ __metadata:
languageName: node
linkType: hard

"uc.micro@npm:^1.0.1, uc.micro@npm:^1.0.5":
version: 1.0.6
resolution: "uc.micro@npm:1.0.6"
checksum: 6898bb556319a38e9cf175e3628689347bd26fec15fc6b29fa38e0045af63075ff3fea4cf1fdba9db46c9f0cbf07f2348cd8844889dd31ebd288c29fe0d27e7a
languageName: node
linkType: hard

"uglify-es@npm:^3.1.9":
version: 3.3.10
resolution: "uglify-es@npm:3.3.10"
Expand Down