Show hovered prop from sequence editor in details panel
* Remove an un-needed prism Co-authored-by: Cole Lawrence <cole@colelawrence.com> Co-authored-by: Aria Minaei <aria.minaei@gmail.com>
This commit is contained in:
parent
162174568b
commit
c74aa1b930
10 changed files with 240 additions and 37 deletions
|
@ -5,9 +5,9 @@ import {getPointerParts} from '@theatre/dataverse'
|
||||||
import type {Pointer} from '@theatre/dataverse'
|
import type {Pointer} from '@theatre/dataverse'
|
||||||
import last from 'lodash-es/last'
|
import last from 'lodash-es/last'
|
||||||
import {darken, transparentize} from 'polished'
|
import {darken, transparentize} from 'polished'
|
||||||
import React from 'react'
|
import React, {useMemo} from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import {indentationFormula} from '@theatre/studio/panels/DetailPanel/DeterminePropEditorForDetail/SingleRowPropEditor'
|
import {rowIndentationFormulaCSS} from '@theatre/studio/panels/DetailPanel/DeterminePropEditorForDetail/rowIndentationFormulaCSS'
|
||||||
import {propNameTextCSS} from '@theatre/studio/propEditors/utils/propNameTextCSS'
|
import {propNameTextCSS} from '@theatre/studio/propEditors/utils/propNameTextCSS'
|
||||||
import {pointerEventsAutoInNormalMode} from '@theatre/studio/css'
|
import {pointerEventsAutoInNormalMode} from '@theatre/studio/css'
|
||||||
import useRefAndState from '@theatre/studio/utils/useRefAndState'
|
import useRefAndState from '@theatre/studio/utils/useRefAndState'
|
||||||
|
@ -16,6 +16,10 @@ import type SheetObject from '@theatre/core/sheetObjects/SheetObject'
|
||||||
|
|
||||||
import useContextMenu from '@theatre/studio/uiComponents/simpleContextMenu/useContextMenu'
|
import useContextMenu from '@theatre/studio/uiComponents/simpleContextMenu/useContextMenu'
|
||||||
import {useEditingToolsForCompoundProp} from '@theatre/studio/propEditors/useEditingToolsForCompoundProp'
|
import {useEditingToolsForCompoundProp} from '@theatre/studio/propEditors/useEditingToolsForCompoundProp'
|
||||||
|
import type {PropHighlighted} from '@theatre/studio/panels/SequenceEditorPanel/whatPropIsHighlighted'
|
||||||
|
import {whatPropIsHighlighted} from '@theatre/studio/panels/SequenceEditorPanel/whatPropIsHighlighted'
|
||||||
|
import {deriver} from '@theatre/studio/utils/derive-utils'
|
||||||
|
import {getDetailRowHighlightBackground} from './getDetailRowHighlightBackground'
|
||||||
|
|
||||||
const Container = styled.div`
|
const Container = styled.div`
|
||||||
--step: 15px;
|
--step: 15px;
|
||||||
|
@ -23,15 +27,17 @@ const Container = styled.div`
|
||||||
${pointerEventsAutoInNormalMode};
|
${pointerEventsAutoInNormalMode};
|
||||||
`
|
`
|
||||||
|
|
||||||
const Header = styled.div`
|
const Header = deriver(styled.div<{isHighlighted: PropHighlighted}>`
|
||||||
height: 30px;
|
height: 30px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
position: relative;
|
position: relative;
|
||||||
`
|
|
||||||
|
background-color: ${getDetailRowHighlightBackground};
|
||||||
|
`)
|
||||||
|
|
||||||
const Padding = styled.div`
|
const Padding = styled.div`
|
||||||
padding-left: ${indentationFormula};
|
padding-left: ${rowIndentationFormulaCSS};
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
`
|
`
|
||||||
|
@ -99,12 +105,22 @@ function DetailCompoundPropEditor<
|
||||||
|
|
||||||
const lastSubPropIsComposite = compositeSubs.length > 0
|
const lastSubPropIsComposite = compositeSubs.length > 0
|
||||||
|
|
||||||
|
const isPropHighlightedD = useMemo(
|
||||||
|
() =>
|
||||||
|
whatPropIsHighlighted.getIsPropHighlightedD({
|
||||||
|
...obj.address,
|
||||||
|
pathToProp: getPointerParts(pointerToProp).path,
|
||||||
|
}),
|
||||||
|
[pointerToProp],
|
||||||
|
)
|
||||||
|
|
||||||
// previous versions of the DetailCompoundPropEditor had a context menu item for "Reset values".
|
// previous versions of the DetailCompoundPropEditor had a context menu item for "Reset values".
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
{contextMenu}
|
{contextMenu}
|
||||||
<Header
|
<Header
|
||||||
|
isHighlighted={isPropHighlightedD}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
style={{'--depth': visualIndentation - 1}}
|
style={{'--depth': visualIndentation - 1}}
|
||||||
>
|
>
|
||||||
|
@ -138,4 +154,4 @@ function DetailCompoundPropEditor<
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DetailCompoundPropEditor
|
export default React.memo(DetailCompoundPropEditor)
|
||||||
|
|
|
@ -2,12 +2,14 @@ import type {
|
||||||
IBasePropType,
|
IBasePropType,
|
||||||
PropTypeConfig_AllSimples,
|
PropTypeConfig_AllSimples,
|
||||||
} from '@theatre/core/propTypes'
|
} from '@theatre/core/propTypes'
|
||||||
import React from 'react'
|
import React, {useMemo} from 'react'
|
||||||
import {useEditingToolsForSimplePropInDetailsPanel} from '@theatre/studio/propEditors/useEditingToolsForSimpleProp'
|
import {useEditingToolsForSimplePropInDetailsPanel} from '@theatre/studio/propEditors/useEditingToolsForSimpleProp'
|
||||||
import {SingleRowPropEditor} from '@theatre/studio/panels/DetailPanel/DeterminePropEditorForDetail/SingleRowPropEditor'
|
import {SingleRowPropEditor} from '@theatre/studio/panels/DetailPanel/DeterminePropEditorForDetail/SingleRowPropEditor'
|
||||||
import type {Pointer} from '@theatre/dataverse'
|
import type {Pointer} from '@theatre/dataverse'
|
||||||
|
import {getPointerParts} from '@theatre/dataverse'
|
||||||
import type SheetObject from '@theatre/core/sheetObjects/SheetObject'
|
import type SheetObject from '@theatre/core/sheetObjects/SheetObject'
|
||||||
import type {ISimplePropEditorReactProps} from '@theatre/studio/propEditors/simpleEditors/ISimplePropEditorReactProps'
|
import type {ISimplePropEditorReactProps} from '@theatre/studio/propEditors/simpleEditors/ISimplePropEditorReactProps'
|
||||||
|
import {whatPropIsHighlighted} from '@theatre/studio/panels/SequenceEditorPanel/whatPropIsHighlighted'
|
||||||
|
|
||||||
export type IDetailSimplePropEditorProps<
|
export type IDetailSimplePropEditorProps<
|
||||||
TPropTypeConfig extends IBasePropType<string, any>,
|
TPropTypeConfig extends IBasePropType<string, any>,
|
||||||
|
@ -37,9 +39,23 @@ function DetailSimplePropEditor<
|
||||||
propConfig,
|
propConfig,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const isPropHighlightedD = useMemo(
|
||||||
|
() =>
|
||||||
|
whatPropIsHighlighted.getIsPropHighlightedD({
|
||||||
|
...obj.address,
|
||||||
|
pathToProp: getPointerParts(pointerToProp).path,
|
||||||
|
}),
|
||||||
|
[pointerToProp],
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SingleRowPropEditor
|
<SingleRowPropEditor
|
||||||
{...{editingTools: editingTools, propConfig, pointerToProp}}
|
{...{
|
||||||
|
editingTools: editingTools,
|
||||||
|
propConfig,
|
||||||
|
pointerToProp,
|
||||||
|
isPropHighlightedD,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<EditorComponent
|
<EditorComponent
|
||||||
editingTools={editingTools}
|
editingTools={editingTools}
|
||||||
|
@ -50,4 +66,4 @@ function DetailSimplePropEditor<
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DetailSimplePropEditor
|
export default React.memo(DetailSimplePropEditor)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import type * as propTypes from '@theatre/core/propTypes'
|
import type * as propTypes from '@theatre/core/propTypes'
|
||||||
import {getPointerParts} from '@theatre/dataverse'
|
import {getPointerParts} from '@theatre/dataverse'
|
||||||
import type {Pointer} from '@theatre/dataverse'
|
import type {Pointer, IDerivation} from '@theatre/dataverse'
|
||||||
import useContextMenu from '@theatre/studio/uiComponents/simpleContextMenu/useContextMenu'
|
import useContextMenu from '@theatre/studio/uiComponents/simpleContextMenu/useContextMenu'
|
||||||
import useRefAndState from '@theatre/studio/utils/useRefAndState'
|
import useRefAndState from '@theatre/studio/utils/useRefAndState'
|
||||||
import {last} from 'lodash-es'
|
import {last} from 'lodash-es'
|
||||||
|
@ -9,10 +9,14 @@ import type {useEditingToolsForSimplePropInDetailsPanel} from '@theatre/studio/p
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import {pointerEventsAutoInNormalMode} from '@theatre/studio/css'
|
import {pointerEventsAutoInNormalMode} from '@theatre/studio/css'
|
||||||
import {propNameTextCSS} from '@theatre/studio/propEditors/utils/propNameTextCSS'
|
import {propNameTextCSS} from '@theatre/studio/propEditors/utils/propNameTextCSS'
|
||||||
|
import type {PropHighlighted} from '@theatre/studio/panels/SequenceEditorPanel/whatPropIsHighlighted'
|
||||||
|
import {deriver} from '@theatre/studio/utils/derive-utils'
|
||||||
|
import {rowIndentationFormulaCSS} from './rowIndentationFormulaCSS'
|
||||||
|
import {getDetailRowHighlightBackground} from './getDetailRowHighlightBackground'
|
||||||
|
|
||||||
export const indentationFormula = `calc(var(--left-pad) + var(--depth) * var(--step))`
|
const Container = deriver(styled.div<{
|
||||||
|
isHighlighted: PropHighlighted
|
||||||
const Container = styled.div`
|
}>`
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
|
@ -28,11 +32,13 @@ const Container = styled.div`
|
||||||
--right-width: 60%;
|
--right-width: 60%;
|
||||||
position: relative;
|
position: relative;
|
||||||
${pointerEventsAutoInNormalMode};
|
${pointerEventsAutoInNormalMode};
|
||||||
`
|
|
||||||
|
background-color: ${getDetailRowHighlightBackground};
|
||||||
|
`)
|
||||||
|
|
||||||
const Left = styled.div`
|
const Left = styled.div`
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding-left: ${indentationFormula};
|
padding-left: ${rowIndentationFormulaCSS};
|
||||||
padding-right: 4px;
|
padding-right: 4px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@ -84,6 +90,7 @@ type ISingleRowPropEditorProps<T> = {
|
||||||
propConfig: propTypes.PropTypeConfig
|
propConfig: propTypes.PropTypeConfig
|
||||||
pointerToProp: Pointer<T>
|
pointerToProp: Pointer<T>
|
||||||
editingTools: ReturnType<typeof useEditingToolsForSimplePropInDetailsPanel>
|
editingTools: ReturnType<typeof useEditingToolsForSimplePropInDetailsPanel>
|
||||||
|
isPropHighlightedD: IDerivation<PropHighlighted>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SingleRowPropEditor<T>({
|
export function SingleRowPropEditor<T>({
|
||||||
|
@ -91,6 +98,7 @@ export function SingleRowPropEditor<T>({
|
||||||
pointerToProp,
|
pointerToProp,
|
||||||
editingTools,
|
editingTools,
|
||||||
children,
|
children,
|
||||||
|
isPropHighlightedD,
|
||||||
}: React.PropsWithChildren<ISingleRowPropEditorProps<T>>): React.ReactElement<
|
}: React.PropsWithChildren<ISingleRowPropEditorProps<T>>): React.ReactElement<
|
||||||
any,
|
any,
|
||||||
any
|
any
|
||||||
|
@ -105,11 +113,10 @@ export function SingleRowPropEditor<T>({
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container isHighlighted={isPropHighlightedD}>
|
||||||
{contextMenu}
|
{contextMenu}
|
||||||
<Left>
|
<Left>
|
||||||
<ControlsContainer>{editingTools.controlIndicators}</ControlsContainer>
|
<ControlsContainer>{editingTools.controlIndicators}</ControlsContainer>
|
||||||
|
|
||||||
<PropNameContainer
|
<PropNameContainer
|
||||||
ref={propNameContainerRef}
|
ref={propNameContainerRef}
|
||||||
title={['obj', 'props', ...getPointerParts(pointerToProp).path].join(
|
title={['obj', 'props', ...getPointerParts(pointerToProp).path].join(
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import type {PropHighlighted} from '@theatre/studio/panels/SequenceEditorPanel/whatPropIsHighlighted'
|
||||||
|
|
||||||
|
export function getDetailRowHighlightBackground({
|
||||||
|
isHighlighted,
|
||||||
|
}: {
|
||||||
|
isHighlighted: PropHighlighted
|
||||||
|
}): string {
|
||||||
|
return isHighlighted === 'self'
|
||||||
|
? '#1857a4'
|
||||||
|
: isHighlighted === 'descendent'
|
||||||
|
? '#0a2f5c'
|
||||||
|
: 'initial'
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export const rowIndentationFormulaCSS = `calc(var(--left-pad) + var(--depth) * var(--step))`
|
|
@ -1,10 +1,15 @@
|
||||||
import {theme} from '@theatre/studio/css'
|
import {theme} from '@theatre/studio/css'
|
||||||
import type {SequenceEditorTree_Row} from '@theatre/studio/panels/SequenceEditorPanel/layout/tree'
|
import type {
|
||||||
|
SequenceEditorTree_PrimitiveProp,
|
||||||
|
SequenceEditorTree_PropWithChildren,
|
||||||
|
SequenceEditorTree_SheetObject,
|
||||||
|
} from '@theatre/studio/panels/SequenceEditorPanel/layout/tree'
|
||||||
import type {VoidFn} from '@theatre/shared/utils/types'
|
import type {VoidFn} from '@theatre/shared/utils/types'
|
||||||
import React from 'react'
|
import React, {useRef} from 'react'
|
||||||
import {HiOutlineChevronRight} from 'react-icons/all'
|
import {HiOutlineChevronRight} from 'react-icons/all'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import {propNameTextCSS} from '@theatre/studio/propEditors/utils/propNameTextCSS'
|
import {propNameTextCSS} from '@theatre/studio/propEditors/utils/propNameTextCSS'
|
||||||
|
import {usePropHighlightMouseEnter} from './usePropHighlightMouseEnter'
|
||||||
|
|
||||||
export const LeftRowContainer = styled.li<{depth: number}>`
|
export const LeftRowContainer = styled.li<{depth: number}>`
|
||||||
--depth: ${(props) => props.depth};
|
--depth: ${(props) => props.depth};
|
||||||
|
@ -66,7 +71,10 @@ const LeftRowChildren = styled.ul`
|
||||||
`
|
`
|
||||||
|
|
||||||
const AnyCompositeRow: React.FC<{
|
const AnyCompositeRow: React.FC<{
|
||||||
leaf: SequenceEditorTree_Row<string>
|
leaf:
|
||||||
|
| SequenceEditorTree_PrimitiveProp
|
||||||
|
| SequenceEditorTree_PropWithChildren
|
||||||
|
| SequenceEditorTree_SheetObject
|
||||||
label: React.ReactNode
|
label: React.ReactNode
|
||||||
toggleSelect?: VoidFn
|
toggleSelect?: VoidFn
|
||||||
toggleCollapsed: VoidFn
|
toggleCollapsed: VoidFn
|
||||||
|
@ -85,8 +93,12 @@ const AnyCompositeRow: React.FC<{
|
||||||
}) => {
|
}) => {
|
||||||
const hasChildren = Array.isArray(children) && children.length > 0
|
const hasChildren = Array.isArray(children) && children.length > 0
|
||||||
|
|
||||||
|
const containerRef = useRef<HTMLLIElement | null>(null)
|
||||||
|
|
||||||
|
usePropHighlightMouseEnter(containerRef.current, leaf)
|
||||||
|
|
||||||
return leaf.shouldRender ? (
|
return leaf.shouldRender ? (
|
||||||
<LeftRowContainer depth={leaf.depth}>
|
<LeftRowContainer depth={leaf.depth} ref={containerRef}>
|
||||||
<LeftRowHeader
|
<LeftRowHeader
|
||||||
style={{
|
style={{
|
||||||
height: leaf.nodeHeight + 'px',
|
height: leaf.nodeHeight + 'px',
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {nextPrevCursorsTheme} from '@theatre/studio/propEditors/NextPrevKeyframe
|
||||||
import {graphEditorColors} from '@theatre/studio/panels/SequenceEditorPanel/GraphEditor/GraphEditor'
|
import {graphEditorColors} from '@theatre/studio/panels/SequenceEditorPanel/GraphEditor/GraphEditor'
|
||||||
import {BaseHeader, LeftRowContainer as BaseContainer} from './AnyCompositeRow'
|
import {BaseHeader, LeftRowContainer as BaseContainer} from './AnyCompositeRow'
|
||||||
import {propNameTextCSS} from '@theatre/studio/propEditors/utils/propNameTextCSS'
|
import {propNameTextCSS} from '@theatre/studio/propEditors/utils/propNameTextCSS'
|
||||||
|
import {usePropHighlightMouseEnter} from './usePropHighlightMouseEnter'
|
||||||
|
|
||||||
const theme = {
|
const theme = {
|
||||||
label: {
|
label: {
|
||||||
|
@ -131,8 +132,12 @@ const PrimitivePropRow: React.FC<{
|
||||||
const label = leaf.pathToProp[leaf.pathToProp.length - 1]
|
const label = leaf.pathToProp[leaf.pathToProp.length - 1]
|
||||||
const isSelectable = true
|
const isSelectable = true
|
||||||
|
|
||||||
|
const containerRef = useRef<HTMLLIElement | null>(null)
|
||||||
|
|
||||||
|
usePropHighlightMouseEnter(containerRef.current, leaf)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PrimitivePropRowContainer depth={leaf.depth}>
|
<PrimitivePropRowContainer depth={leaf.depth} ref={containerRef}>
|
||||||
<PrimitivePropRowHead
|
<PrimitivePropRowHead
|
||||||
isEven={leaf.n % 2 === 0}
|
isEven={leaf.n % 2 === 0}
|
||||||
style={{
|
style={{
|
||||||
|
|
|
@ -2,7 +2,6 @@ import type {
|
||||||
SequenceEditorTree_PrimitiveProp,
|
SequenceEditorTree_PrimitiveProp,
|
||||||
SequenceEditorTree_PropWithChildren,
|
SequenceEditorTree_PropWithChildren,
|
||||||
} from '@theatre/studio/panels/SequenceEditorPanel/layout/tree'
|
} from '@theatre/studio/panels/SequenceEditorPanel/layout/tree'
|
||||||
import {usePrism} from '@theatre/react'
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import AnyCompositeRow from './AnyCompositeRow'
|
import AnyCompositeRow from './AnyCompositeRow'
|
||||||
import PrimitivePropRow from './PrimitivePropRow'
|
import PrimitivePropRow from './PrimitivePropRow'
|
||||||
|
@ -26,20 +25,18 @@ export const decideRowByPropType = (
|
||||||
const PropWithChildrenRow: React.VFC<{
|
const PropWithChildrenRow: React.VFC<{
|
||||||
leaf: SequenceEditorTree_PropWithChildren
|
leaf: SequenceEditorTree_PropWithChildren
|
||||||
}> = ({leaf}) => {
|
}> = ({leaf}) => {
|
||||||
return usePrism(() => {
|
return (
|
||||||
return (
|
<AnyCompositeRow
|
||||||
<AnyCompositeRow
|
leaf={leaf}
|
||||||
leaf={leaf}
|
label={leaf.pathToProp[leaf.pathToProp.length - 1]}
|
||||||
label={leaf.pathToProp[leaf.pathToProp.length - 1]}
|
isCollapsed={leaf.isCollapsed}
|
||||||
isCollapsed={leaf.isCollapsed}
|
toggleCollapsed={() =>
|
||||||
toggleCollapsed={() =>
|
setCollapsedSheetObjectOrCompoundProp(!leaf.isCollapsed, leaf)
|
||||||
setCollapsedSheetObjectOrCompoundProp(!leaf.isCollapsed, leaf)
|
}
|
||||||
}
|
>
|
||||||
>
|
{leaf.children.map((propLeaf) => decideRowByPropType(propLeaf))}
|
||||||
{leaf.children.map((propLeaf) => decideRowByPropType(propLeaf))}
|
</AnyCompositeRow>
|
||||||
</AnyCompositeRow>
|
)
|
||||||
)
|
|
||||||
}, [leaf])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PropWithChildrenRow
|
export default PropWithChildrenRow
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
import type {SequenceEditorTree_AllRowTypes} from '@theatre/studio/panels/SequenceEditorPanel/layout/tree'
|
||||||
|
import type {PropAddress} from '@theatre/shared/utils/addresses'
|
||||||
|
import {useLayoutEffect} from 'react'
|
||||||
|
import {whatPropIsHighlighted} from '@theatre/studio/panels/SequenceEditorPanel/whatPropIsHighlighted'
|
||||||
|
|
||||||
|
/** This should ignore if */
|
||||||
|
export function usePropHighlightMouseEnter(
|
||||||
|
node: HTMLElement | null,
|
||||||
|
leaf: SequenceEditorTree_AllRowTypes,
|
||||||
|
) {
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
if (!node) return
|
||||||
|
if (leaf.type !== 'propWithChildren' && leaf.type !== 'primitiveProp')
|
||||||
|
return
|
||||||
|
|
||||||
|
let unlock: null | (() => void) = null
|
||||||
|
const propAddress: PropAddress = {
|
||||||
|
...leaf.sheetObject.address,
|
||||||
|
pathToProp: leaf.pathToProp,
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMouseEnter() {
|
||||||
|
unlock = whatPropIsHighlighted.replaceLock(propAddress, () => {
|
||||||
|
// cleanup on forced unlock
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function onMouseLeave() {
|
||||||
|
unlock?.()
|
||||||
|
}
|
||||||
|
|
||||||
|
node.addEventListener('mouseenter', onMouseEnter)
|
||||||
|
node.addEventListener('mouseleave', onMouseLeave)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unlock?.()
|
||||||
|
node.removeEventListener('mouseenter', onMouseEnter)
|
||||||
|
node.removeEventListener('mouseleave', onMouseLeave)
|
||||||
|
}
|
||||||
|
}, [node])
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
import type {IDerivation} from '@theatre/dataverse'
|
||||||
|
import {val} from '@theatre/dataverse'
|
||||||
|
import {Atom} from '@theatre/dataverse'
|
||||||
|
import {prism} from '@theatre/dataverse'
|
||||||
|
import type {
|
||||||
|
PropAddress,
|
||||||
|
WithoutSheetInstance,
|
||||||
|
} from '@theatre/shared/utils/addresses'
|
||||||
|
|
||||||
|
import pointerDeep from '@theatre/shared/utils/pointerDeep'
|
||||||
|
import type {$IntentionalAny, VoidFn} from '@theatre/shared/utils/types'
|
||||||
|
import lodashSet from 'lodash-es/set'
|
||||||
|
|
||||||
|
/** constant global manager */
|
||||||
|
export const whatPropIsHighlighted = createWhatPropIsHighlightedState()
|
||||||
|
|
||||||
|
export type PropHighlighted = 'self' | 'descendent' | null
|
||||||
|
|
||||||
|
/** Only used in prop highlighting with boolean. */
|
||||||
|
type PathToPropAsDeepObject<T extends boolean | number | string> = {
|
||||||
|
[key in string]: T | PathToPropAsDeepObject<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
function createWhatPropIsHighlightedState() {
|
||||||
|
let lastLockId = 0
|
||||||
|
const whatIsHighlighted = new Atom<
|
||||||
|
| {hasLock: false; deepPath?: undefined}
|
||||||
|
| {
|
||||||
|
hasLock: true
|
||||||
|
lockId: number
|
||||||
|
cleanup: () => void
|
||||||
|
deepPath: PathToPropAsDeepObject<boolean>
|
||||||
|
}
|
||||||
|
>({hasLock: false})
|
||||||
|
|
||||||
|
return {
|
||||||
|
replaceLock(address: WithoutSheetInstance<PropAddress>, cleanup: VoidFn) {
|
||||||
|
const lockId = lastLockId++
|
||||||
|
|
||||||
|
const existingState = whatIsHighlighted.getState()
|
||||||
|
if (existingState.hasLock) existingState.cleanup()
|
||||||
|
|
||||||
|
whatIsHighlighted.setState({
|
||||||
|
hasLock: true,
|
||||||
|
lockId,
|
||||||
|
cleanup,
|
||||||
|
deepPath: arrayToDeepObject(addressToArray(address)),
|
||||||
|
})
|
||||||
|
|
||||||
|
return function unlock() {
|
||||||
|
const curr = whatIsHighlighted.getState()
|
||||||
|
if (curr.hasLock && curr.lockId === lockId) {
|
||||||
|
curr.cleanup()
|
||||||
|
whatIsHighlighted.setState({hasLock: false})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getIsPropHighlightedD(
|
||||||
|
address: WithoutSheetInstance<PropAddress>,
|
||||||
|
): IDerivation<PropHighlighted> {
|
||||||
|
const highlightedP = pointerDeep(
|
||||||
|
whatIsHighlighted.pointer.deepPath,
|
||||||
|
addressToArray(address),
|
||||||
|
)
|
||||||
|
return prism(() => {
|
||||||
|
const value = val(highlightedP)
|
||||||
|
return value === true
|
||||||
|
? 'self'
|
||||||
|
: // obj continues deep path prop from here
|
||||||
|
value
|
||||||
|
? 'descendent'
|
||||||
|
: // some other prop or no lock
|
||||||
|
null
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addressToArray(
|
||||||
|
address: WithoutSheetInstance<PropAddress>,
|
||||||
|
): Array<string | number> {
|
||||||
|
return [
|
||||||
|
address.projectId,
|
||||||
|
address.sheetId,
|
||||||
|
address.objectKey,
|
||||||
|
...address.pathToProp,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
function arrayToDeepObject(
|
||||||
|
arr: Array<string | number>,
|
||||||
|
): PathToPropAsDeepObject<boolean> {
|
||||||
|
const obj = {}
|
||||||
|
lodashSet(obj, arr, true)
|
||||||
|
return obj as $IntentionalAny
|
||||||
|
}
|
Loading…
Reference in a new issue