UNPKG

intercom-react

Version:
338 lines (315 loc) 12.7 kB
'use strict'; var React = require('react'); var ReactDOM = require('react-dom'); var lodashDecorators = require('lodash-decorators'); /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ function __decorate(decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; } function __metadata(metadataKey, metadataValue) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); } function classNames(...classes) { return classes.filter((className) => className).join(' '); } var getIntercomFromFrame = (frame) => frame.contentWindow.Intercom; var objectEqual = (object1, object2) => JSON.stringify(object1) === JSON.stringify(object2); function injectCustomStyles(frame, styles) { const { contentWindow } = frame; const node = document.createElement('style'); node.innerHTML = styles; contentWindow.document.head.appendChild(node); } class Portal extends React.PureComponent { render() { const { children } = this.props; return ReactDOM.createPortal(children, document.body); } } function styleInject(css, ref) { if ( ref === void 0 ) ref = {}; var insertAt = ref.insertAt; if (!css || typeof document === 'undefined') { return; } var head = document.head || document.getElementsByTagName('head')[0]; var style = document.createElement('style'); style.type = 'text/css'; if (insertAt === 'top') { if (head.firstChild) { head.insertBefore(style, head.firstChild); } else { head.appendChild(style); } } else { head.appendChild(style); } if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } } var ImportIsolatedRemote = "ImportIsolatedRemote_ImportIsolatedRemote__2bxiR"; var css = ".ImportIsolatedRemote_ImportIsolatedRemote__2bxiR {\n width: 0;\n height: 0;\n border: none; }\n"; styleInject(css); class ImportIsolatedRemote$2 extends React.PureComponent { constructor() { super(...arguments); this.frameNode = React.createRef(); this.scriptNode = null; } componentDidMount() { const { current: frame } = this.frameNode; const { source, onImported } = this.props; if (!frame || !frame.contentWindow) { return; } const { contentWindow } = frame; const script = document.createElement('script'); script.src = source; this.scriptNode = script; function loadScript() { contentWindow.document.body.appendChild(script); script.onload = () => onImported(frame); } if (frame.contentDocument.readyState === 'uninitialized') { frame.onload = loadScript; return; } loadScript(); } componentWillUnmount() { const { scriptNode, frameNode: { current: frame }, } = this; if (frame) { frame.onload = null; } if (scriptNode) { scriptNode.onload = null; } } render() { const { title } = this.props; return (React.createElement(Portal, null, React.createElement("iframe", { className: ImportIsolatedRemote, title: title, ref: this.frameNode }))); } } const LAUNCHER_SIZE_PIXELS = 60; const LAUNCHER_MARGIN_PIXELS = 20; class BorderlessFrameObserver extends React.Component { constructor() { super(...arguments); this.observer = null; } componentWillMount() { const { frame } = this.props; this.observeNode(frame.contentWindow.document.body, this.handleBodyMutation, { childList: true, }); this.injectCustomGradientStyles(); } componentWillUnmount() { this.cleanObserver(); } render() { return null; } injectCustomGradientStyles() { const { frame } = this.props; injectCustomStyles(frame, ` .intercom-gradient { width: 100% !important; height: 100% !important; } `); } observeNode(nodeToObserve, onMutation, options) { this.cleanObserver(); const observer = new MutationObserver(onMutation); observer.observe(nodeToObserve, options); this.observer = observer; return observer; } cleanObserver() { const { observer } = this; if (observer) { observer.disconnect(); } } handleBodyMutation([{ target: body }]) { const intercomAppNode = body.querySelector('.intercom-app'); this.observeNode(intercomAppNode, this.handleIntercomAppMutation, { attributes: true, subtree: true, }); } handleIntercomAppMutation(mutations) { const { launcher, onSizesUpdate } = this.props; for (const { target } of mutations) { const node = target; if (!node.classList.contains('intercom-borderless-frame') && !node.classList.contains('intercom-notifications-frame')) { continue; } const { style: { height }, offsetWidth, } = node; const finalWidth = launcher ? offsetWidth + LAUNCHER_MARGIN_PIXELS : offsetWidth; let finalHeight = height || '0px'; if (height && launcher) { finalHeight = addMarginToPixels(height, LAUNCHER_SIZE_PIXELS + LAUNCHER_MARGIN_PIXELS * 2); } onSizesUpdate({ width: `${finalWidth}px`, height: finalHeight, }); return; } } } __decorate([ lodashDecorators.bind(), __metadata("design:type", Function), __metadata("design:paramtypes", [Array]), __metadata("design:returntype", void 0) ], BorderlessFrameObserver.prototype, "handleBodyMutation", null); __decorate([ lodashDecorators.bind(), __metadata("design:type", Function), __metadata("design:paramtypes", [Array]), __metadata("design:returntype", void 0) ], BorderlessFrameObserver.prototype, "handleIntercomAppMutation", null); function addMarginToPixels(pixelsString, margin) { const pixels = Number(pixelsString.replace('px', '')); return `${pixels + margin}px`; } var Intercom = "Intercom_Intercom__3Amxb"; var IntercomHasLauncher = "Intercom_IntercomHasLauncher__2YqCZ"; var IntercomAnimating = "Intercom_IntercomAnimating__3MvHf"; var IntercomOpen = "Intercom_IntercomOpen__3SD9A"; var css$1 = ".Intercom_Intercom__3Amxb {\n position: fixed;\n bottom: 0;\n right: 0;\n z-index: 999;\n width: 0;\n height: 0;\n background: transparent;\n border: none; }\n\n.Intercom_IntercomHasLauncher__2YqCZ {\n width: 90px;\n height: 90px; }\n\n.Intercom_IntercomAnimating__3MvHf {\n pointer-events: none; }\n\n.Intercom_IntercomOpen__3SD9A {\n width: 100%;\n max-width: 451px;\n height: calc(100% - 40px);\n min-height: 250px;\n max-height: 704px; }\n @media all and (max-width: 451px) {\n .Intercom_IntercomOpen__3SD9A {\n height: 100%;\n max-height: none; } }\n"; styleInject(css$1); const ANIMATION_DURATION = 300; class Intercom$2 extends React.PureComponent { constructor() { super(...arguments); this.state = { frame: null, }; } componentWillReceiveProps({ open: nextOpen, user: nextUser }) { const { user } = this.props; if (nextOpen) { this.getIntercom()('show'); } if (nextUser && !objectEqual(user || {}, nextUser)) { this.getIntercom()('update', nextUser); } } componentWillUnmount() { this.getIntercom()('shutdown'); } render() { const { appId, launcher } = this.props; const { frame } = this.state; const importUrl = `https://widget.intercom.io/widget/${appId}`; const borderlessFrameObserver = frame && (React.createElement(BorderlessFrameObserver, { frame: frame, onSizesUpdate: this.handleBorderlessFrameSizesUpdate, launcher: launcher })); return (React.createElement(React.Fragment, null, React.createElement(ImportIsolatedRemote$2, { title: "intercom", source: importUrl, onImported: this.initializeIntercom }), borderlessFrameObserver)); } updateState({ open = false, animating = false, borderlessFrameSizes = null, }) { const { launcher } = this.props; const { frame } = this.state; if (!frame) { return; } if (borderlessFrameSizes) { const { width, height } = borderlessFrameSizes; frame.setAttribute('style', `width: ${width}; height: ${height};`); } else { frame.removeAttribute('style'); } const className = classNames(Intercom, launcher && IntercomHasLauncher, open && IntercomOpen, animating && IntercomAnimating); frame.setAttribute('class', className); } initializeIntercom(frame) { const { open, onOpen, onClose, appId, onUnreadCountChange, user, onInitialization, launcher, } = this.props; const intercom = getIntercomFromFrame(frame); this.setState({ frame }); intercom('boot', Object.assign({ app_id: appId }, user, { hide_default_launcher: !launcher })); intercom('onShow', () => { this.updateState({ open: true, animating: false }); if (onOpen) { onOpen(); } }); intercom('onHide', () => { this.updateState({ open: true, animating: true }); setTimeout(() => this.updateState({ open: false, animating: false }), ANIMATION_DURATION); if (onClose) { onClose(); } }); if (onUnreadCountChange) { intercom('onUnreadCountChange', onUnreadCountChange); } if (open) { intercom('show'); } else { this.updateState({ open: false, animating: false }); } this.injectCustomLauncherStyles(); if (onInitialization) { onInitialization(intercom); } } getIntercom() { const { frame } = this.state; if (!frame) { return () => { }; } return getIntercomFromFrame(frame); } injectCustomLauncherStyles() { const { frame } = this.state; injectCustomStyles(frame, ` .intercom-launcher-frame-shadow { box-shadow: none !important; } `); } handleBorderlessFrameSizesUpdate(borderlessFrameSizes) { this.updateState({ borderlessFrameSizes }); } } Intercom$2.defaultProps = { launcher: true, }; __decorate([ lodashDecorators.bind(), __metadata("design:type", Function), __metadata("design:paramtypes", [HTMLIFrameElement]), __metadata("design:returntype", void 0) ], Intercom$2.prototype, "initializeIntercom", null); __decorate([ lodashDecorators.bind(), __metadata("design:type", Function), __metadata("design:paramtypes", [Object]), __metadata("design:returntype", void 0) ], Intercom$2.prototype, "handleBorderlessFrameSizesUpdate", null); module.exports = Intercom$2;