-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #58 from quarkly/comp-cardflip
feat: added CardFlip component
- Loading branch information
Showing
5 changed files
with
279 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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). |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters