Skip to content

Commit

Permalink
Merge pull request #58 from quarkly/comp-cardflip
Browse files Browse the repository at this point in the history
feat: added CardFlip component
  • Loading branch information
andreycrane authored Apr 20, 2021
2 parents 4ddfa5e + e8cf311 commit 20db5d8
Show file tree
Hide file tree
Showing 5 changed files with 279 additions and 1 deletion.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@
"BackToTop": "BackToTop",
"YoomoneyDonateForm": "YoomoneyDonateForm",
"Carousel": "Carousel",
"Animation": "Animation"
"Animation": "Animation",
"CardFlip": "CardFlip"
}
},
"quarklyInfoDeleted": {
Expand Down
50 changes: 50 additions & 0 deletions preview/docs/CardFlip.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
## 📖 Detailed overview

Компонент представляет из себя карточку с картинкой, которую можно развернуть при клике или наведении на нее. На обратной стороне карточки, вы можете разместить любые другие компоненты.

## 🎬 Live Demo

[Live demo link](https://quarkly-ui-components.netlify.app/cardflip/)

## ⚙️ Usage

Добавьте компонент на страницу и посмотрите как он работает в режиме превью.

### Поменять изображение карточки

Чтобы поменять изображение карточки, выберите встроенный компонент `Image` и измените ссылку в параметре `Src`.

### Соотношение сторон изображения

При выборе `auto` в свойстве `Aspect Ratio`, размер изображения будет равен размеру (высоте и ширине) компонента.

## 🧩 Components and Props

| Props Name | Type | Description | Default | Example |
| --------------- | :------: | :----------------------------------------------------------------: | :-------: | :-------: |
| Flip Duration | `number` | Продолжительность анимации разворота | `1000` | `2000` |
| Timing Function | `string` | Cкорость течения анимации | `-` | `ease-in` |
| Flip Trigger | `enum` | Действие, вызывающее анимацию [Click, Hover] | `Click` | `Hover` |
| Flip Direction | `enum` | Направление разворота [toRight, toLeft, ToUp, toDown] | `toRight` | `ToUp` |
| Aspect Ratio | `enum` | Размер изображения в пропорциях [auto, 16:9, 4:3, 1:1, 3:4, 9:16 ] | `auto` | `1:1` |

## 🗓 Changelog

- 16/03/2021 (v1.0)
- Первая версия

## 📮 Feedback

If you encountered a bug, please contact us so we can fix it promptly. We’re rapidly developing, so don’t hesitate to send us your feedback and request new features you can’t stand missing. Feel free to share what you’re working on - we **love** to see what you’re building with Quarkly!

[Help with components](https://feedback.quarkly.io/communities/1-quarkly-forum/categories/7-components/topics)

[We're on Discord](https://discord.gg/f9KhSMGX)

[Our Twitter](https://twitter.com/quarklyapp)

[[email protected]](mailto:[email protected])

## 📝 License

Licensed under the [MIT License](./LICENSE).
Binary file added preview/static/CardFlip.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
226 changes: 226 additions & 0 deletions src/CardFlip.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
import React, { useMemo, useCallback, useState, useEffect } from 'react';
import { useOverrides } from '@quarkly/components';
import { Box, Image } from '@quarkly/widgets';

const overrides = {
'Flip Card Content': {
kind: 'Box',
props: {
width: '100%',
'min-width': '0',
'min-height': '0',
'transform-style': 'preserve-3d',
position: 'relative',
cursor: 'pointer',
},
},
'Flip Card Image': {
kind: 'Image',
props: {
width: '100%',
height: '100%',
src:
'https://uploads.quarkly.io/molecules/default-picture-1200.png',
'object-position': '50% 50%',
'object-fit': 'cover',
},
},
'Flip Card Item': {
kind: 'Box',
props: {
top: '0',
left: '0',
width: '100%',
height: '100%',
'backface-visibility': 'hidden',
position: 'absolute',
},
},
'Flip Card Item Face': {
kind: 'Box',
},
'Flip Card Item Back': {
kind: 'Box',
props: {
padding: '24px 16px',
background: '--color-lightD2',
'box-sizing': 'border-box',
},
},
};

const flipStyles = {
toRight: {
transform: 'rotateY(180deg)',
},
toLeft: {
transform: 'rotateY(-180deg)',
},
toUp: {
transform: 'rotateX(180deg)',
},
toDown: {
transform: 'rotateX(-180deg)',
},
};

const cardHeights = {
auto: 'auto',
'16:9': '56.25%',
'4:3': '75%',
'1:1': '100%',
'3:4': '133.33%',
'9:16': '177.78%',
};

const FlipCard = ({
flipTriggerProp,
flipDirectionProp,
flipDurationProp,
timingFunctionProp,
aspectRatioProp,
isFlippedProp,
...props
}) => {
const { override, children, rest } = useOverrides(props, overrides);

const [isFlipped, setFlipped] = useState(isFlippedProp);

const flipTrigger = flipTriggerProp === 'Click';

const flipDuration = useMemo(() => flipDurationProp.replace(/\s+/g, ''), [
flipDurationProp,
]);

const onClickFlip = useCallback(() => {
if (flipTrigger) setFlipped((prevFlipped) => !prevFlipped);
}, [flipTrigger]);

const onHoverFlip = useCallback(() => {
if (!flipTrigger) setFlipped((prevFlipped) => !prevFlipped);
}, [flipTrigger]);

useEffect(() => {
setFlipped(isFlippedProp);
}, [isFlippedProp]);

return (
<Box
height={aspectRatioProp === 'auto' ? '500px' : 'auto'}
onMouseEnter={onHoverFlip}
onMouseLeave={onHoverFlip}
onClick={onClickFlip}
{...rest}
>
<Box
transition={`transform ${flipDuration}ms ${timingFunctionProp}`}
{...override('Flip Card Content')}
{...(isFlipped && flipStyles[flipDirectionProp])}
padding-top={
aspectRatioProp !== 'auto'
? cardHeights[aspectRatioProp]
: undefined
}
height={aspectRatioProp !== 'auto' ? '0' : '100%'}
>
<Box {...override(`Flip Card Item`, `Flip Card Item Face`)}>
<Image {...override('Flip Card Image')} />
</Box>
<Box
{...override(`Flip Card Item`, `Flip Card Item Back`)}
{...flipStyles[flipDirectionProp]}
>
{children}
</Box>
</Box>
</Box>
);
};

const propInfo = {
flipTriggerProp: {
title: 'Flip Trigger',
description: {
en: 'Способ активации анимации',
},
control: 'radio-group',
variants: ['Click', 'Hover'],
category: 'Main',
weight: 0.5,
},
flipDirectionProp: {
title: 'Flip Direction',
description: {
en: 'Напрвление поворота',
},
control: 'select',
variants: ['toRight', 'toLeft', 'toUp', 'toDown'],
category: 'Main',
weight: 0.5,
},
aspectRatioProp: {
title: 'Aspect Ratio',
description: {
en: 'Формат разрешения',
},
control: 'select',
variants: ['auto', '16:9', '4:3', '1:1', '3:4', '9:16'],
category: 'Main',
weight: 0.5,
},
flipDurationProp: {
title: 'Flip Duration',
description: {
en: 'Продолжительность анимации',
},
control: 'input',
category: 'Animation params',
weight: 0.5,
},
timingFunctionProp: {
title: 'Timing Function',
description: {
en: 'Скорость течения анимации',
},
control: 'input',
variants: [
'ease',
'ease-in',
'ease-out',
'ease-in-out',
'linear',
'step-start',
'step-end',
],
category: 'Animation params',
weight: 0.5,
},
isFlippedProp: {
title: 'Перевернуть карточку',
description: {
en: 'Перевернуть карточку для теста',
},
control: 'checkbox',
category: 'Test',
weight: 1,
},
};

const defaultProps = {
flipTriggerProp: 'Click',
flipDirectionProp: 'toRight',
aspectRatioProp: 'auto',
flipDurationProp: '1000',
timingFunctionProp: 'cubic-bezier(.50,-0.35,.50,1.65)',
isFlippedProp: false,

width: '400px',
position: 'relative',
perspective: '600px',
};

export default Object.assign(FlipCard, {
overrides,
propInfo,
defaultProps,
});
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ export { default as BackToTop } from './BackToTop';
export { default as YoomoneyDonateForm } from './YoomoneyDonateForm';
export { default as Carousel } from './Carousel';
export { default as Animation } from './Animation';
export { default as CardFlip } from './CardFlip';

0 comments on commit 20db5d8

Please sign in to comment.