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