text: /**
   * This is an example of how you should add custom elements instead of manipulating the DOM directly
   */
  
  // Import custom components
  const customVueComponent = require('./components/vuecomponent');
  const customReactComponent = require('./components/reactcomponent');
  
  module.exports = (Plugin, Api, Vendor) => {
  
      // Destructure some apis
      const { Logger, ReactComponents, Patcher, monkeyPatch, Reflection, Utils, CssUtils, VueInjector, Vuewrap, requireUncached } = Api;
      const { Vue } = Vendor;
      const { React } = Reflection.modules; // This should be in vendor
  
      return class extends Plugin {
  
          async onStart() {
              this.injectStyle();
              this.patchGuildTextChannel();
              this.patchMessages();
              return true;
          }
  
          async onStop() {
              // The automatic unpatcher is not there yet
              Patcher.unpatchAll();
              CssUtils.deleteAllStyles();
  
              // Force update elements to remove our changes
              const GuildTextChannel = await ReactComponents.getComponent('GuildTextChannel');
              GuildTextChannel.forceUpdateAll();
              const MessageContent = await ReactComponents.getComponent('MessageContent', { selector: Reflection.resolve('container', 'containerCozy', 'containerCompact', 'edited').selector }, m => m.defaultProps && m.defaultProps.hasOwnProperty('disableButtons'));
              MessageContent.forceUpdateAll();
              return true;
          }
  
          /* Inject some style for our custom element */
          async injectStyle() {
              const css = `
                  .exampleCustomElement {
                      background: #7a7d82;
                      color: #FFF;
                      border-radius: 5px;
                      font-size: 12px;
                      font-weight: 600;
                      opacity: .5;
                      &:hover {
                          opacity: 1;
                      }
                  }
                  .exampleBtnGroup {
                      .bd-button {
                          font-size: 14px;
                          padding: 5px;
                      }
                  }
                  `;
              await CssUtils.injectSass(css);
          }
  
          async patchGuildTextChannel() {
              // Get the GuildTextChannel component and patch it's render function
              const GuildTextChannel = await ReactComponents.getComponent('GuildTextChannel');
              monkeyPatch(GuildTextChannel.component.prototype).after('render', this.injectCustomElements.bind(this));
              // Force update to see our changes immediatly
              GuildTextChannel.forceUpdateAll();
          }
  
          async patchMessages() {
              // Get Message component and patch it's render function
              const MessageContent = await ReactComponents.getComponent('MessageContent', { selector: Reflection.resolve('container', 'containerCozy', 'containerCompact', 'edited').selector });
              monkeyPatch(MessageContent.component.prototype).after('render', this.injectGenericComponents.bind(this));
              // Force update to see our changes immediatly
              MessageContent.forceUpdateAll();
          }
  
          /*
           * Injecting a custom React element using React.createElement
           * https://reactjs.org/docs/react-api.html#createelement
           * Injecting a custom Vue element using Vue.component
           * https://vuejs.org/v2/guide/render-function.html
           **/
          injectCustomElements(that, args, returnValue) {
              // Get the child we want using a treewalker since we know the child we want has a channel property and children.
              const child = Utils.findInReactTree(returnValue, filter => filter.hasOwnProperty('channel') && filter.children);
              if (!child) return;
              // If children is not an array make it into one
              if (!child.children instanceof Array) child.children = [child.children];
  
              // Add our custom components to children
              child.children.push(customReactComponent(React, { onClick: e => this.handleClick(e, child.channel) }));
              child.children.push(customVueComponent(Vuewrap, { onClick: e => this.handleClick(e, child.channel) }));
          }
  
          /**
           * Inject generic components provided by BD
           */
          injectGenericComponents(that, args, returnValue) {
              // If children is not an array make it into one
              if (!returnValue.props.children instanceof Array) returnValue.props.children = [returnValue.props.children];
              // Add a generic Button component provided by BD
              returnValue.props.children.push(Api.Components.ButtonGroup({
                  classes: [ 'exampleBtnGroup' ], // Additional classes for button group
                  buttons: [
                      {
                          classes: ['exampleBtn'], // Additional classes for button
                          text: 'Hello World!', // Text for button
                          onClick: e => Logger.log('Hello World!') // Button click handler
                      },
                      {
                          classes: ['exampleBtn'],
                          text: 'Button',
                          onClick: e => Logger.log('Button!')
                      }
                  ]
              }).render()); // Render will return the wrapped component that can then be displayed
          }
  
          /**
           * Will log the channel object
           */
          handleClick(e, channel) {
              Logger.log('Clicked!', channel);
          }
      }
  
  };
  