Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add <e.custom> #234

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions packages/playground/src/shared/custom-r3f-component/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {editable as e, SheetProvider} from '@theatre/r3f'
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.custom
uniqueName="points"
customComponent="points"
editableType="mesh"
>
<torusKnotGeometry args={[1, 0.3, 128, 64]} />
<meshNormalMaterial />
</e.custom>
</SheetProvider>
</Canvas>
</div>
)
}

export default App
10 changes: 10 additions & 0 deletions packages/playground/src/shared/custom-r3f-component/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import studio from '@theatre/studio'
import extension from '@theatre/r3f/dist/extension'

studio.extend(extension)
studio.initialize()

ReactDOM.render(<App />, document.getElementById('root'))
60 changes: 56 additions & 4 deletions packages/r3f/src/main/editable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,22 @@ import type {EditableFactoryConfig} from './editableFactoryConfigUtils'
import {makeStoreKey} from './utils'
import type {$FixMe} from '../types'

const createEditable = <Keys extends keyof JSX.IntrinsicElements>(
const createEditable = <
// This should really be extends keyof JSX.IntrinsicElements, but that results in a union
// that is "too complex to represent".
Keys extends string,
>(
config: EditableFactoryConfig,
) => {
const editable = <
T extends ComponentType<any> | Keys | 'primitive',
T extends ComponentType<any> | Keys | 'primitive' | 'custom',
U extends T extends Keys ? T : Keys,
>(
Component: T,
type: T extends 'primitive' ? null : U,
type: T extends 'primitive' | 'custom' ? null : U,
) => {
// Since we can't make T conform to keyof JSX.IntrinsicElements (see above) we have to @ts-ignore here.
// @ts-ignore
type Props = Omit<ComponentProps<T>, 'visible'> & {
uniqueName: string
visible?: boolean | 'editor'
Expand All @@ -30,6 +36,14 @@ const createEditable = <Keys extends keyof JSX.IntrinsicElements>(
editableType: U
}
: {}) &
(T extends 'custom'
? {
customComponent: keyof JSX.IntrinsicElements | ComponentType<any>
editableType: U
}
: {}) &
// Since we can't make T conform to keyof JSX.IntrinsicElements (see above) we have to @ts-ignore here.
// @ts-ignore
RefAttributes<JSX.IntrinsicElements[U]>

return forwardRef(
Expand All @@ -38,14 +52,18 @@ const createEditable = <Keys extends keyof JSX.IntrinsicElements>(
uniqueName,
visible,
editableType,
customComponent,
additionalProps,
objRef,
...props
}: Props,
ref,
) => {
const actualType = type ?? editableType
const ActualComponent = customComponent ?? Component

// Since we can't make T conform to keyof JSX.IntrinsicElements (see above) we have to @ts-ignore here.
// @ts-ignore
const objectRef = useRef<JSX.IntrinsicElements[U]>()

const sheet = useCurrentSheet()!
Expand Down Expand Up @@ -134,7 +152,7 @@ const createEditable = <Keys extends keyof JSX.IntrinsicElements>(

return (
// @ts-ignore
<Component
<ActualComponent
ref={mergeRefs([objectRef, ref])}
{...props}
visible={visible !== 'editor' && visible}
Expand All @@ -157,17 +175,51 @@ const createEditable = <Keys extends keyof JSX.IntrinsicElements>(
]),
),
primitive: editable('primitive', null),
custom: editable('custom', null),
} as unknown as {
[Property in Keys]: React.ForwardRefExoticComponent<
React.PropsWithoutRef<
// Since we can't make T conform to keyof JSX.IntrinsicElements (see above) we have to @ts-ignore here.
// @ts-ignore
Omit<JSX.IntrinsicElements[Property], 'visible'> & {
uniqueName: string
visible?: boolean | 'editor'
additionalProps?: $FixMe
objRef?: $FixMe
// Since we can't make T conform to keyof JSX.IntrinsicElements (see above) we have to @ts-ignore here.
// @ts-ignore
} & React.RefAttributes<JSX.IntrinsicElements[Property]>
>
>
} & {
primitive: React.ForwardRefExoticComponent<
React.PropsWithoutRef<
{
object: any
uniqueName: string
visible?: boolean | 'editor'
additionalProps?: $FixMe
objRef?: $FixMe
editableType: keyof JSX.IntrinsicElements
} & React.RefAttributes<JSX.IntrinsicElements['primitive']>
> & {
// Have to reproduce the primitive component's props here because we need to
// lift this index type here to the outside to make auto-complete work
[props: string]: any
}
>
custom: React.ForwardRefExoticComponent<
React.PropsWithoutRef<{
uniqueName: string
visible?: boolean | 'editor'
additionalProps?: $FixMe
objRef?: $FixMe
editableType: keyof JSX.IntrinsicElements
customComponent: keyof JSX.IntrinsicElements | ComponentType<any>
}> & {
[props: string]: any
}
>
}

return Object.assign(editable, extensions)
Expand Down