react-native-web-headroom
Version:
React Native Web Headroom
76 lines (66 loc) • 2.08 kB
JavaScript
/* eslint-disable no-underscore-dangle */
import { window, document } from 'global';
import Channel from '@storybook/channels';
import stringify from 'json-stringify-safe';
export const KEY = 'storybook-channel';
export class PostmsgTransport {
constructor(config) {
this._config = config;
this._buffer = [];
this._handler = null;
window.addEventListener('message', this._handleEvent.bind(this), false);
document.addEventListener('DOMContentLoaded', () => this._flush());
// Check whether the config.page parameter has a valid value
if (config.page !== 'manager' && config.page !== 'preview') {
throw new Error(`postmsg-channel: "config.page" cannot be "${config.page}"`);
}
}
setHandler(handler) {
this._handler = handler;
}
send(event) {
const iframeWindow = this._getWindow();
if (!iframeWindow) {
return new Promise((resolve, reject) => {
this._buffer.push({ event, resolve, reject });
});
}
const data = stringify({ key: KEY, event });
iframeWindow.postMessage(data, '*');
return Promise.resolve(null);
}
_flush() {
const buffer = this._buffer;
this._buffer = [];
buffer.forEach(item => {
this.send(item.event)
.then(item.resolve)
.catch(item.reject);
});
}
_getWindow() {
if (this._config.page === 'manager') {
// FIXME this is a really bad idea! use a better way to do this.
// This finds the storybook preview iframe to send messages to.
const iframe = document.getElementById('storybook-preview-iframe');
if (!iframe) {
return null;
}
return iframe.contentWindow;
}
return window.parent;
}
_handleEvent(rawEvent) {
try {
const { data } = rawEvent;
const { key, event } = JSON.parse(data);
if (key === KEY) {
this._handler(event);
}
} catch (error) {} // eslint-disable-line
}
}
export default function createChannel({ page }) {
const transport = new PostmsgTransport({ page });
return new Channel({ transport });
}