Make extension panes hot-reload/reconfigurable
This commit is contained in:
parent
4f00443ee1
commit
d8140a5982
9 changed files with 136 additions and 44 deletions
|
@ -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]()
|
||||||
|
},
|
||||||
|
]
|
|
@ -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')
|
||||||
|
})
|
||||||
|
})
|
|
@ -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>
|
|
@ -28,7 +28,7 @@ const ext1: IExtension = {
|
||||||
panes: [],
|
panes: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
studio.initialize()
|
studio.initialize({usePersistentStorage: false})
|
||||||
|
|
||||||
let currentStep = -1
|
let currentStep = -1
|
||||||
|
|
|
@ -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"]',
|
|
@ -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
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue