Skip to content

Commit

Permalink
Create useFlip hook #183
Browse files Browse the repository at this point in the history
  • Loading branch information
leroykorterink committed Oct 20, 2023
1 parent 2f34106 commit bae0edc
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/react-animation/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './useExposeAnimation/useExposeAnimation.js';
export * from './useExposedAnimation/useExposedAnimation.js';
export * from './useExposedAnimations/useExposedAnimations.js';
export * from './useScrollAnimation/useScrollAnimation.js';
export * from './useFlip/useFlip.js';
46 changes: 46 additions & 0 deletions packages/react-animation/src/useFlip/useFlip.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Meta, Canvas } from '@storybook/blocks';
import * as stories from './useFlip.stories';

<Meta title="components/useFlip" of={stories} />

# useFlip

Use to flip a components state from one value to another.

```tsx
function MyComponent(): ReactElement {
const [isFlipped, toggle] = useToggle(false);

const divRef = useRef<HTMLDivElement>(null);
useFlip(divRef, flipOptions);

useEventListener(globalThis.document, 'click', () => {
toggle();
});

return (
<div
ref={divRef}
style={
isFlipped
? {
...styles,
position: 'absolute',
insetBlock: 0,
insetInlineStart: '50%',
insetInlineEnd: 0,
}
: {
...styles,
inlineSize: 150,
blockSize: 150,
}
}
/>
);
}
```

### Demo

<Canvas of={stories.Default} />
63 changes: 63 additions & 0 deletions packages/react-animation/src/useFlip/useFlip.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/* eslint-disable react/jsx-no-literals */
import { useEventListener, useToggle } from '@mediamonks/react-hooks';
import type { Meta, StoryObj } from '@storybook/react';
import { useRef, type CSSProperties, type ReactElement } from 'react';
import { useFlip } from './useFlip.js';

const meta = {
title: 'hooks/useFlip',
} as Meta;

export default meta;

type Story = StoryObj<typeof meta>;

const flipOptions = {
ease: 'power2.inOut',
} satisfies Flip.FromToVars;

const styles = {
backgroundColor: 'royalblue',
} satisfies CSSProperties;

export const Default: Story = {
render(): ReactElement {
const [isFlipped, toggle] = useToggle(false);
const div1Ref = useRef<HTMLDivElement>(null);
const div2Ref = useRef<HTMLDivElement>(null);

useFlip(div1Ref, flipOptions);
useFlip(div2Ref, flipOptions);

useEventListener(globalThis.document, 'click', () => {
toggle();
});

return (
<>
<p>
Click to rerender, the box will fill the right side of the screen using position absolute.
</p>
<div
ref={div1Ref}
style={
isFlipped
? {
...styles,
position: 'absolute',
insetBlock: 0,
insetInlineStart: '50%',
insetInlineEnd: 0,
}
: {
...styles,
inlineSize: 150,
blockSize: 150,
}
}
/>
<p ref={div2Ref}>The element renders inline</p>
</>
);
},
};
26 changes: 26 additions & 0 deletions packages/react-animation/src/useFlip/useFlip.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { unref, type Unreffable } from '@mediamonks/react-hooks';
import gsap from 'gsap';
import Flip from 'gsap/Flip';
import { useEffect, useRef, type MutableRefObject } from 'react';

gsap.registerPlugin(Flip);

export function useFlip(
ref: Unreffable<HTMLElement | null>,
flipStateVariables: Flip.FromToVars = {},
): MutableRefObject<Flip.FlipState | undefined> {
const flipStateRef = useRef<Flip.FlipState>();

// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (globalThis.window !== undefined) {
flipStateRef.current = Flip.getState(unref(ref));
}

useEffect(() => {
if (flipStateRef.current) {
Flip.from(flipStateRef.current, flipStateVariables);
}
});

return flipStateRef;
}

0 comments on commit bae0edc

Please sign in to comment.