From 81fe4479ed3108ecc58cc70f7c2a4dd554b47423 Mon Sep 17 00:00:00 2001 From: Andrew Prifer Date: Tue, 28 Jun 2022 15:59:03 +0200 Subject: [PATCH] Add r3f custom components () --- .../src/shared/custom-r3f-component/App.tsx | 38 ++++++++++++ .../src/shared/custom-r3f-component/index.tsx | 10 ++++ packages/r3f/src/main/editable.tsx | 60 +++++++++++++++++-- 3 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 packages/playground/src/shared/custom-r3f-component/App.tsx create mode 100644 packages/playground/src/shared/custom-r3f-component/index.tsx diff --git a/packages/playground/src/shared/custom-r3f-component/App.tsx b/packages/playground/src/shared/custom-r3f-component/App.tsx new file mode 100644 index 000000000..3c810b3ff --- /dev/null +++ b/packages/playground/src/shared/custom-r3f-component/App.tsx @@ -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 ( +
{ + // return setBgIndex((bgIndex) => (bgIndex + 1) % bgs.length) + }} + style={{ + height: '100vh', + }} + > + + + + + + + + + +
+ ) +} + +export default App diff --git a/packages/playground/src/shared/custom-r3f-component/index.tsx b/packages/playground/src/shared/custom-r3f-component/index.tsx new file mode 100644 index 000000000..550726371 --- /dev/null +++ b/packages/playground/src/shared/custom-r3f-component/index.tsx @@ -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(, document.getElementById('root')) diff --git a/packages/r3f/src/main/editable.tsx b/packages/r3f/src/main/editable.tsx index 34969e9c6..6af81d36e 100644 --- a/packages/r3f/src/main/editable.tsx +++ b/packages/r3f/src/main/editable.tsx @@ -10,16 +10,22 @@ import type {EditableFactoryConfig} from './editableFactoryConfigUtils' import {makeStoreKey} from './utils' import type {$FixMe} from '../types' -const createEditable = ( +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 | Keys | 'primitive', + T extends ComponentType | 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, 'visible'> & { uniqueName: string visible?: boolean | 'editor' @@ -30,6 +36,14 @@ const createEditable = ( editableType: U } : {}) & + (T extends 'custom' + ? { + customComponent: keyof JSX.IntrinsicElements | ComponentType + editableType: U + } + : {}) & + // Since we can't make T conform to keyof JSX.IntrinsicElements (see above) we have to @ts-ignore here. + // @ts-ignore RefAttributes return forwardRef( @@ -38,6 +52,7 @@ const createEditable = ( uniqueName, visible, editableType, + customComponent, additionalProps, objRef, ...props @@ -45,7 +60,10 @@ const createEditable = ( 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() const sheet = useCurrentSheet()! @@ -134,7 +152,7 @@ const createEditable = ( return ( // @ts-ignore - ( ]), ), 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 & { 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 > > + } & { + primitive: React.ForwardRefExoticComponent< + React.PropsWithoutRef< + { + object: any + uniqueName: string + visible?: boolean | 'editor' + additionalProps?: $FixMe + objRef?: $FixMe + editableType: keyof JSX.IntrinsicElements + } & React.RefAttributes + > & { + // 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 + }> & { + [props: string]: any + } + > } return Object.assign(editable, extensions)