Skip to content

Commit

Permalink
docs: add banner mouse effect animation (ant-design#44711)
Browse files Browse the repository at this point in the history
* docs: add banner mouse effect animation

* refactor to useRef

* refactor to react way

* refactor to hooks

* type: add type

* fix: fix error

* fix: fix error

* fix: update RTL

---------

Co-authored-by: 栗嘉男 <574980606@qq.com>
  • Loading branch information
afc163 and li-jia-nan authored Sep 10, 2023
1 parent bdf8c43 commit 4489eec
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 25 deletions.
28 changes: 17 additions & 11 deletions .dumi/pages/index/components/Group.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,42 @@
import * as React from 'react';
import { useContext } from 'react';
import { useTheme } from 'antd-style';
import { Typography } from 'antd';
import { useTheme } from 'antd-style';

import SiteContext from '../../../theme/slots/SiteContext';

export interface GroupMaskProps {
style?: React.CSSProperties;
children?: React.ReactNode;
disabled?: boolean;
onMouseMove?: React.MouseEventHandler<HTMLDivElement>;
onMouseEnter?: React.MouseEventHandler<HTMLDivElement>;
onMouseLeave?: React.MouseEventHandler<HTMLDivElement>;
}

export function GroupMask({ children, style, disabled }: GroupMaskProps) {
export const GroupMask: React.FC<GroupMaskProps> = (props) => {
const { children, style, disabled, onMouseMove, onMouseEnter, onMouseLeave } = props;
const additionalStyle: React.CSSProperties = disabled
? {}
: {
position: 'relative',
background: `rgba(255,255,255,0.1)`,
background: `rgba(255, 255, 255, 0.1)`,
backdropFilter: `blur(25px)`,
zIndex: 1,
};

return (
<div
className="site-mask"
style={{
position: 'relative',
...style,
...additionalStyle,
}}
style={{ position: 'relative', ...style, ...additionalStyle }}
onMouseMove={onMouseMove}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
{children}
</div>
);
}
};

export interface GroupProps {
id?: string;
Expand All @@ -48,7 +52,7 @@ export interface GroupProps {
decoration?: React.ReactNode;
}

export default function Group(props: GroupProps) {
const Group: React.FC<GroupProps> = (props) => {
const { id, title, titleColor, description, children, decoration, background, collapse } = props;
const token = useTheme();
const { isMobile } = useContext(SiteContext);
Expand Down Expand Up @@ -114,4 +118,6 @@ export default function Group(props: GroupProps) {
</GroupMask>
</div>
);
}
};

export default Group;
11 changes: 7 additions & 4 deletions .dumi/pages/index/components/PreviewBanner/ComponentsBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,16 +107,17 @@ const useStyle = createStyles(({ token, css }) => {

export interface ComponentsBlockProps {
className?: string;
style?: React.CSSProperties;
}

export default function ComponentsBlock(props: ComponentsBlockProps) {
const { className } = props;
const ComponentsBlock: React.FC<ComponentsBlockProps> = (props) => {
const { className, style } = props;

const [locale] = useLocale(locales);
const { styles } = useStyle();

return (
<div className={classNames(className, styles.holder)}>
<div className={classNames(className, styles.holder)} style={style}>
<ModalPanel title="Ant Design 5.0" width="100%">
{locale.text}
</ModalPanel>
Expand Down Expand Up @@ -253,4 +254,6 @@ export default function ComponentsBlock(props: ComponentsBlockProps) {
<Alert message="Ant Design love you!" type="success" />
</div>
);
}
};

export default ComponentsBlock;
15 changes: 10 additions & 5 deletions .dumi/pages/index/components/PreviewBanner/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import SiteContext from '../../../../theme/slots/SiteContext';
import * as utils from '../../../../theme/utils';
import { GroupMask } from '../Group';
import ComponentsBlock from './ComponentsBlock';
import useMouseTransform from './useMouseTransform';

const locales = {
cn: {
Expand Down Expand Up @@ -81,11 +82,12 @@ const useStyle = () => {
};
})();
};

export interface PreviewBannerProps {
children?: React.ReactNode;
}

export default function PreviewBanner(props: PreviewBannerProps) {
const PreviewBanner: React.FC<PreviewBannerProps> = (props) => {
const { children } = props;

const [locale] = useLocale(locales);
Expand All @@ -95,8 +97,10 @@ export default function PreviewBanner(props: PreviewBannerProps) {
const { pathname, search } = useLocation();
const isZhCN = utils.isZhCN(pathname);

const [componentsBlockStyle, mouseEvents] = useMouseTransform();

return (
<GroupMask>
<GroupMask {...mouseEvents}>
{/* Image Left Top */}
<img
style={{ position: 'absolute', left: isMobile ? -120 : 0, top: 0, width: 240 }}
Expand All @@ -112,7 +116,7 @@ export default function PreviewBanner(props: PreviewBannerProps) {

<div className={styles.holder}>
{/* Mobile not show the component preview */}
{!isMobile && <ComponentsBlock className={styles.block} />}
{!isMobile && <ComponentsBlock className={styles.block} style={componentsBlockStyle} />}

<Typography className={styles.typography}>
<h1>Ant Design 5.0</h1>
Expand All @@ -129,9 +133,10 @@ export default function PreviewBanner(props: PreviewBannerProps) {
<Button size="large">{locale.designLanguage}</Button>
</Link>
</Space>

<div className={styles.child}>{children}</div>
</div>
</GroupMask>
);
}
};

export default PreviewBanner;
73 changes: 73 additions & 0 deletions .dumi/pages/index/components/PreviewBanner/useMouseTransform.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React, { startTransition } from 'react';
import { ConfigProvider } from 'antd';

const getTransformRotateStyle = (
event: React.MouseEvent<HTMLDivElement, MouseEvent>,
currentTarget: EventTarget & HTMLDivElement,
multiple: number,
isRTL: boolean,
): string => {
const box = currentTarget?.getBoundingClientRect();
const calcX = -(event.clientY - box.y - box.height / 2) / multiple;
const calcY = (event.clientX - box.x - box.width / 2) / multiple;
return isRTL
? `rotate3d(${24 + calcX}, ${83 + calcY}, -45, 57deg)`
: `rotate3d(${24 + calcX}, ${-83 + calcY}, 45, 57deg)`;
};

const useMouseTransform = ({ transitionDuration = 500, multiple = 36 } = {}) => {
const [componentsBlockStyle, setComponentsBlockStyle] = React.useState<React.CSSProperties>({});

const { direction } = React.useContext(ConfigProvider.ConfigContext);

const isRTL = direction === 'rtl';

const onMouseMove: React.MouseEventHandler<HTMLDivElement> = (event) => {
const { currentTarget } = event;
startTransition(() => {
setComponentsBlockStyle((style) => ({
...style,
transform: getTransformRotateStyle(event, currentTarget, multiple, isRTL),
}));
});
};

const onMouseEnter: React.MouseEventHandler<HTMLDivElement> = () => {
startTransition(() => {
setComponentsBlockStyle((style) => ({
...style,
transition: `transform ${transitionDuration / 1000}s`,
}));
});

setTimeout(() => {
startTransition(() => {
setComponentsBlockStyle((style) => ({
...style,
transition: '',
}));
});
}, transitionDuration);
};

const onMouseLeave: React.MouseEventHandler<HTMLDivElement> = () => {
startTransition(() => {
setComponentsBlockStyle((style) => ({
...style,
transition: `transform ${transitionDuration / 1000}s`,
transform: '',
}));
});
};

return [
componentsBlockStyle,
{
onMouseMove,
onMouseEnter,
onMouseLeave,
},
] as const;
};

export default useMouseTransform;
8 changes: 3 additions & 5 deletions components/radio/group.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as React from 'react';
import classNames from 'classnames';
import useMergedState from 'rc-util/lib/hooks/useMergedState';
import pickAttrs from 'rc-util/lib/pickAttrs';
import * as React from 'react';

import { ConfigContext } from '../config-provider';
import useSize from '../config-provider/hooks/useSize';
import { RadioGroupContextProvider } from './context';
Expand Down Expand Up @@ -100,10 +101,7 @@ const RadioGroup = React.forwardRef<HTMLDivElement, RadioGroupProps>((props, ref
);
return wrapSSR(
<div
{...pickAttrs(props, {
aria: true,
data: true,
})}
{...pickAttrs(props, { aria: true, data: true })}
className={classString}
style={style}
onMouseEnter={onMouseEnter}
Expand Down

0 comments on commit 4489eec

Please sign in to comment.