diff --git a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/AggregatedKeyframeTrack/AggregateKeyframeEditor/AggregateKeyframeDot.tsx b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/AggregatedKeyframeTrack/AggregateKeyframeEditor/AggregateKeyframeDot.tsx index 388682b..1e6241e 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/AggregatedKeyframeTrack/AggregateKeyframeEditor/AggregateKeyframeDot.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/AggregatedKeyframeTrack/AggregateKeyframeEditor/AggregateKeyframeDot.tsx @@ -17,7 +17,11 @@ import type {KeyframeWithPathToPropFromCommonRoot} from '@theatre/studio/store/t import {commonRootOfPathsToProps} from '@theatre/shared/utils/addresses' import type {ILogger} from '@theatre/shared/logger' import DopeSnap from '@theatre/studio/panels/SequenceEditorPanel/RightOverlay/DopeSnap' -import type {EditingOptionsTree} from '@theatre/studio/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/useSingleKeyframeInlineEditorPopover' +import type { + PrimitivePropEditingOptions, + PropWithChildrenEditingOptionsTree, + SheetObjectEditingOptionsTree, +} from '@theatre/studio/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/useSingleKeyframeInlineEditorPopover' import {useKeyframeInlineEditorPopover} from '@theatre/studio/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/useSingleKeyframeInlineEditorPopover' import type { SequenceEditorTree_PrimitiveProp, @@ -31,17 +35,22 @@ type IAggregateKeyframeDotProps = { utils: IAggregateKeyframeEditorUtils } +const isOptionsTreeNodeNotNull = ( + a: PropWithChildrenEditingOptionsTree | PrimitivePropEditingOptions | null, +): a is PropWithChildrenEditingOptionsTree | PrimitivePropEditingOptions => + a !== null + function sheetObjectBuild( viewModel: SequenceEditorTree_SheetObject, keyframes: KeyframeWithTrack[], -): EditingOptionsTree | null { +): SheetObjectEditingOptionsTree | null { const children = viewModel.children .map((a) => a.type === 'propWithChildren' ? propWithChildrenBuild(a, keyframes) : primitivePropBuild(a, keyframes), ) - .filter((a): a is EditingOptionsTree => a !== null) + .filter(isOptionsTreeNodeNotNull) if (children.length === 0) return null return { type: 'sheetObject', @@ -52,14 +61,14 @@ function sheetObjectBuild( function propWithChildrenBuild( viewModel: SequenceEditorTree_PropWithChildren, keyframes: KeyframeWithTrack[], -): EditingOptionsTree | null { +): PropWithChildrenEditingOptionsTree | null { const children = viewModel.children .map((a) => a.type === 'propWithChildren' ? propWithChildrenBuild(a, keyframes) : primitivePropBuild(a, keyframes), ) - .filter((a): a is EditingOptionsTree => a !== null) + .filter(isOptionsTreeNodeNotNull) if (children.length === 0) return null return { type: 'propWithChildren', @@ -71,7 +80,7 @@ function propWithChildrenBuild( function primitivePropBuild( viewModelLeaf: SequenceEditorTree_PrimitiveProp, keyframes: KeyframeWithTrack[], -): EditingOptionsTree | null { +): PrimitivePropEditingOptions | null { const keyframe = keyframes.find((kf) => kf.track.id === viewModelLeaf.trackId) if (!keyframe) return null return { @@ -94,7 +103,9 @@ export function AggregateKeyframeDot( useKeyframeInlineEditorPopover( props.editorProps.viewModel.type === 'sheetObject' ? sheetObjectBuild(props.editorProps.viewModel, cur.keyframes) - : propWithChildrenBuild(props.editorProps.viewModel, cur.keyframes), + ?.children ?? null + : propWithChildrenBuild(props.editorProps.viewModel, cur.keyframes) + ?.children ?? null, ) const presence = usePresence(props.utils.itemKey) diff --git a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/DeterminePropEditorForSingleKeyframe.tsx b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/DeterminePropEditorForSingleKeyframe.tsx index 9880737..009ecf4 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/DeterminePropEditorForSingleKeyframe.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/DeterminePropEditorForSingleKeyframe.tsx @@ -4,8 +4,6 @@ import styled from 'styled-components' import type {PropTypeConfig_AllSimples} from '@theatre/core/propTypes' import type {ISimplePropEditorReactProps} from '@theatre/studio/propEditors/simpleEditors/ISimplePropEditorReactProps' import {simplePropEditorByPropType} from '@theatre/studio/propEditors/simpleEditors/simplePropEditorByPropType' - -import SingleKeyframeSimplePropEditor from './DeterminePropEditorForSingleKeyframe/SingleKeyframeSimplePropEditor' import type { EditingOptionsTree, PrimitivePropEditingOptions, @@ -33,7 +31,7 @@ const SingleKeyframePropLabel = styled.div` color: #919191; ` -const IndentedThing = styled.div` +const Indent = styled.div` margin-left: 24px; ` @@ -47,18 +45,24 @@ const IndentedThing = styled.div` * * @param p - propConfig object for any type of prop. */ -export function DeterminePropEditorForKeyframeTree(p: EditingOptionsTree) { +export function DeterminePropEditorForKeyframeTree( + p: EditingOptionsTree & {autoFocusInput?: boolean}, +) { if (p.type === 'sheetObject') { return ( <> {p.sheetObject.address.objectKey} - + {p.children.map((c, i) => ( - + ))} - + ) } else if (p.type === 'propWithChildren') { @@ -66,19 +70,31 @@ export function DeterminePropEditorForKeyframeTree(p: EditingOptionsTree) { return ( <> {label} - + {p.children.map((c, i) => ( - + ))} - + ) } else { - return + return } } -function BeepBoop(p: PrimitivePropEditingOptions) { +const SingleKeyframeSimplePropEditorContainer = styled.div` + padding: 0 6px; + display: flex; + align-items: center; +` + +function PrimitivePropEditor( + p: PrimitivePropEditingOptions & {autoFocusInput?: boolean}, +) { const label = p.propConfig.label ?? last(p.pathToProp) const editingTools = useEditingToolsForKeyframeEditorPopover(p) @@ -92,12 +108,14 @@ function BeepBoop(p: PrimitivePropEditingOptions) { return ( {label} - + + + ) } diff --git a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/DeterminePropEditorForSingleKeyframe/SingleKeyframeSimplePropEditor.tsx b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/DeterminePropEditorForSingleKeyframe/SingleKeyframeSimplePropEditor.tsx deleted file mode 100644 index 9354d58..0000000 --- a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/DeterminePropEditorForSingleKeyframe/SingleKeyframeSimplePropEditor.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import React from 'react' -import type {ISimplePropEditorReactProps} from '@theatre/studio/propEditors/simpleEditors/ISimplePropEditorReactProps' -import styled from 'styled-components' -import type {PropTypeConfig_AllSimples} from '@theatre/core/propTypes' -import type {IEditingTools} from '@theatre/studio/propEditors/utils/IEditingTools' - -export type ISingleKeyframeSimplePropEditorProps< - TPropTypeConfig extends PropTypeConfig_AllSimples, -> = { - propConfig: TPropTypeConfig - editingTools: IEditingTools - keyframeValue: TPropTypeConfig['valueType'] - SimpleEditorComponent: React.VFC> -} - -const SingleKeyframeSimplePropEditorContainer = styled.div` - padding: 0 6px; - display: flex; - align-items: center; -` - -/** - * Initially used for inline keyframe property editor, this editor is attached to the - * functionality of editing a property for a sequence keyframe. - */ -function SingleKeyframeSimplePropEditor< - TPropTypeConfig extends PropTypeConfig_AllSimples, ->({ - propConfig, - editingTools, - keyframeValue: value, - SimpleEditorComponent: EditorComponent, -}: ISingleKeyframeSimplePropEditorProps) { - return ( - - - - ) -} - -export default SingleKeyframeSimplePropEditor diff --git a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/SingleKeyframeDot.tsx b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/SingleKeyframeDot.tsx index 312f231..7274f8c 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/SingleKeyframeDot.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/SingleKeyframeDot.tsx @@ -102,38 +102,39 @@ const SingleKeyframeDot: React.VFC = (props) => { const [contextMenu] = useSingleKeyframeContextMenu(node, logger, props) const [inlineEditorPopover, openEditor, _, isInlineEditorPopoverOpen] = - useKeyframeInlineEditorPopover({ - type: 'primitiveProp', - keyframe: props.keyframe, - pathToProp: props.leaf.pathToProp, - propConfig: props.leaf.propConf, - sheetObject: props.leaf.sheetObject, - trackId: props.leaf.trackId, - }) - const [isDragging] = useDragForSingleKeyframeDot(node, props, { - onClickFromDrag(dragStartEvent) { - openEditor(dragStartEvent, ref.current!) + useKeyframeInlineEditorPopover([ + { + type: 'primitiveProp', + keyframe: props.keyframe, + pathToProp: props.leaf.pathToProp, + propConfig: props.leaf.propConf, + sheetObject: props.leaf.sheetObject, + trackId: props.leaf.trackId, }, - }) + ]) + const [isDragging] = useDragForSingleKeyframeDot(node, props, { + onClickFromDrag(dragStartEvent) { + openEditor(dragStartEvent, ref.current!) + }, + }) - return ( - <> - - - {inlineEditorPopover} - {contextMenu} - - ) - }, -) + return ( + <> + + + {inlineEditorPopover} + {contextMenu} + + ) +} export default SingleKeyframeDot diff --git a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/useSingleKeyframeInlineEditorPopover.tsx b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/useSingleKeyframeInlineEditorPopover.tsx index 270d8c0..29991de 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/useSingleKeyframeInlineEditorPopover.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/useSingleKeyframeInlineEditorPopover.tsx @@ -15,13 +15,19 @@ import type {UnknownValidCompoundProps} from '@theatre/core/propTypes/internals' /** The editor that pops up when directly clicking a Keyframe. */ export function useKeyframeInlineEditorPopover( - props: EditingOptionsTree | null, + props: EditingOptionsTree[] | null, ) { return usePopover({debugName: 'useKeyframeInlineEditorPopover'}, () => ( - {props === null ? undefined : ( - - )} + {!Array.isArray(props) + ? undefined + : props.map((prop, i) => ( + + ))} )) } @@ -30,12 +36,12 @@ export type EditingOptionsTree = | SheetObjectEditingOptionsTree | PropWithChildrenEditingOptionsTree | PrimitivePropEditingOptions -type SheetObjectEditingOptionsTree = { +export type SheetObjectEditingOptionsTree = { type: 'sheetObject' sheetObject: SheetObject children: EditingOptionsTree[] } -type PropWithChildrenEditingOptionsTree = { +export type PropWithChildrenEditingOptionsTree = { type: 'propWithChildren' propConfig: PropTypeConfig_Compound pathToProp: PathToProp diff --git a/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/GraphEditorDotNonScalar.tsx b/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/GraphEditorDotNonScalar.tsx index 805de39..2d92a3e 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/GraphEditorDotNonScalar.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/GraphEditorDotNonScalar.tsx @@ -71,13 +71,16 @@ const GraphEditorDotNonScalar: React.VFC = (props) => { const curValue = props.which === 'left' ? 0 : 1 const [inlineEditorPopover, openEditor, _, _isInlineEditorPopoverOpen] = - useKeyframeInlineEditorPopover({ - keyframe: props.keyframe, - pathToProp: props.pathToProp, - propConf: props.propConfig, - sheetObject: props.sheetObject, - trackId: props.trackId, - }) + useKeyframeInlineEditorPopover([ + { + type: 'primitiveProp', + keyframe: props.keyframe, + pathToProp: props.pathToProp, + propConfig: props.propConfig, + sheetObject: props.sheetObject, + trackId: props.trackId, + }, + ]) const isDragging = useDragKeyframe({ node, diff --git a/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/GraphEditorDotScalar.tsx b/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/GraphEditorDotScalar.tsx index fccccc9..1e37624 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/GraphEditorDotScalar.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/GraphEditorDotScalar.tsx @@ -71,13 +71,16 @@ const GraphEditorDotScalar: React.VFC = (props) => { const cyInExtremumSpace = props.extremumSpace.fromValueSpace(curValue) const [inlineEditorPopover, openEditor, _, _isInlineEditorPopoverOpen] = - useKeyframeInlineEditorPopover({ - keyframe: props.keyframe, - pathToProp: props.pathToProp, - propConf: props.propConfig, - sheetObject: props.sheetObject, - trackId: props.trackId, - }) + useKeyframeInlineEditorPopover([ + { + type: 'primitiveProp', + keyframe: props.keyframe, + pathToProp: props.pathToProp, + propConfig: props.propConfig, + sheetObject: props.sheetObject, + trackId: props.trackId, + }, + ]) const isDragging = useDragKeyframe({ node, diff --git a/theatre/studio/src/propEditors/simpleEditors/BooleanPropEditor.tsx b/theatre/studio/src/propEditors/simpleEditors/BooleanPropEditor.tsx index 787cd44..ff460c1 100644 --- a/theatre/studio/src/propEditors/simpleEditors/BooleanPropEditor.tsx +++ b/theatre/studio/src/propEditors/simpleEditors/BooleanPropEditor.tsx @@ -6,12 +6,17 @@ import type {ISimplePropEditorReactProps} from './ISimplePropEditorReactProps' const Input = styled(BasicCheckbox)` margin-left: 6px; + + :focus { + outline: 1px solid #555; + } ` function BooleanPropEditor({ propConfig, editingTools, value, + autoFocus, }: ISimplePropEditorReactProps) { const onChange = useCallback( (el: React.ChangeEvent) => { @@ -20,7 +25,7 @@ function BooleanPropEditor({ [propConfig, editingTools], ) - return + return } export default BooleanPropEditor diff --git a/theatre/studio/src/propEditors/simpleEditors/ISimplePropEditorReactProps.ts b/theatre/studio/src/propEditors/simpleEditors/ISimplePropEditorReactProps.ts index c49aa12..0cbe098 100644 --- a/theatre/studio/src/propEditors/simpleEditors/ISimplePropEditorReactProps.ts +++ b/theatre/studio/src/propEditors/simpleEditors/ISimplePropEditorReactProps.ts @@ -8,4 +8,5 @@ export type ISimplePropEditorReactProps< propConfig: TPropTypeConfig editingTools: IEditingTools value: TPropTypeConfig['valueType'] + autoFocus?: boolean } diff --git a/theatre/studio/src/propEditors/simpleEditors/NumberPropEditor.tsx b/theatre/studio/src/propEditors/simpleEditors/NumberPropEditor.tsx index eff8b46..9682066 100644 --- a/theatre/studio/src/propEditors/simpleEditors/NumberPropEditor.tsx +++ b/theatre/studio/src/propEditors/simpleEditors/NumberPropEditor.tsx @@ -7,6 +7,7 @@ function NumberPropEditor({ propConfig, editingTools, value, + autoFocus, }: ISimplePropEditorReactProps) { const nudge = useCallback( (params: {deltaX: number; deltaFraction: number; magnitude: number}) => { @@ -23,6 +24,7 @@ function NumberPropEditor({ permanentlySetValue={editingTools.permanentlySetValue} range={propConfig.range} nudge={nudge} + autoFocus={autoFocus} /> ) } diff --git a/theatre/studio/src/propEditors/simpleEditors/RgbaPropEditor.tsx b/theatre/studio/src/propEditors/simpleEditors/RgbaPropEditor.tsx index ad98d9f..f9a5e26 100644 --- a/theatre/studio/src/propEditors/simpleEditors/RgbaPropEditor.tsx +++ b/theatre/studio/src/propEditors/simpleEditors/RgbaPropEditor.tsx @@ -63,6 +63,7 @@ const RgbaPopover = styled.div` function RgbaPropEditor({ editingTools, value, + autoFocus, }: ISimplePropEditorReactProps) { const containerRef = useRef(null!) @@ -116,6 +117,7 @@ function RgbaPropEditor({ discardTemporaryValue={noop} permanentlySetValue={onChange} isValid={(v) => !!v.match(validHexRegExp)} + autoFocus={autoFocus} /> {popoverNode} diff --git a/theatre/studio/src/propEditors/simpleEditors/StringLiteralPropEditor.tsx b/theatre/studio/src/propEditors/simpleEditors/StringLiteralPropEditor.tsx index 4648a26..57356e7 100644 --- a/theatre/studio/src/propEditors/simpleEditors/StringLiteralPropEditor.tsx +++ b/theatre/studio/src/propEditors/simpleEditors/StringLiteralPropEditor.tsx @@ -8,6 +8,7 @@ function StringLiteralPropEditor({ propConfig, editingTools, value, + autoFocus, }: ISimplePropEditorReactProps>) { const onChange = useCallback( (val: TLiteralOptions) => { @@ -21,12 +22,14 @@ function StringLiteralPropEditor({ value={value} onChange={onChange} options={propConfig.valuesAndLabels} + autoFocus={autoFocus} /> ) : ( ) } diff --git a/theatre/studio/src/propEditors/simpleEditors/StringPropEditor.tsx b/theatre/studio/src/propEditors/simpleEditors/StringPropEditor.tsx index f01d854..a72a104 100644 --- a/theatre/studio/src/propEditors/simpleEditors/StringPropEditor.tsx +++ b/theatre/studio/src/propEditors/simpleEditors/StringPropEditor.tsx @@ -6,6 +6,7 @@ import type {ISimplePropEditorReactProps} from './ISimplePropEditorReactProps' function StringPropEditor({ editingTools, value, + autoFocus, }: ISimplePropEditorReactProps) { return ( ) } diff --git a/theatre/studio/src/uiComponents/form/BasicNumberInput.tsx b/theatre/studio/src/uiComponents/form/BasicNumberInput.tsx index 6e1bb62..70feb91 100644 --- a/theatre/studio/src/uiComponents/form/BasicNumberInput.tsx +++ b/theatre/studio/src/uiComponents/form/BasicNumberInput.tsx @@ -115,6 +115,7 @@ const BasicNumberInput: React.FC<{ */ onBlur?: () => void nudge: BasicNumberInputNudgeFn + autoFocus?: boolean }> = (propsA) => { const [stateRef] = useRefAndState({mode: 'noFocus'}) const isValid = propsA.isValid ?? alwaysValid @@ -307,6 +308,7 @@ const BasicNumberInput: React.FC<{ e.preventDefault() e.stopPropagation() }} + autoFocus={propsA.autoFocus} /> ) diff --git a/theatre/studio/src/uiComponents/form/BasicSelect.tsx b/theatre/studio/src/uiComponents/form/BasicSelect.tsx index dde9280..abfec78 100644 --- a/theatre/studio/src/uiComponents/form/BasicSelect.tsx +++ b/theatre/studio/src/uiComponents/form/BasicSelect.tsx @@ -55,11 +55,13 @@ function BasicSelect({ onChange, options, className, + autoFocus, }: { value: TLiteralOptions onChange: (val: TLiteralOptions) => void options: Record className?: string + autoFocus?: boolean }) { const _onChange = useCallback( (el: React.ChangeEvent) => { @@ -70,7 +72,12 @@ function BasicSelect({ return ( - {Object.keys(options).map((key, i) => (