diff --git a/packages/funnel/src/PartLabel.js b/packages/funnel/src/PartLabel.js
index 87d1a36c17..1f55d1f0a2 100644
--- a/packages/funnel/src/PartLabel.js
+++ b/packages/funnel/src/PartLabel.js
@@ -8,16 +8,18 @@
*/
import React from 'react'
import PropTypes from 'prop-types'
-import { config, useSpring, animated } from 'react-spring'
-import { useTheme } from '@nivo/core'
+import { useSpring, animated } from 'react-spring'
+import { useTheme, useMotionConfig } from '@nivo/core'
export const PartLabel = ({ part }) => {
const theme = useTheme()
+ const { animate, config: motionConfig } = useMotionConfig()
const animatedProps = useSpring({
transform: `translate(${part.x}, ${part.y})`,
color: part.labelColor,
- config: config.wobbly,
+ config: motionConfig,
+ immediate: !animate,
})
return (
diff --git a/website/src/components/controls/ControlsGroup.js b/website/src/components/controls/ControlsGroup.js
index 9f0c26d0a5..8b7e8a9bd2 100644
--- a/website/src/components/controls/ControlsGroup.js
+++ b/website/src/components/controls/ControlsGroup.js
@@ -25,6 +25,7 @@ import BoxAnchorControl from './BoxAnchorControl'
import MarginControl from './MarginControl'
import OpacityControl from './OpacityControl'
import LineWidthControl from './LineWidthControl'
+import MotionConfigControl from './MotionConfigControl'
import NumberArrayControl from './NumberArrayControl'
import AngleControl from './AngleControl'
import OrdinalColorsControl from './OrdinalColorsControl'
@@ -242,6 +243,19 @@ const ControlSwitcher = memo(
/>
)
+ case 'motionConfig':
+ return (
+
+ )
+
case 'opacity':
return (
({
+ value: presetId,
+ label: presetId,
+}))
+
+const defaultConfig = {
+ mass: 1,
+ tension: 170,
+ friction: 26,
+ clamp: false,
+ precision: 0.01,
+ velocity: 0,
+}
+
+const MotionConfigControl = memo(({ id, property, flavors, currentFlavor, value, onChange }) => {
+ const type = isString(value) ? 'preset' : 'custom'
+ const [preset, setPreset] = useState(type === 'preset' ? value : 'default')
+ const [customConfig, setCustomConfig] = useState(type === 'custom' ? value : defaultConfig)
+
+ const handleTypeChange = useCallback(
+ event => {
+ const newType = event.target.value
+ if (newType === 'preset') {
+ onChange(preset)
+ } else {
+ onChange(customConfig)
+ }
+ },
+ [onChange]
+ )
+
+ const handlePresetChange = useCallback(
+ option => {
+ setPreset(option.value)
+ onChange(option.value)
+ },
+ [onChange]
+ )
+
+ const handleMassChange = event => {
+ const mass = Number(event.target.value)
+ const newCustomConfig = {
+ ...customConfig,
+ mass,
+ }
+ setCustomConfig(newCustomConfig)
+ onChange(newCustomConfig)
+ }
+
+ const handleTensionChange = event => {
+ const tension = Number(event.target.value)
+ const newCustomConfig = {
+ ...customConfig,
+ tension,
+ }
+ setCustomConfig(newCustomConfig)
+ onChange(newCustomConfig)
+ }
+
+ const handleFrictionChange = event => {
+ const friction = Number(event.target.value)
+ const newCustomConfig = {
+ ...customConfig,
+ friction,
+ }
+ setCustomConfig(newCustomConfig)
+ onChange(newCustomConfig)
+ }
+
+ const handleClampChange = clamp => {
+ const newCustomConfig = {
+ ...customConfig,
+ clamp,
+ }
+ setCustomConfig(newCustomConfig)
+ onChange(newCustomConfig)
+ }
+
+ return (
+
+
+
+
+ {type === 'preset' && (
+
+ {property.help}
+
+ )
+})
+
+export default MotionConfigControl
diff --git a/website/src/components/controls/Radio.js b/website/src/components/controls/Radio.js
index e4ea383179..d240914e6d 100644
--- a/website/src/components/controls/Radio.js
+++ b/website/src/components/controls/Radio.js
@@ -63,7 +63,7 @@ const Radio = memo(({ options, value, onChange }) => {
)
})
-Radio.displayName = 'RadioControl'
+Radio.displayName = 'Radio'
Radio.propTypes = {
value: PropTypes.string.isRequired,
options: PropTypes.arrayOf(
diff --git a/website/src/lib/componentProperties.js b/website/src/lib/componentProperties.js
index 29e1c6e2bc..6db0680a02 100644
--- a/website/src/lib/componentProperties.js
+++ b/website/src/lib/componentProperties.js
@@ -89,6 +89,17 @@ export const motionProperties = (flavors, defaults, type = 'react-motion') => {
max: 40,
},
})
+ } else if (type === 'react-spring') {
+ props.push({
+ key: 'motionConfig',
+ flavors,
+ help: 'Motion config for react-spring, either a preset or a custom configuration.',
+ type: 'string | object',
+ required: false,
+ defaultValue: defaults.motionConfig,
+ controlType: 'motionConfig',
+ group: 'Motion',
+ })
}
return props