Started using styled-components in r3f

This commit is contained in:
Aria Minaei 2021-07-04 19:14:00 +02:00
parent 16434644dc
commit b109dca19b
5 changed files with 181 additions and 135 deletions

View file

@ -34,6 +34,7 @@
"@types/lodash-es": "^4.17.4", "@types/lodash-es": "^4.17.4",
"@types/node": "^15.6.2", "@types/node": "^15.6.2",
"@types/react": "^17.0.9", "@types/react": "^17.0.9",
"@types/styled-components": "^5.1.9",
"typescript": "^4.3.2" "typescript": "^4.3.2"
}, },
"dependencies": { "dependencies": {
@ -50,6 +51,7 @@
"react-shadow": "^19.0.2", "react-shadow": "^19.0.2",
"react-use-measure": "^2.0.4", "react-use-measure": "^2.0.4",
"reakit": "^1.3.8", "reakit": "^1.3.8",
"styled-components": "^5.3.0",
"three": "^0.129.0", "three": "^0.129.0",
"zustand": "^3.5.1" "zustand": "^3.5.1"
} }

View file

@ -5,12 +5,32 @@ import {Canvas} from '@react-three/fiber'
import {useEditorStore} from '../store' import {useEditorStore} from '../store'
import {OrbitControls} from '@react-three/drei' import {OrbitControls} from '@react-three/drei'
import shallow from 'zustand/shallow' import shallow from 'zustand/shallow'
import root from 'react-shadow' import root from 'react-shadow/styled-components'
import styles from '../bundle.css.txt' import styles from '../bundle.css.txt'
import UI from './UI' import UI from './UI'
import ProxyManager from './ProxyManager' import ProxyManager from './ProxyManager'
import studio from '@theatre/studio' import studio from '@theatre/studio'
import {useVal} from '@theatre/dataverse-react' import {useVal} from '@theatre/dataverse-react'
import styled, {createGlobalStyle} from 'styled-components'
const GlobalStyle = createGlobalStyle`
:host {
contain: strict;
all: initial;
color: white;
font: 11px -apple-system, BlinkMacSystemFont, Segoe WPC, Segoe Editor,
HelveticaNeue-Light, Ubuntu, Droid Sans, sans-serif;
}
* {
padding: 0;
margin: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
list-style: none;
}
`
const EditorScene = () => { const EditorScene = () => {
const orbitControlsRef = useRef<typeof OrbitControls>() const orbitControlsRef = useRef<typeof OrbitControls>()
@ -43,6 +63,27 @@ const EditorScene = () => {
) )
} }
const Wrapper = styled.div<{editorOpen: boolean}>`
tab-size: 4;
line-height: 1.15; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
margin: 0;
position: fixed;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
z-index: 50;
display: ${(props) => (props.editorOpen ? 'block' : 'none')};
`
const CanvasWrapper = styled.div`
display: relative;
z-index: 0;
height: 100%;
`
const Editor: VFC = () => { const Editor: VFC = () => {
const [editorObject, sceneSnapshot, initialEditorCamera, createSnapshot] = const [editorObject, sceneSnapshot, initialEditorCamera, createSnapshot] =
useEditorStore( useEditorStore(
@ -55,7 +96,7 @@ const Editor: VFC = () => {
shallow, shallow,
) )
const editorOpen = useVal(editorObject?.props.isOpen) const editorOpen = !!useVal(editorObject?.props.isOpen)
useLayoutEffect(() => { useLayoutEffect(() => {
if (editorOpen) { if (editorOpen) {
createSnapshot() createSnapshot()
@ -66,43 +107,31 @@ const Editor: VFC = () => {
return ( return (
<root.div> <root.div>
<div id="react-three-editable-editor-root"> <GlobalStyle />
<> <Wrapper id="theatre-plugin-r3f-root" editorOpen={editorOpen}>
{sceneSnapshot ? (
<> <>
<div className="relative z-50"> <CanvasWrapper>
<div <Canvas
className={`fixed ${editorOpen ? 'block' : 'hidden'} inset-0`} // @ts-ignore
colorManagement
camera={initialEditorCamera}
onCreated={({gl}) => {
gl.setClearColor('white')
}}
shadowMap
pixelRatio={window.devicePixelRatio}
onPointerMissed={() => studio.__experimental_setSelection([])}
> >
{sceneSnapshot ? ( <EditorScene />
<> </Canvas>
<div className="relative z-0 h-full"> </CanvasWrapper>
<Canvas
// @ts-ignore
colorManagement
camera={initialEditorCamera}
onCreated={({gl}) => {
gl.setClearColor('white')
}}
shadowMap
pixelRatio={window.devicePixelRatio}
onPointerMissed={() =>
studio.__experimental_setSelection([])
}
>
<EditorScene />
</Canvas>
</div>
<UI /> <UI />
</>
) : null}
</div>
</div>
<style type="text/css">{styles}</style>
</> </>
</> ) : null}
</div> </Wrapper>
<style type="text/css">{styles}</style>
</root.div> </root.div>
) )
} }

View file

@ -1,4 +1,5 @@
import type {VFC} from 'react' import type {VFC} from 'react'
import {useState} from 'react'
import React from 'react' import React from 'react'
import TransformControlsModeSelect from './TransformControlsModeSelect' import TransformControlsModeSelect from './TransformControlsModeSelect'
import {useEditorStore} from '../store' import {useEditorStore} from '../store'
@ -13,6 +14,7 @@ import studio from '@theatre/studio'
import {getSelected} from './useSelected' import {getSelected} from './useSelected'
import {useVal} from '@theatre/dataverse-react' import {useVal} from '@theatre/dataverse-react'
import IconButton from './elements/IconButton' import IconButton from './elements/IconButton'
import {PortalContext} from 'reakit'
const UI: VFC = () => { const UI: VFC = () => {
const [editorObject] = useEditorStore( const [editorObject] = useEditorStore(
@ -29,114 +31,121 @@ const UI: VFC = () => {
const viewportShading = const viewportShading =
useVal(editorObject?.props.viewportShading) ?? 'rendered' useVal(editorObject?.props.viewportShading) ?? 'rendered'
const [wrapper, setWrapper] = useState<null | HTMLDivElement>(null)
if (!editorObject) return <></> if (!editorObject) return <></>
return ( return (
<div className="absolute inset-0 z-50 pointer-events-none"> <PortalContext.Provider value={wrapper}>
<div className="flex h-full"> <div
<div className="relative flex-1 m-5"> className="absolute inset-0 z-50 pointer-events-none"
<div className="flex items-start justify-between"> ref={setWrapper}
<div className="flex gap-4"> >
<div className="pointer-events-auto"> <div className="flex h-full">
<TransformControlsModeSelect <div className="relative flex-1 m-5">
value={transformControlsMode} <div className="flex items-start justify-between">
onChange={(value) => <div className="flex gap-4">
studio.transaction(({set}) => <div className="pointer-events-auto">
set(editorObject!.props.transformControlsMode, value), <TransformControlsModeSelect
) value={transformControlsMode}
} onChange={(value) =>
/> studio.transaction(({set}) =>
</div> set(editorObject!.props.transformControlsMode, value),
<div className="pointer-events-auto">
<TransformControlsSpaceSelect
value={transformControlsSpace}
onChange={(space) => {
studio.transaction(({set}) => {
set(editorObject.props.transformControlsSpace, space)
})
}}
/>
</div>
<div className="pointer-events-auto">
<ViewportShadingSelect
value={viewportShading}
onChange={(shading) => {
studio.transaction(({set}) => {
set(editorObject.props.viewportShading, shading)
})
}}
/>
</div>
<div className="pointer-events-auto">
<IconButton
label="Focus on selected"
icon={<RiFocus3Line />}
onClick={() => {
const orbitControls =
useEditorStore.getState().orbitControlsRef?.current
const selected = getSelected()
let focusObject
if (selected) {
focusObject =
useEditorStore.getState().editablesSnapshot![selected]
.proxyObject
}
if (orbitControls && focusObject) {
focusObject.getWorldPosition(
// @ts-ignore TODO
orbitControls.target as Vector3,
) )
} }
}} />
/> </div>
</div> <div className="pointer-events-auto">
<div className="pointer-events-auto"> <TransformControlsSpaceSelect
<IconButton value={transformControlsSpace}
label="Align object to view" onChange={(space) => {
icon={<GiPocketBow />} studio.transaction(({set}) => {
onClick={() => { set(editorObject.props.transformControlsSpace, space)
const camera = ( })
useEditorStore.getState().orbitControlsRef }}
?.current as $FixMe />
)?.object </div>
<div className="pointer-events-auto">
<ViewportShadingSelect
value={viewportShading}
onChange={(shading) => {
studio.transaction(({set}) => {
set(editorObject.props.viewportShading, shading)
})
}}
/>
</div>
<div className="pointer-events-auto">
<IconButton
label="Focus on selected"
icon={<RiFocus3Line />}
onClick={() => {
const orbitControls =
useEditorStore.getState().orbitControlsRef?.current
const selected = getSelected()
const selected = getSelected() let focusObject
let proxyObject if (selected) {
focusObject =
if (selected) { useEditorStore.getState().editablesSnapshot![selected]
proxyObject = .proxyObject
useEditorStore.getState().editablesSnapshot![selected]
.proxyObject
if (proxyObject && camera) {
const direction = new Vector3()
const position = camera.position.clone()
camera.getWorldDirection(direction)
proxyObject.position.set(0, 0, 0)
proxyObject.lookAt(direction)
proxyObject.parent!.worldToLocal(position)
proxyObject.position.copy(position)
proxyObject.updateMatrix()
} }
}
}} if (orbitControls && focusObject) {
/> focusObject.getWorldPosition(
// @ts-ignore TODO
orbitControls.target as Vector3,
)
}
}}
/>
</div>
<div className="pointer-events-auto">
<IconButton
label="Align object to view"
icon={<GiPocketBow />}
onClick={() => {
const camera = (
useEditorStore.getState().orbitControlsRef
?.current as $FixMe
)?.object
const selected = getSelected()
let proxyObject
if (selected) {
proxyObject =
useEditorStore.getState().editablesSnapshot![selected]
.proxyObject
if (proxyObject && camera) {
const direction = new Vector3()
const position = camera.position.clone()
camera.getWorldDirection(direction)
proxyObject.position.set(0, 0, 0)
proxyObject.lookAt(direction)
proxyObject.parent!.worldToLocal(position)
proxyObject.position.copy(position)
proxyObject.updateMatrix()
}
}
}}
/>
</div>
</div>
<div className="absolute right-0 top-0 -z-10">
<ReferenceWindow height={referenceWindowSize} />
</div> </div>
</div>
<div className="absolute right-0 top-0 -z-10">
<ReferenceWindow height={referenceWindowSize} />
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </PortalContext.Provider>
) )
} }

View file

@ -2,6 +2,7 @@ import type {ReactElement, ReactNode} from 'react'
import React from 'react' import React from 'react'
import type {IconType} from 'react-icons' import type {IconType} from 'react-icons'
import {Group, Button} from 'reakit' import {Group, Button} from 'reakit'
import styled from 'styled-components'
import {Tooltip, TooltipReference, useTooltipState} from './Tooltip' import {Tooltip, TooltipReference, useTooltipState} from './Tooltip'
interface OptionButtonProps<Option> { interface OptionButtonProps<Option> {
@ -12,6 +13,8 @@ interface OptionButtonProps<Option> {
onClick: () => void onClick: () => void
} }
// const Ro = styled(TooltipReference)``
function OptionButton<Option>({ function OptionButton<Option>({
value, value,
option, option,
@ -51,16 +54,17 @@ interface CompactModeSelectProps<Option> {
settingsPanel?: ReactNode settingsPanel?: ReactNode
} }
const Container = styled(Group)`
display: flex;
`
const CompactModeSelect = <Option extends string | number>({ const CompactModeSelect = <Option extends string | number>({
value, value,
onChange, onChange,
options, options,
}: CompactModeSelectProps<Option>) => { }: CompactModeSelectProps<Option>) => {
return ( return (
<Group <Container>
// @ts-ignore
className="flex"
>
{options.map(({label, icon, option}) => ( {options.map(({label, icon, option}) => (
<OptionButton <OptionButton
key={option} key={option}
@ -71,7 +75,7 @@ const CompactModeSelect = <Option extends string | number>({
onClick={() => onChange(option)} onClick={() => onChange(option)}
/> />
))} ))}
</Group> </Container>
) )
} }

View file

@ -3802,6 +3802,7 @@ __metadata:
"@types/lodash-es": ^4.17.4 "@types/lodash-es": ^4.17.4
"@types/node": ^15.6.2 "@types/node": ^15.6.2
"@types/react": ^17.0.9 "@types/react": ^17.0.9
"@types/styled-components": ^5.1.9
lodash-es: ^4.17.21 lodash-es: ^4.17.21
prism-react-renderer: 1.2.1 prism-react-renderer: 1.2.1
react: ^17.0.2 react: ^17.0.2
@ -3811,6 +3812,7 @@ __metadata:
react-shadow: ^19.0.2 react-shadow: ^19.0.2
react-use-measure: ^2.0.4 react-use-measure: ^2.0.4
reakit: ^1.3.8 reakit: ^1.3.8
styled-components: ^5.3.0
three: ^0.129.0 three: ^0.129.0
typescript: ^4.3.2 typescript: ^4.3.2
zustand: ^3.5.1 zustand: ^3.5.1