pl-fe: @react-spring/web migrations, adapted from mastodon
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@ -1,13 +1,13 @@
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { spring } from 'react-motion';
|
||||
|
||||
import Button from 'pl-fe/components/ui/button';
|
||||
import HStack from 'pl-fe/components/ui/hstack';
|
||||
import Stack from 'pl-fe/components/ui/stack';
|
||||
import OptionalMotion from 'pl-fe/features/ui/util/optional-motion';
|
||||
import { useCompose } from 'pl-fe/hooks/use-compose';
|
||||
|
||||
import Warning from './warning';
|
||||
|
||||
interface IClearLinkSuggestion {
|
||||
composeId: string;
|
||||
handleAccept: (key: string) => void;
|
||||
@ -25,9 +25,10 @@ const ClearLinkSuggestion = ({
|
||||
if (!suggestion) return null;
|
||||
|
||||
return (
|
||||
<OptionalMotion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>
|
||||
{({ opacity, scaleX, scaleY }) => (
|
||||
<Stack space={1} className='rounded border border-solid border-gray-400 bg-transparent px-2.5 py-2 text-xs text-gray-900 dark:border-gray-800 dark:text-white' style={{ opacity: opacity, transform: `scale(${scaleX}, ${scaleY})` }}>
|
||||
<Warning
|
||||
animated
|
||||
message={
|
||||
<Stack space={1}>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='compose.clear_link_suggestion.body'
|
||||
@ -52,8 +53,8 @@ const ClearLinkSuggestion = ({
|
||||
</Button>
|
||||
</HStack>
|
||||
</Stack>
|
||||
)}
|
||||
</OptionalMotion>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
import React from 'react';
|
||||
import { defineMessages, FormattedMessage } from 'react-intl';
|
||||
import { spring } from 'react-motion';
|
||||
|
||||
import { ignoreHashtagCasingSuggestion } from 'pl-fe/actions/compose';
|
||||
import { changeSetting } from 'pl-fe/actions/settings';
|
||||
import Button from 'pl-fe/components/ui/button';
|
||||
import HStack from 'pl-fe/components/ui/hstack';
|
||||
import Stack from 'pl-fe/components/ui/stack';
|
||||
import OptionalMotion from 'pl-fe/features/ui/util/optional-motion';
|
||||
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||
import { useCompose } from 'pl-fe/hooks/use-compose';
|
||||
import toast from 'pl-fe/toast';
|
||||
|
||||
import Warning from './warning';
|
||||
|
||||
const messages = defineMessages({
|
||||
hashtagCasingSuggestionsDisabled: { id: 'compose.hashtag_casing_suggestion.disabled', defaultMessage: 'You will no longer receive suggestions about hashtag capitalization.' },
|
||||
});
|
||||
@ -41,9 +41,10 @@ const HashtagCasingSuggestion = ({
|
||||
if (!suggestion) return null;
|
||||
|
||||
return (
|
||||
<OptionalMotion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>
|
||||
{({ opacity, scaleX, scaleY }) => (
|
||||
<Stack space={1} className='rounded border border-solid border-gray-400 bg-transparent px-2.5 py-2 text-xs text-gray-900 dark:border-gray-800 dark:text-white' style={{ opacity: opacity, transform: `scale(${scaleX}, ${scaleY})` }}>
|
||||
<Warning
|
||||
animated
|
||||
message={
|
||||
<Stack space={1}>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id='compose.hashtag_casing_suggestion.body'
|
||||
@ -68,8 +69,8 @@ const HashtagCasingSuggestion = ({
|
||||
</Button>
|
||||
</HStack>
|
||||
</Stack>
|
||||
)}
|
||||
</OptionalMotion>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { animated, useSpring } from '@react-spring/web';
|
||||
import React from 'react';
|
||||
import { spring } from 'react-motion';
|
||||
|
||||
import Motion from '../../ui/util/optional-motion';
|
||||
import { useSettings } from 'pl-fe/stores/settings';
|
||||
|
||||
interface IWarning {
|
||||
message: React.ReactNode;
|
||||
@ -9,17 +9,29 @@ interface IWarning {
|
||||
}
|
||||
|
||||
/** Warning message displayed in ComposeForm. */
|
||||
const Warning: React.FC<IWarning> = ({ message, animated }) => {
|
||||
const Warning: React.FC<IWarning> = ({ message, animated: animate }) => {
|
||||
const { reduceMotion } = useSettings();
|
||||
|
||||
const styles = useSpring({
|
||||
from: {
|
||||
opacity: 0,
|
||||
transform: 'scale(0.85, 0.75)',
|
||||
},
|
||||
to: {
|
||||
opacity: 1,
|
||||
transform: 'scale(1, 1)',
|
||||
},
|
||||
immediate: !animate || reduceMotion,
|
||||
});
|
||||
|
||||
const className = 'rounded border border-solid border-gray-400 bg-transparent px-2.5 py-2 text-xs text-gray-900 dark:border-gray-800 dark:text-white';
|
||||
|
||||
if (animated) return (
|
||||
<Motion defaultStyle={{ opacity: 0, scaleX: 0.85, scaleY: 0.75 }} style={{ opacity: spring(1, { damping: 35, stiffness: 400 }), scaleX: spring(1, { damping: 35, stiffness: 400 }), scaleY: spring(1, { damping: 35, stiffness: 400 }) }}>
|
||||
{({ opacity, scaleX, scaleY }) => (
|
||||
<div className={className} style={{ opacity: opacity, transform: `scale(${scaleX}, ${scaleY})` }}>
|
||||
{message}
|
||||
</div>
|
||||
)}
|
||||
</Motion>
|
||||
if (!message) return null;
|
||||
|
||||
if (animate) return (
|
||||
<animated.div className={className} style={styles}>
|
||||
{message}
|
||||
</animated.div>
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Motion, MotionProps } from 'react-motion';
|
||||
|
||||
import { useSettings } from 'pl-fe/stores/settings';
|
||||
|
||||
import ReducedMotion from './reduced-motion';
|
||||
|
||||
const OptionalMotion = (props: MotionProps) => {
|
||||
const { reduceMotion } = useSettings();
|
||||
|
||||
return (
|
||||
reduceMotion ? <ReducedMotion {...props} /> : <Motion {...props} />
|
||||
);
|
||||
};
|
||||
|
||||
export default OptionalMotion;
|
||||
@ -1,31 +0,0 @@
|
||||
// Like react-motion's Motion, but reduces all animations to cross-fades
|
||||
// for the benefit of users with motion sickness.
|
||||
import React from 'react';
|
||||
import { Motion, MotionProps } from 'react-motion';
|
||||
|
||||
const stylesToKeep = ['opacity', 'backgroundOpacity'];
|
||||
|
||||
const extractValue = (value: any) => {
|
||||
// This is either an object with a "val" property or it's a number
|
||||
return (typeof value === 'object' && value && 'val' in value) ? value.val : value;
|
||||
};
|
||||
|
||||
const ReducedMotion: React.FC<MotionProps> = ({ style = {}, defaultStyle = {}, children }) => {
|
||||
|
||||
Object.keys(style).forEach(key => {
|
||||
if (stylesToKeep.includes(key)) {
|
||||
return;
|
||||
}
|
||||
// If it's setting an x or height or scale or some other value, we need
|
||||
// to preserve the end-state value without actually animating it
|
||||
style[key] = defaultStyle[key] = extractValue(style[key]);
|
||||
});
|
||||
|
||||
return (
|
||||
<Motion style={style} defaultStyle={defaultStyle}>
|
||||
{children}
|
||||
</Motion>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReducedMotion;
|
||||
Reference in New Issue
Block a user