xref: /expo/docs/components/plugins/SnackEmbed.tsx (revision eeffdb10)
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)
51        .join('')
52        .trim();
53      embedProps = {
54        'data-snack-code': code,
55      };
56      if (this.props.hasOwnProperty('name')) {
57        embedProps['data-snack-name'] = this.props.name;
58      }
59      if (this.props.hasOwnProperty('description')) {
60        embedProps['data-snack-description'] = this.props.description;
61      }
62    }
63
64    // fill in default options for snack styling
65    if (this.props.hasOwnProperty('platform')) {
66      embedProps['data-snack-platform'] = this.props.platform;
67    } else {
68      embedProps['data-snack-platform'] = 'ios';
69    }
70
71    if (this.props.hasOwnProperty('preview')) {
72      embedProps['data-snack-preview'] = this.props.preview;
73    } else {
74      embedProps['data-snack-preview'] = false;
75    }
76
77    if (this.props.hasOwnProperty('theme')) {
78      embedProps['data-snack-theme'] = this.props.theme;
79    } else {
80      embedProps['data-snack-theme'] = 'light';
81    }
82
83    var embedStyle = {};
84    if (this.props.hasOwnProperty('style')) {
85      embedStyle = this.props.style!;
86    }
87
88    return (
89      <div
90        {...embedProps}
91        style={{
92          overflow: 'hidden',
93          background: '#fafafa',
94          borderWidth: 1,
95          borderStyle: 'solid',
96          height: 505,
97          maxWidth: '1200px',
98          borderRadius: 4,
99          borderColor: 'rgba(0,0,0,.16)',
100          ...embedStyle,
101        }}
102      />
103    );
104  }
105}
106