Nudging behavior on number props can now be customized
This commit is contained in:
parent
74724d7ec1
commit
36017c6a73
7 changed files with 81 additions and 14 deletions
|
@ -13,7 +13,7 @@ const editorSheetObjectConfig = types.compound({
|
|||
showAxes: types.boolean(true, {label: 'Axes'}),
|
||||
showGrid: types.boolean(true, {label: 'Grid'}),
|
||||
showOverlayIcons: types.boolean(false, {label: 'Overlay Icons'}),
|
||||
resolution: types.number(1440, {
|
||||
resolution: types.number(500, {
|
||||
label: 'Resolution',
|
||||
range: [0, 1000],
|
||||
}),
|
||||
|
|
|
@ -18,21 +18,25 @@ export type TransformControlsMode = 'translate' | 'rotate' | 'scale'
|
|||
export type TransformControlsSpace = 'world' | 'local'
|
||||
export type ViewportShading = 'wireframe' | 'flat' | 'solid' | 'rendered'
|
||||
|
||||
const positionComp = types.number(1, {nudgeMultiplier: 0.1})
|
||||
const rotationComp = types.number(1, {nudgeMultiplier: 0.02})
|
||||
const scaleComp = types.number(1, {nudgeMultiplier: 0.1})
|
||||
|
||||
export const baseSheetObjectType = types.compound({
|
||||
position: types.compound({
|
||||
x: types.number(0),
|
||||
y: types.number(0),
|
||||
z: types.number(0),
|
||||
x: positionComp,
|
||||
y: positionComp,
|
||||
z: positionComp,
|
||||
}),
|
||||
rotation: types.compound({
|
||||
x: types.number(0),
|
||||
y: types.number(0),
|
||||
z: types.number(0),
|
||||
x: rotationComp,
|
||||
y: rotationComp,
|
||||
z: rotationComp,
|
||||
}),
|
||||
scale: types.compound({
|
||||
x: types.number(1),
|
||||
y: types.number(1),
|
||||
z: types.number(1),
|
||||
x: scaleComp,
|
||||
y: scaleComp,
|
||||
z: scaleComp,
|
||||
}),
|
||||
})
|
||||
|
||||
|
|
|
@ -13,11 +13,40 @@ export interface PropTypeConfig_Number extends IBasePropType<number> {
|
|||
type: 'number'
|
||||
default: number
|
||||
range?: [min: number, max: number]
|
||||
nudgeFn: NumberNudgeFn
|
||||
nudgeMultiplier: number
|
||||
}
|
||||
|
||||
export type NumberNudgeFn = (p: {
|
||||
deltaX: number
|
||||
deltaFraction: number
|
||||
magnitude: number
|
||||
config: PropTypeConfig_Number
|
||||
}) => number
|
||||
|
||||
const defaultNumberNudgeFn: NumberNudgeFn = ({
|
||||
config,
|
||||
deltaX,
|
||||
deltaFraction,
|
||||
magnitude,
|
||||
}) => {
|
||||
const {range} = config
|
||||
if (range) {
|
||||
return (
|
||||
deltaFraction * (range[1] - range[0]) * magnitude * config.nudgeMultiplier
|
||||
)
|
||||
}
|
||||
|
||||
return deltaX * magnitude * config.nudgeMultiplier
|
||||
}
|
||||
|
||||
export const number = (
|
||||
defaultValue: number,
|
||||
opts?: Pick<PropTypeConfig_Number, 'range'> & PropTypeConfigExtras,
|
||||
opts?: {
|
||||
nudgeFn?: PropTypeConfig_Number['nudgeFn']
|
||||
range?: PropTypeConfig_Number['range']
|
||||
nudgeMultiplier?: number
|
||||
} & PropTypeConfigExtras,
|
||||
): PropTypeConfig_Number => {
|
||||
return {
|
||||
type: 'number',
|
||||
|
@ -26,6 +55,9 @@ export const number = (
|
|||
[s]: 'TheatrePropType',
|
||||
...(opts ? opts : {}),
|
||||
label: opts?.label,
|
||||
nudgeFn: opts?.nudgeFn ?? defaultNumberNudgeFn,
|
||||
nudgeMultiplier:
|
||||
typeof opts?.nudgeMultiplier === 'number' ? opts.nudgeMultiplier : 1,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type {PropTypeConfig_Number} from '@theatre/core/propTypes'
|
||||
import type SheetObject from '@theatre/core/sheetObjects/SheetObject'
|
||||
import BasicNumberInput from '@theatre/studio/uiComponents/form/BasicNumberInput'
|
||||
import React from 'react'
|
||||
import React, {useCallback} from 'react'
|
||||
import {useEditingToolsForPrimitiveProp} from './utils/useEditingToolsForPrimitiveProp'
|
||||
import {SingleRowPropEditor} from './utils/SingleRowPropEditor'
|
||||
|
||||
|
@ -12,6 +12,13 @@ const NumberPropEditor: React.FC<{
|
|||
}> = ({propConfig, pointerToProp, obj}) => {
|
||||
const stuff = useEditingToolsForPrimitiveProp<number>(pointerToProp, obj)
|
||||
|
||||
const nudge = useCallback(
|
||||
(params: {deltaX: number; deltaFraction: number; magnitude: number}) => {
|
||||
return propConfig.nudgeFn({...params, config: propConfig})
|
||||
},
|
||||
[propConfig],
|
||||
)
|
||||
|
||||
return (
|
||||
<SingleRowPropEditor {...{stuff, propConfig, pointerToProp}}>
|
||||
<BasicNumberInput
|
||||
|
@ -20,6 +27,7 @@ const NumberPropEditor: React.FC<{
|
|||
discardTemporaryValue={stuff.discardTemporaryValue}
|
||||
permenantlySetValue={stuff.permenantlySetValue}
|
||||
range={propConfig.range}
|
||||
nudge={nudge}
|
||||
/>
|
||||
</SingleRowPropEditor>
|
||||
)
|
||||
|
|
|
@ -4,6 +4,7 @@ import styled from 'styled-components'
|
|||
import type {SequenceEditorPanelLayout} from '@theatre/studio/panels/SequenceEditorPanel/layout/layout'
|
||||
import {usePrism, useVal} from '@theatre/dataverse-react'
|
||||
import getStudio from '@theatre/studio/getStudio'
|
||||
import type {BasicNumberInputNudgeFn} from '@theatre/studio/uiComponents/form/BasicNumberInput'
|
||||
import BasicNumberInput from '@theatre/studio/uiComponents/form/BasicNumberInput'
|
||||
import type {CommitOrDiscard} from '@theatre/studio/StudioStore/StudioStore'
|
||||
import {propNameText} from '@theatre/studio/panels/DetailPanel/propEditors/utils/SingleRowPropEditor'
|
||||
|
@ -23,6 +24,8 @@ const Label = styled.div`
|
|||
white-space: nowrap;
|
||||
`
|
||||
|
||||
const nudge: BasicNumberInputNudgeFn = ({deltaX}) => deltaX * 0.25
|
||||
|
||||
const LengthEditorPopover: React.FC<{
|
||||
layoutP: Pointer<SequenceEditorPanelLayout>
|
||||
/**
|
||||
|
@ -87,6 +90,7 @@ const LengthEditorPopover: React.FC<{
|
|||
isValid={greaterThanZero}
|
||||
inputRef={inputRef}
|
||||
onBlur={onRequestClose}
|
||||
nudge={nudge}
|
||||
/>
|
||||
</Container>
|
||||
)
|
||||
|
|
|
@ -73,6 +73,7 @@ const FillIndicator = styled.div`
|
|||
background-color: #2d5561;
|
||||
z-index: -1;
|
||||
border-radius: 2px;
|
||||
pointer-events: none;
|
||||
|
||||
${Container}.dragging &, ${Container}.noFocus:hover & {
|
||||
background-color: #338198;
|
||||
|
@ -103,6 +104,12 @@ type IState = IState_NoFocus | IState_EditingViaKeyboard | IState_Dragging
|
|||
|
||||
const alwaysValid = (v: number) => true
|
||||
|
||||
export type BasicNumberInputNudgeFn = (params: {
|
||||
deltaX: number
|
||||
deltaFraction: number
|
||||
magnitude: number
|
||||
}) => number
|
||||
|
||||
const BasicNumberInput: React.FC<{
|
||||
value: number
|
||||
temporarilySetValue: (v: number) => void
|
||||
|
@ -117,6 +124,7 @@ const BasicNumberInput: React.FC<{
|
|||
* before this, so use this for UI purposes such as closing a popover.
|
||||
*/
|
||||
onBlur?: () => void
|
||||
nudge: BasicNumberInputNudgeFn
|
||||
}> = (propsA) => {
|
||||
const [stateA, setState] = useState<IState>({mode: 'noFocus'})
|
||||
const isValid = propsA.isValid ?? alwaysValid
|
||||
|
@ -207,8 +215,11 @@ const BasicNumberInput: React.FC<{
|
|||
})
|
||||
}
|
||||
|
||||
let inputWidth: number
|
||||
|
||||
const transitionToDraggingMode = () => {
|
||||
const curValue = refs.current.props.value
|
||||
inputWidth = inputRef.current?.getBoundingClientRect().width!
|
||||
|
||||
setState({
|
||||
mode: 'dragging',
|
||||
|
@ -238,9 +249,16 @@ const BasicNumberInput: React.FC<{
|
|||
}
|
||||
}
|
||||
|
||||
const onDrag = (dx: number, _dy: number) => {
|
||||
const onDrag = (deltaX: number, _dy: number) => {
|
||||
const curState = refs.current.state as IState_Dragging
|
||||
const newValue = curState.valueBeforeDragging + dx
|
||||
|
||||
const newValue =
|
||||
curState.valueBeforeDragging +
|
||||
propsA.nudge({
|
||||
deltaX,
|
||||
deltaFraction: deltaX / inputWidth,
|
||||
magnitude: 1,
|
||||
})
|
||||
|
||||
setState({
|
||||
...curState,
|
||||
|
|
|
@ -23,6 +23,7 @@ const Container = styled.ul`
|
|||
min-width: ${minWidth}px;
|
||||
z-index: 10000;
|
||||
background: ${transparentize(0.2, '#111')};
|
||||
backdrop-filter: blur(2px);
|
||||
color: white;
|
||||
list-style-type: none;
|
||||
padding: 2px 0;
|
||||
|
|
Loading…
Reference in a new issue