xref: /expo/docs/components/plugins/SnackEmbed.tsx (revision 428b6b44)
1import * as React from 'react';
2
3import { SNACK_URL } from '../../common/snack';
4
5type Props = React.PropsWithChildren<{
6  snackId?: string;
7  name?: string;
8  description?: string;
9  platform?: string;
10  preview?: boolean;
11  theme?: string;
12  style?: React.CSSProperties;
13}>;
14
15const SnackEmbed = ({
16  snackId,
17  name,
18  description,
19  platform,
20  preview,
21  theme,
22  style,
23  children,
24}: Props) => {
25  React.useEffect(() => {
26    let script = document.getElementById('snack') as HTMLScriptElement;
27    // inject script if it hasn't been loaded by a previous page
28    if (!script) {
29      script = document.createElement('script');
30      script.src = `${snackId ? 'https://snack.expo.dev' : SNACK_URL}/embed.js`;
31      script.async = true;
32      script.id = 'snack';
33
34      document.body.appendChild(script);
35      script.addEventListener('load', () => {
36        window.ExpoSnack.initialize();
37      });
38    }
39
40    if (window.ExpoSnack) {
41      window.ExpoSnack.initialize();
42    }
43  }, [snackId]);
44
45  // TODO(abi): Handle `data-snack-sdk-version` somehow
46  // maybe using `context`?
47
48  // get snack data from snack id or from inline code
49  // TODO (barthap): Type all possible keys for this
50  let embedProps: Record<string, any>;
51  if (snackId) {
52    embedProps = { 'data-snack-id': snackId };
53  } else {
54    const code = React.Children.toArray(children).join('').trim();
55    embedProps = {
56      'data-snack-code': code,
57    };
58    if (name) {
59      embedProps['data-snack-name'] = name;
60    }
61    if (description) {
62      embedProps['data-snack-description'] = description;
63    }
64  }
65
66  // fill in default options for snack styling
67  if (platform) {
68    embedProps['data-snack-platform'] = platform;
69  } else {
70    embedProps['data-snack-platform'] = 'ios';
71  }
72
73  if (preview) {
74    embedProps['data-snack-preview'] = preview;
75  } else {
76    embedProps['data-snack-preview'] = false;
77  }
78
79  if (theme) {
80    embedProps['data-snack-theme'] = theme;
81  } else {
82    embedProps['data-snack-theme'] = 'light';
83  }
84
85  const embedStyle = style ? style! : {};
86
87  return (
88    <div
89      {...embedProps}
90      style={{
91        overflow: 'hidden',
92        background: '#fafafa',
93        borderWidth: 1,
94        borderStyle: 'solid',
95        height: 505,
96        maxWidth: '1200px',
97        borderRadius: 4,
98        borderColor: 'rgba(0,0,0,.16)',
99        ...embedStyle,
100      }}
101    />
102  );
103};
104
105export default SnackEmbed;
106