Make extension panes hot-reload/reconfigurable

This commit is contained in:
Aria Minaei 2023-08-03 11:29:55 +02:00
parent 4f00443ee1
commit d8140a5982
9 changed files with 136 additions and 44 deletions

View file

@ -0,0 +1,88 @@
import type {IExtension} from '@theatre/studio'
import studio from '@theatre/studio'
import '@theatre/core'
import {extensionButton} from '../../shared/utils/useExtensionButton'
const ext1: IExtension = {
id: '@theatre/hello-world-extension',
toolbars: {},
panes: [],
}
studio.initialize({usePersistentStorage: false})
let currentStep = -1
extensionButton(
'Forward',
() => {
if (currentStep < steps.length - 1) {
currentStep++
steps[currentStep]()
}
},
'>',
)
const steps = [
function step0() {
studio.extend(
{
...ext1,
panes: [
{
class: 'pane1',
mount: ({paneId, node}) => {
const el = document.createElement('div')
el.innerHTML = 'pane1-config1'
node.appendChild(el)
return function unmount() {
node.removeChild(el)
console.log('unmount pane1-config1')
}
},
},
],
},
{__experimental_reconfigure: true},
)
studio.createPane('pane1')
},
function step1() {
studio.extend(
{
...ext1,
panes: [
{
class: 'pane1',
mount: ({paneId, node}) => {
const el = document.createElement('div')
el.innerHTML = 'pane1-config2'
node.appendChild(el)
return function unmount() {
node.removeChild(el)
console.log('unmount pane1-config2')
}
},
},
],
},
{__experimental_reconfigure: true},
)
},
function step2() {
studio.extend(
{
...ext1,
panes: [],
},
{__experimental_reconfigure: true},
)
},
function step3() {
steps[1]()
},
]

View file

@ -0,0 +1,26 @@
import {test, expect} from '@playwright/test'
test.describe('hot-reload-extension-pane', () => {
test('works', async ({page}) => {
await page.goto('./tests/hot-reload-extension-pane/')
const toolbar = page.locator(
'[data-test-id="theatre-extensionToolbar-global"]',
)
const forwardButton = toolbar.getByRole('button', {name: '>'})
await forwardButton.click()
const pane = page.locator(
'[data-test-id="theatre-pane-content-pane1 \\#1"]',
)
expect(await pane.textContent()).toEqual('pane1-config1')
await forwardButton.click()
expect(await pane.textContent()).toEqual('pane1-config2')
await forwardButton.click()
await expect(pane).not.toBeAttached()
await forwardButton.click()
expect(await pane.textContent()).toEqual('pane1-config2')
})
})

View file

@ -0,0 +1,11 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Theatre.js Playground</title>
<script src="./index.tsx" type="module"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>

View file

@ -28,7 +28,7 @@ const ext1: IExtension = {
panes: [], panes: [],
} }
studio.initialize() studio.initialize({usePersistentStorage: false})
let currentStep = -1 let currentStep = -1

View file

@ -1,8 +1,8 @@
import {test, expect} from '@playwright/test' import {test, expect} from '@playwright/test'
test.describe('reconfigure-extension', () => { test.describe('hot-reload-extension-toolbar', () => {
test('works', async ({page}) => { test('works', async ({page}) => {
await page.goto('./tests/reconfigure-extension/') await page.goto('./tests/hot-reload-extension-toolbar/')
const toolbar = page.locator( const toolbar = page.locator(
'[data-test-id="theatre-extensionToolbar-global"]', '[data-test-id="theatre-extensionToolbar-global"]',

View file

@ -1,37 +0,0 @@
import {editable as e, SheetProvider} from '@theatre/r3f'
import {Stars, TorusKnot} from '@react-three/drei'
import {getProject} from '@theatre/core'
import React from 'react'
import {Canvas} from '@react-three/fiber'
function App() {
return (
<div
onClick={() => {
// return setBgIndex((bgIndex) => (bgIndex + 1) % bgs.length)
}}
style={{
height: '100vh',
}}
>
<Canvas
dpr={[1.5, 2]}
linear
gl={{preserveDrawingBuffer: true}}
frameloop="demand"
>
<SheetProvider sheet={getProject('Space').sheet('Scene')}>
<ambientLight intensity={0.75} />
<e.group theatreKey="trefoil">
<TorusKnot scale={[1, 1, 1]} args={[1, 0.3, 128, 64]}>
<meshNormalMaterial />
</TorusKnot>
</e.group>
<Stars radius={500} depth={50} count={1000} factor={10} />
</SheetProvider>
</Canvas>
</div>
)
}
export default App

View file

@ -1,5 +1,4 @@
import {prism, val} from '@theatre/dataverse' import {prism, val} from '@theatre/dataverse'
import {emptyArray} from '@theatre/shared/utils'
import type {PaneInstanceId} from '@theatre/shared/utils/ids' import type {PaneInstanceId} from '@theatre/shared/utils/ids'
import SimpleCache from '@theatre/shared/utils/SimpleCache' import SimpleCache from '@theatre/shared/utils/SimpleCache'
import type {$IntentionalAny, StrictRecord} from '@theatre/shared/utils/types' import type {$IntentionalAny, StrictRecord} from '@theatre/shared/utils/types'
@ -50,7 +49,7 @@ export default class PaneManager {
} }
return inst return inst
}, },
emptyArray, [definition],
) )
instances[instanceId] = instance instances[instanceId] = instance

View file

@ -27,6 +27,8 @@ const minDims = {width: 300, height: 300}
const ExtensionPaneWrapper: React.FC<{ const ExtensionPaneWrapper: React.FC<{
paneInstance: PaneInstance<$FixMe> paneInstance: PaneInstance<$FixMe>
}> = ({paneInstance}) => { }> = ({paneInstance}) => {
console.log(paneInstance)
return ( return (
<BasePanel <BasePanel
panelId={`pane-${paneInstance.instanceId}` as UIPanelId} panelId={`pane-${paneInstance.instanceId}` as UIPanelId}
@ -156,7 +158,7 @@ const Content: React.FC<{paneInstance: PaneInstance<$FixMe>}> = ({
}, [paneInstance]) }, [paneInstance])
return ( return (
<Container> <Container data-test-id={`theatre-pane-wrapper-${paneInstance.instanceId}`}>
<PanelDragZone> <PanelDragZone>
<TitleBar> <TitleBar>
<PaneTools> <PaneTools>
@ -168,7 +170,10 @@ const Content: React.FC<{paneInstance: PaneInstance<$FixMe>}> = ({
</TitleBar> </TitleBar>
</PanelDragZone> </PanelDragZone>
<ErrorBoundary FallbackComponent={ErrorFallback}> <ErrorBoundary FallbackComponent={ErrorFallback}>
<F2 ref={setMountingPoint} /> <F2
data-test-id={`theatre-pane-content-${paneInstance.instanceId}`}
ref={setMountingPoint}
/>
</ErrorBoundary> </ErrorBoundary>
</Container> </Container>
) )