From 08202d7812a3d16d6478394b344e801c33b5ecd2 Mon Sep 17 00:00:00 2001 From: Ugo Stephant Date: Wed, 26 Oct 2022 15:57:36 +0200 Subject: [PATCH] feat: add transitions --- .storybook/main.js | 1 + packages/react/lib/ColorField/index.d.ts | 1 + packages/react/lib/ColorField/index.js | 4 +- .../react/lib/ColorField/index.stories.js | 5 +++ packages/react/lib/DateField/index.d.ts | 1 + packages/react/lib/DateField/index.js | 4 +- packages/react/lib/DateField/index.stories.js | 5 +++ packages/react/lib/Dropdown/index.stories.js | 11 +++++ packages/react/lib/DropdownMenu/index.d.ts | 1 + packages/react/lib/DropdownMenu/index.js | 17 ++++++-- packages/react/lib/SelectField/index.d.ts | 1 + packages/react/lib/SelectField/index.js | 3 ++ .../react/lib/SelectField/index.stories.js | 6 +++ packages/react/lib/Tooltip/index.d.ts | 2 +- packages/theme/lib/index.sass | 1 + packages/theme/lib/transitions.sass | 41 +++++++++++++++++++ packages/transitions/lib/index.js | 9 ++-- 17 files changed, 102 insertions(+), 11 deletions(-) create mode 100644 packages/theme/lib/transitions.sass diff --git a/.storybook/main.js b/.storybook/main.js index c41b9cbd2..d1638613b 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -18,6 +18,7 @@ module.exports = { 'react-native': 'react-native-web', '@junipero/core': path.resolve('./packages/core/lib'), '@junipero/hooks': path.resolve('./packages/hooks/lib'), + '@junipero/transitions': path.resolve('./packages/transitions/lib'), }; config.module.rules.push({ diff --git a/packages/react/lib/ColorField/index.d.ts b/packages/react/lib/ColorField/index.d.ts index eac47b398..f387a9aa2 100644 --- a/packages/react/lib/ColorField/index.d.ts +++ b/packages/react/lib/ColorField/index.d.ts @@ -22,6 +22,7 @@ export declare type ColorFieldRef = { }; declare interface ColorFieldProps extends React.ComponentPropsWithRef { + animateMenu: (menu: JSX.Element, opts: { opened: Boolean }) => JSX.Element; className?: String; dismissOptions?: dismissProps; globalEventsTarget: EventTarget; diff --git a/packages/react/lib/ColorField/index.js b/packages/react/lib/ColorField/index.js index 75dfbbe05..9bfe4ecfb 100644 --- a/packages/react/lib/ColorField/index.js +++ b/packages/react/lib/ColorField/index.js @@ -24,6 +24,7 @@ import TextField from '../TextField'; import FieldControl from '../FieldControl'; const ColorField = forwardRef(({ + animateMenu, className, dismissOptions, globalEventsTarget, @@ -357,7 +358,7 @@ const ColorField = forwardRef(({ /> - +
( export const alwaysOpened = () => ( ); + +export const animated = () => ( + +); diff --git a/packages/react/lib/DateField/index.d.ts b/packages/react/lib/DateField/index.d.ts index b1d629ae6..d2284a57f 100644 --- a/packages/react/lib/DateField/index.d.ts +++ b/packages/react/lib/DateField/index.d.ts @@ -16,6 +16,7 @@ export declare type DateFieldRef = { }; declare interface DateFieldProps extends React.ComponentPropsWithRef { + animateMenu: (menu: JSX.Element, opts: { opened: Boolean }) => JSX.Element; className?: String; min?: Date; max?: Date; diff --git a/packages/react/lib/DateField/index.js b/packages/react/lib/DateField/index.js index 1fbce7151..9d65cca7b 100644 --- a/packages/react/lib/DateField/index.js +++ b/packages/react/lib/DateField/index.js @@ -23,6 +23,7 @@ import DropdownToggle from '../DropdownToggle'; import DropdownMenu from '../DropdownMenu'; const DateField = forwardRef(({ + animateMenu, className, max, min, @@ -368,7 +369,7 @@ const DateField = forwardRef(({
- +
@@ -429,6 +430,7 @@ const DateField = forwardRef(({ DateField.displayName = 'DateField'; DateField.propTypes = { + animateMenu: PropTypes.func, autoFocus: PropTypes.bool, clearable: PropTypes.bool, disabled: PropTypes.bool, diff --git a/packages/react/lib/DateField/index.stories.js b/packages/react/lib/DateField/index.stories.js index 328f52cf4..b9a5a1bed 100644 --- a/packages/react/lib/DateField/index.stories.js +++ b/packages/react/lib/DateField/index.stories.js @@ -1,4 +1,5 @@ import { action } from '@storybook/addon-actions'; +import { slideInDownMenu } from '@junipero/transitions'; import FieldControl from '../FieldControl'; import Label from '../Label'; @@ -55,3 +56,7 @@ export const alwaysOpened = () => ( onChange={action('change')} /> ); + +export const animated = () => ( + +); diff --git a/packages/react/lib/Dropdown/index.stories.js b/packages/react/lib/Dropdown/index.stories.js index f9b18bafc..93a3a8d0f 100644 --- a/packages/react/lib/Dropdown/index.stories.js +++ b/packages/react/lib/Dropdown/index.stories.js @@ -1,3 +1,5 @@ +import { slideInDownMenu } from '@junipero/transitions'; + import DropdownToggle from '../DropdownToggle'; import DropdownMenu from '../DropdownMenu'; import DropdownGroup from '../DropdownGroup'; @@ -38,3 +40,12 @@ export const withGroups = () => ( ); + +export const animated = () => ( + + Open me + + Item 1 + + +); diff --git a/packages/react/lib/DropdownMenu/index.d.ts b/packages/react/lib/DropdownMenu/index.d.ts index 994df72c4..5d27b6409 100644 --- a/packages/react/lib/DropdownMenu/index.d.ts +++ b/packages/react/lib/DropdownMenu/index.d.ts @@ -6,6 +6,7 @@ export declare type DropdownMenuRef = { }; declare interface DropdownMenuProps extends React.ComponentPropsWithRef { + animate: (menu: JSX.Element, opts: { opened: Boolean }) => JSX.Element; children?: React.ReactNode; className?: String; ref?: MutableRefObject; diff --git a/packages/react/lib/DropdownMenu/index.js b/packages/react/lib/DropdownMenu/index.js index 402b56df4..d906cbeae 100644 --- a/packages/react/lib/DropdownMenu/index.js +++ b/packages/react/lib/DropdownMenu/index.js @@ -1,10 +1,12 @@ import { forwardRef, useRef, useImperativeHandle } from 'react'; import { classNames, ensureNode } from '@junipero/core'; import { createPortal } from 'react-dom'; +import PropTypes from 'prop-types'; import { useDropdown } from '../hooks'; const DropdownMenu = forwardRef(({ + animate, children, className, ...rest @@ -25,10 +27,16 @@ const DropdownMenu = forwardRef(({ isJunipero: true, })); - if (!opened) { + if (!opened && !animate) { return null; } + const menu = ( +
    + { children } +
+ ); + const content = (
-
    - { children } -
+ { animate ? animate(menu, { opened }) : menu }
); @@ -52,5 +58,8 @@ const DropdownMenu = forwardRef(({ }); DropdownMenu.displayName = 'DropdownMenu'; +DropdownMenu.propTypes = { + animate: PropTypes.func, +}; export default DropdownMenu; diff --git a/packages/react/lib/SelectField/index.d.ts b/packages/react/lib/SelectField/index.d.ts index bc5a8f590..e8a72b620 100644 --- a/packages/react/lib/SelectField/index.d.ts +++ b/packages/react/lib/SelectField/index.d.ts @@ -15,6 +15,7 @@ export declare type SelectFieldRef = { }; declare interface SelectFieldProps extends React.ComponentPropsWithRef { + animateMenu: (menu: JSX.Element, opts: { opened: Boolean }) => JSX.Element; className?: String; options?: Array; placeholder?: String; diff --git a/packages/react/lib/SelectField/index.js b/packages/react/lib/SelectField/index.js index 94fed6401..08f82b1fb 100644 --- a/packages/react/lib/SelectField/index.js +++ b/packages/react/lib/SelectField/index.js @@ -28,6 +28,7 @@ import Tag from '../Tag'; import Spinner from '../Spinner'; const SelectField = forwardRef(({ + animateMenu, className, options, placeholder, @@ -436,6 +437,7 @@ const SelectField = forwardRef(({
@@ -452,6 +454,7 @@ const SelectField = forwardRef(({ SelectField.displayName = 'SelectField'; SelectField.propTypes = { + animateMenu: PropTypes.func, allowArbitraryItems: PropTypes.bool, autoFocus: PropTypes.bool, clearable: PropTypes.bool, diff --git a/packages/react/lib/SelectField/index.stories.js b/packages/react/lib/SelectField/index.stories.js index a354d1370..e503e72ea 100644 --- a/packages/react/lib/SelectField/index.stories.js +++ b/packages/react/lib/SelectField/index.stories.js @@ -1,3 +1,5 @@ +import { slideInDownMenu } from '@junipero/transitions'; + import FieldControl from '../FieldControl'; import Label from '../Label'; import Abstract from '../Abstract'; @@ -88,3 +90,7 @@ export const withArbitraryValues = () => ( multiple={true} /> ); + +export const animated = () => ( + +); diff --git a/packages/react/lib/Tooltip/index.d.ts b/packages/react/lib/Tooltip/index.d.ts index 4a5021eda..e34d76116 100644 --- a/packages/react/lib/Tooltip/index.d.ts +++ b/packages/react/lib/Tooltip/index.d.ts @@ -22,7 +22,7 @@ export declare type TooltipRef = { declare interface TooltipProps extends React.ComponentPropsWithRef { animate?: ( tooltipInner: React.ReactNode, - options: { opnend?: Boolean } + options: { opened?: Boolean } ) => void; apparition?: String; children?: React.ReactNode; diff --git a/packages/theme/lib/index.sass b/packages/theme/lib/index.sass index 4cc1022a9..b9389f44f 100644 --- a/packages/theme/lib/index.sass +++ b/packages/theme/lib/index.sass @@ -1,6 +1,7 @@ // Core @use "./reset" @use "./icons" +@use "./transitions" // Display @use "./Abstract" diff --git a/packages/theme/lib/transitions.sass b/packages/theme/lib/transitions.sass new file mode 100644 index 000000000..eb55f7054 --- /dev/null +++ b/packages/theme/lib/transitions.sass @@ -0,0 +1,41 @@ +.jp-slide-in-up-menu + &-enter + opacity: 0 + transform: translate3d(0, 10px, 0) + + &-active + opacity: 1 + transform: translate3d(0, 0, 0) + transition-property: opacity, transform + transition-timing-function: ease-out + transition-duration: 100ms + + &-exit + opacity: 1 + transform: translate3d(0, 0, 0) + + &-active + opacity: 0 + transform: translate3d(0, 10px, 0) + transition-property: opacity, transform + transition-timing-function: ease-out + transition-duration: 100ms + +.jp-slide-in-down-menu + &-enter + opacity: 0 + transform: translate3d(0, -10px, 0) + + &-active + opacity: 1 + transform: translate3d(0, 0, 0) + transition: opacity .1s ease-out, transform .1s ease-out + + &-exit + opacity: 1 + transform: translate3d(0, 0, 0) + + &-active + opacity: 0 + transform: translate3d(0, -10px, 0) + transition: opacity .1s ease-out, transform .1s ease-out diff --git a/packages/transitions/lib/index.js b/packages/transitions/lib/index.js index d09a42282..ab0ce8722 100644 --- a/packages/transitions/lib/index.js +++ b/packages/transitions/lib/index.js @@ -4,9 +4,10 @@ export const animateMenu = ( name, { time = 100, ...opts } = {} ) => - (menu, { opened }) => ( + (menu, { opened } = {}) => ( ); -export const slideInUpMenu = animateMenu('slide-in-up-menu'); -export const slideInDownMenu = animateMenu('slide-in-down-menu'); +export const slideInUpMenu = animateMenu('jp-slide-in-up-menu'); +export const slideInDownMenu = animateMenu('jp-slide-in-down-menu'); export const animateModal = ( name, { time = 300, ...opts } = {} ) => - (modal, { opened }) => ( + (modal, { opened } = {}) => (