iframe react

pull/5370/head
bunsenstraat 3 years ago
parent 0f4dc4f4b8
commit 477a952023
  1. 13
      apps/remix-ide/src/app/components/panel.ts
  2. 4
      apps/remix-ide/src/remixAppManager.js
  3. 1
      libs/remix-ui/app/src/index.ts
  4. 29
      libs/remix-ui/app/src/lib/remix-app/components/panels/iFramePluginView.tsx
  5. 85
      libs/remix-ui/app/src/lib/remix-app/plugins/IFrameReactPlugin.tsx
  6. 3
      libs/remix-ui/plugin-manager/src/lib/components/LocalPluginForm.tsx
  7. 3
      libs/remix-ui/plugin-manager/src/types.d.ts

@ -31,14 +31,12 @@ export class AbstractPanel extends HostPlugin {
} }
addView (profile, view) { addView (profile, view) {
console.log(profile, view)
if (this.plugins[profile.name]) throw new Error(`Plugin ${profile.name} already rendered`) if (this.plugins[profile.name]) throw new Error(`Plugin ${profile.name} already rendered`)
this.plugins[profile.name] = { this.plugins[profile.name] = {
profile: profile, profile: profile,
view: view, view: view,
active: false active: false
} }
console.log(this.plugins)
} }
removeView (profile) { removeView (profile) {
@ -61,20 +59,11 @@ export class AbstractPanel extends HostPlugin {
*/ */
showContent (name) { showContent (name) {
if (!this.plugins[name]) throw new Error(`Plugin ${name} is not yet activated`) if (!this.plugins[name]) throw new Error(`Plugin ${name} is not yet activated`)
// hiding the current view and display the `moduleName`
/*
if (this.active) {
this.contents[this.active].style.display = 'none'
}
this.contents[name].style.display = 'flex'
this.contents[name].style.paddingTop = '20%'
this.contents[name].style.flexDirection = 'column'
*/
Object.values(this.plugins).forEach(plugin => { Object.values(this.plugins).forEach(plugin => {
plugin.active = false plugin.active = false
}) })
this.plugins[name].active = true this.plugins[name].active = true
console.log(this.plugins)
} }
focus (name) { focus (name) {

@ -1,6 +1,6 @@
/* global localStorage, fetch */ /* global localStorage, fetch */
import { PluginManager } from '@remixproject/engine' import { PluginManager } from '@remixproject/engine'
import { IframePlugin } from '@remixproject/engine-web' import { IframeReactPlugin } from '@remix-ui/app'
import { EventEmitter } from 'events' import { EventEmitter } from 'events'
import QueryParams from './lib/query-params' import QueryParams from './lib/query-params'
import { PermissionHandler } from './app/ui/persmission-handler' import { PermissionHandler } from './app/ui/persmission-handler'
@ -130,7 +130,7 @@ export class RemixAppManager extends PluginManager {
} }
} }
return plugins.map(plugin => { return plugins.map(plugin => {
return new IframePlugin(plugin) return new IframeReactPlugin(plugin)
}) })
} }

@ -1 +1,2 @@
export { default as RemixApp } from './lib/remix-app/remix-app' export { default as RemixApp } from './lib/remix-app/remix-app'
export { default as IframeReactPlugin } from './lib/remix-app/plugins/IFrameReactPlugin'

@ -0,0 +1,29 @@
import React, { useRef, useState } from 'react'
import IframeReactPlugin from '../../plugins/IFrameReactPlugin'
interface IFramePluginViewProps {
plugin: IframeReactPlugin
}
const IFramePluginView = (props: IFramePluginViewProps) => {
const ref = useRef()
const [loading, isLoading] = useState<boolean>(true)
const loaded = () => {
props.plugin.shake(ref.current)
isLoading(false)
}
const loader = <div className='d-flex justify-content-center align-items-center'>
<div className='spinner-border' role="status">
<span className='sr-only'>Loading...</span>
</div>
</div>
return (<>
<div className={loading ? '' : 'd-none'}>{loader}</div>
<iframe onLoad={loaded} ref={ref} src={props.plugin.profile.url} title={props.plugin.name} id={props.plugin.name} seamless={true} sandbox='allow-popups allow-scripts allow-same-origin allow-forms allow-top-navigation'></iframe>
</>)
}
export default IFramePluginView

@ -0,0 +1,85 @@
import type { Message, Profile, ExternalProfile, LocationProfile } from '@remixproject/plugin-utils'
import { PluginConnector } from '@remixproject/engine'
import React from 'react' // eslint-disable-line
import IFramePluginView from '../components/panels/iFramePluginView'
export type IframeProfile = Profile & LocationProfile & ExternalProfile
/**
* Connect an Iframe client to the engine.
* @dev This implements the ViewPlugin as it cannot extends two class. Maybe use a mixin at some point
*/
class IframeReactPlugin extends PluginConnector {
// Listener is needed to remove the listener
private readonly listener = ['message', (e: MessageEvent) => this.getEvent(e), false] as const
private container: any
private origin: string
private source: Window
private url: string
constructor (public profile: IframeProfile) {
super(profile)
}
/** Implement "activate" of the ViewPlugin */
connect (url: string) {
this.profile.url = url
this.render()
}
addToView () {
this.call(this.profile.location, 'addView', this.profile, this.container)
}
shake (iframe: any) {
return new Promise((resolve, reject) => {
// Wait for the iframe to load and handshake
if (!iframe.contentWindow) {
reject(new Error(`${this.name} plugin cannot find url ${this.profile.url}`))
}
this.origin = new URL(iframe.src).origin
this.source = iframe.contentWindow
window.addEventListener(...this.listener)
this.handshake()
.then(resolve)
.catch(reject)
//
})
}
/** Implement "deactivate" of the ViewPlugin */
disconnect () {
console.trace('disconnect')
window.removeEventListener(...this.listener)
return this.call(this.profile.location, 'removeView', this.profile)
.catch(console.error)
}
/** Get message from the iframe */
private async getEvent (event: MessageEvent) {
if (event.source !== this.source) return // Filter only messages that comes from this iframe
if (event.origin !== this.origin) return // Filter only messages that comes from this origin
const message: Message = event.data
this.getMessage(message)
}
/**
* Post a message to the iframe of this plugin
* @param message The message to post
*/
protected send (message: Partial<Message>) {
if (!this.source) {
throw new Error('No window attached to Iframe yet')
}
this.source.postMessage(message, this.origin)
}
/** Create and return the iframe */
render () {
this.container = <IFramePluginView plugin={this} />
this.addToView()
}
}
export default IframeReactPlugin

@ -6,6 +6,7 @@ import { IframePlugin, WebsocketPlugin } from '@remixproject/engine-web'
import { localPluginReducerActionType, localPluginToastReducer } from '../reducers/pluginManagerReducer' import { localPluginReducerActionType, localPluginToastReducer } from '../reducers/pluginManagerReducer'
import { canActivate, FormStateProps, PluginManagerComponent } from '../../types' import { canActivate, FormStateProps, PluginManagerComponent } from '../../types'
import { IframeReactPlugin } from '@remix-ui/app'
interface LocalPluginFormProps { interface LocalPluginFormProps {
closeModal: () => void closeModal: () => void
@ -79,7 +80,7 @@ function LocalPluginForm ({ closeModal, visible, pluginManager }: LocalPluginFor
icon: 'assets/img/localPlugin.webp', icon: 'assets/img/localPlugin.webp',
canActivate: typeof canactivate === 'string' ? canactivate.split(',').filter(val => val).map(val => { return val.trim() }) : [] canActivate: typeof canactivate === 'string' ? canactivate.split(',').filter(val => val).map(val => { return val.trim() }) : []
} }
const localPlugin = type === 'iframe' ? new IframePlugin(initialState) : new WebsocketPlugin(initialState) const localPlugin = type === 'iframe' ? new IframeReactPlugin(initialState) : new WebsocketPlugin(initialState)
localPlugin.profile.hash = `local-${name}` localPlugin.profile.hash = `local-${name}`
targetPlugin.description = localPlugin.profile.description !== undefined ? localPlugin.profile.description : '' targetPlugin.description = localPlugin.profile.description !== undefined ? localPlugin.profile.description : ''
targetPlugin.events = localPlugin.profile.events !== undefined ? localPlugin.profile.events : [] targetPlugin.events = localPlugin.profile.events !== undefined ? localPlugin.profile.events : []

@ -4,6 +4,7 @@ import { EventEmitter } from 'events'
import { Engine } from '@remixproject/engine/lib/engine' import { Engine } from '@remixproject/engine/lib/engine'
import { PluginBase, Profile } from '@remixproject/plugin-utils' import { PluginBase, Profile } from '@remixproject/plugin-utils'
import { IframePlugin, ViewPlugin, WebsocketPlugin } from '@remixproject/engine-web' import { IframePlugin, ViewPlugin, WebsocketPlugin } from '@remixproject/engine-web'
import { IframeReactPlugin } from '@remix-ui/app'
/* eslint-disable camelcase */ /* eslint-disable camelcase */
interface SetPluginOptionType { interface SetPluginOptionType {
@ -88,7 +89,7 @@ export class PluginManagerComponent extends ViewPlugin extends Plugin implements
render(): HTMLDivElement render(): HTMLDivElement
getAndFilterPlugins: (filter?: string, profiles?: Profile[]) => void getAndFilterPlugins: (filter?: string, profiles?: Profile[]) => void
triggerEngineEventListener: () => void triggerEngineEventListener: () => void
activateAndRegisterLocalPlugin: (localPlugin: IframePlugin | WebsocketPlugin) => Promise<void> activateAndRegisterLocalPlugin: (localPlugin: IframePlugin | IframeReactPlugin | WebsocketPlugin) => Promise<void>
activeProfiles: string[] activeProfiles: string[]
_paq: any _paq: any
} }

Loading…
Cancel
Save