Skip to content

Commit

Permalink
Pass container to UIPlugin.render for non-Preact integration (#5437)
Browse files Browse the repository at this point in the history
  • Loading branch information
Murderlon authored Aug 29, 2024
1 parent ededd0b commit bc27b4a
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 16 deletions.
58 changes: 50 additions & 8 deletions examples/react-example/App.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,60 @@
/* eslint-disable */
import React from 'react'
import Uppy from '@uppy/core'
import { createRoot } from 'react-dom/client'
import Uppy, {
UIPlugin,
type Meta,
type Body,
type UIPluginOptions,
type State,
} from '@uppy/core'
import Tus from '@uppy/tus'
import Webcam from '@uppy/webcam'
import RemoteSources from '@uppy/remote-sources'
import { Dashboard, useUppyState } from '@uppy/react'

import '@uppy/core/dist/style.css'
import '@uppy/dashboard/dist/style.css'
import '@uppy/drag-drop/dist/style.css'
import '@uppy/file-input/dist/style.css'
import '@uppy/progress-bar/dist/style.css'
import '@uppy/webcam/dist/style.css'

interface MyPluginOptions extends UIPluginOptions {}

interface MyPluginState extends Record<string, unknown> {}

// Custom plugin example inside React
class MyPlugin<M extends Meta, B extends Body> extends UIPlugin<
MyPluginOptions,
M,
B,
MyPluginState
> {
container!: HTMLElement

constructor(uppy: Uppy<M, B>, opts?: MyPluginOptions) {
super(uppy, opts)
this.type = 'acquirer'
this.id = this.opts.id || 'TEST'
this.title = 'Test'
}

override install() {
const { target } = this.opts
if (target) {
this.mount(target, this)
}
}

override uninstall() {
this.unmount()
}

override render(state: State<M, B>, container: HTMLElement) {
// Important: during the initial render is not defined. Safely return.
if (!container) return
createRoot(container).render(
<h2>React component inside Uppy's Preact UI</h2>,
)
}
}

const metaFields = [
{ id: 'license', name: 'License', placeholder: 'specify license' },
Expand All @@ -20,9 +64,7 @@ function createUppy() {
return new Uppy({ restrictions: { requiredMetaFields: ['license'] } })
.use(Tus, { endpoint: 'https://tusd.tusdemo.net/files/' })
.use(Webcam)
.use(RemoteSources, {
companionUrl: 'https://companion.uppy.io',
})
.use(MyPlugin)
}

export default function App() {
Expand Down
2 changes: 1 addition & 1 deletion examples/react-example/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ import React from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.tsx'

createRoot(document.querySelector('#app')).render(<App />)
createRoot(document.querySelector('#app')!).render(<App />)
17 changes: 12 additions & 5 deletions packages/@uppy/core/src/UIPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable class-methods-use-this */
import { render, type ComponentChild } from 'preact'
import { render } from 'preact'
import findDOMElement from '@uppy/utils/lib/findDOMElement'
import getTextDirection from '@uppy/utils/lib/getTextDirection'

Expand Down Expand Up @@ -112,7 +112,7 @@ class UIPlugin<
// so it could still be called even after uppy.removePlugin or uppy.destroy
// hence the check
if (!this.uppy.getPlugin(this.id)) return
render(this.render(state), uppyRootElement)
render(this.render(state, uppyRootElement), uppyRootElement)
this.afterUpdate()
})

Expand All @@ -127,7 +127,10 @@ class UIPlugin<
targetElement.innerHTML = ''
}

render(this.render(this.uppy.getState()), uppyRootElement)
render(
this.render(this.uppy.getState(), uppyRootElement),
uppyRootElement,
)
this.el = uppyRootElement
targetElement.appendChild(uppyRootElement)

Expand Down Expand Up @@ -176,8 +179,12 @@ class UIPlugin<
* so this.el and this.parent might not be available in `install`.
* This is the case with @uppy/react plugins, for example.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
render(state: Record<string, unknown>): ComponentChild {
render(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
state: Record<string, unknown>,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
container: HTMLElement,
): any {
throw new Error(
'Extend the render method to add your plugin to a DOM element',
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { h } from 'preact'
import classNames from 'classnames'
import { useRef } from 'preact/hooks'
import ignoreEvent from '../utils/ignoreEvent.ts'

type $TSFixMe = any
Expand All @@ -12,6 +13,7 @@ function PickerPanelContent({
state,
uppy,
}: $TSFixMe) {
const ref = useRef<HTMLDivElement>(null)
return (
<div
className={classNames('uppy-DashboardContent-panel', className)}
Expand Down Expand Up @@ -39,8 +41,9 @@ function PickerPanelContent({
{i18n('cancel')}
</button>
</div>
<div className="uppy-DashboardContent-panelBody">
{uppy.getPlugin(activePickerPanel.id).render(state)}

<div ref={ref} className="uppy-DashboardContent-panelBody">
{uppy.getPlugin(activePickerPanel.id).render(state, ref.current)}
</div>
</div>
)
Expand Down

0 comments on commit bc27b4a

Please sign in to comment.