diff options
author | Thomas F. K. Jorna <[email protected]> | 2021-10-11 01:27:47 +0200 |
---|---|---|
committer | Thomas F. K. Jorna <[email protected]> | 2021-10-11 01:27:47 +0200 |
commit | bb6fe7325dfe76c0618d34455e56122c3204a3b3 (patch) | |
tree | 63585e12385dfa5c7501f03646cb2a88cb43a0da /components | |
parent | 546a88ec37073840e98ed689f7139d04985e861c (diff) |
chore: build
Diffstat (limited to 'components')
-rw-r--r-- | components/Sidebar/Collapse.tsx | 146 | ||||
-rw-r--r-- | components/Sidebar/transition-utils.tsx | 144 | ||||
-rw-r--r-- | components/contextmenu.tsx | 4 |
3 files changed, 291 insertions, 3 deletions
diff --git a/components/Sidebar/Collapse.tsx b/components/Sidebar/Collapse.tsx new file mode 100644 index 0000000..b297605 --- /dev/null +++ b/components/Sidebar/Collapse.tsx @@ -0,0 +1,146 @@ +// modified from https://github.com/chakra-ui/chakra-ui/blob/fc3b97d0978cf2adb9fc79157c6e42b4b68155c5/packages/transition/src/collapse.tsx + +import { cx, mergeWith, warn, __DEV__ } from '@chakra-ui/utils' +import { AnimatePresence, HTMLMotionProps, motion, Variants as _Variants } from 'framer-motion' +import * as React from 'react' +import { TransitionEasings, Variants, withDelay, WithTransitionConfig } from './transition-utils' + +const isNumeric = (value?: string | number) => value != null && parseInt(value.toString(), 10) > 0 + +export interface CollapseOptions { + /** + * If `true`, the opacity of the content will be animated + * @default true + */ + animateOpacity?: boolean + /** + * The size you want the content in its collapsed state. + * @default 0 + */ + startingSize?: number | string + /** + * The size you want the content in its expanded state. + * @default "auto" + */ + endingSize?: number | string + /** + * The dimension you want to collapse by. + * @default "size" + */ + dimension?: string +} + +const defaultTransitions = { + exit: { + size: { duration: 0.2, ease: TransitionEasings.ease }, + opacity: { duration: 0.3, ease: TransitionEasings.ease }, + }, + enter: { + size: { duration: 0.3, ease: TransitionEasings.ease }, + opacity: { duration: 0.4, ease: TransitionEasings.ease }, + }, +} + +const variants: Variants<CollapseOptions> = { + exit: ({ animateOpacity, startingSize, transition, transitionEnd, delay, dimension }) => ({ + ...(animateOpacity && { opacity: isNumeric(startingSize) ? 1 : 0 }), + overflow: 'hidden', + [dimension as string]: startingSize, + transitionEnd: transitionEnd?.exit, + transition: transition?.exit ?? withDelay.exit(defaultTransitions.exit, delay), + }), + enter: ({ animateOpacity, endingSize, transition, transitionEnd, delay, dimension }) => ({ + ...(animateOpacity && { opacity: 1 }), + [dimension as string]: endingSize, + transitionEnd: transitionEnd?.enter, + transition: transition?.enter ?? withDelay.enter(defaultTransitions.enter, delay), + }), +} + +export type ICollapse = CollapseProps + +export interface CollapseProps + extends WithTransitionConfig<HTMLMotionProps<'div'>>, + CollapseOptions {} + +export const Collapse = React.forwardRef<HTMLDivElement, CollapseProps>((props, ref) => { + const { + in: isOpen, + unmountOnExit, + animateOpacity = true, + startingSize = 0, + endingSize = 'auto', + dimension = 'height', + style, + className, + transition, + transitionEnd, + ...rest + } = props + + const [mounted, setMounted] = React.useState(false) + React.useEffect(() => { + const timeout = setTimeout(() => { + setMounted(true) + }) + return () => clearTimeout(timeout) + }, []) + + /** + * Warn 🚨: `startingSize` and `unmountOnExit` are mutually exclusive + * + * If you specify a starting size, the collapsed needs to be mounted + * for the size to take effect. + */ + warn({ + condition: Boolean(startingSize > 0 && unmountOnExit), + message: `startingSize and unmountOnExit are mutually exclusive. You can't use them together`, + }) + + const hasStartingSize = parseFloat(startingSize.toString()) > 0 + + const custom = { + startingSize, + endingSize, + animateOpacity, + dimension, + transition: !mounted ? { enter: { duration: 0 } } : transition, + transitionEnd: mergeWith(transitionEnd, { + enter: { overflow: 'initial' }, + exit: unmountOnExit + ? undefined + : { + display: hasStartingSize ? 'block' : 'none', + }, + }), + } + + const show = unmountOnExit ? isOpen : true + const animate = isOpen || unmountOnExit ? 'enter' : 'exit' + + return ( + <AnimatePresence initial={false} custom={custom}> + {show && ( + <motion.div + ref={ref} + {...rest} + className={cx('chakra-collapse', className)} + style={{ + overflow: 'hidden', + display: 'block', + ...style, + }} + custom={custom} + variants={variants as _Variants} + initial={unmountOnExit ? 'exit' : false} + animate={animate} + exit="exit" + /> + )} + </AnimatePresence> + ) +}) + +if (__DEV__) { + Collapse.displayName = 'Collapse' +} diff --git a/components/Sidebar/transition-utils.tsx b/components/Sidebar/transition-utils.tsx new file mode 100644 index 0000000..68634bb --- /dev/null +++ b/components/Sidebar/transition-utils.tsx @@ -0,0 +1,144 @@ +// Taken from https://github.com/chakra-ui/chakra-ui/blob/fc3b97d0978cf2adb9fc79157c6e42b4b68155c5/packages/transition/src/transition-utils.ts +import { isNumber } from '@chakra-ui/utils' +import { Target, TargetAndTransition, Transition } from 'framer-motion' + +type TargetResolver<P = {}> = ( + props: P & { + transition?: TransitionConfig + transitionEnd?: TransitionEndConfig + delay?: number | DelayConfig + }, +) => TargetAndTransition + +type Variant<P = {}> = TargetAndTransition | TargetResolver<P> + +export type Variants<P = {}> = { + enter: Variant<P> + exit: Variant<P> + initial?: Variant<P> +} + +type WithMotionState<P> = Partial<Record<'enter' | 'exit', P>> + +export type TransitionConfig = WithMotionState<Transition> + +export type TransitionEndConfig = WithMotionState<Target> + +export type DelayConfig = WithMotionState<number> + +export const TransitionEasings = { + ease: [0.25, 0.1, 0.25, 1], + easeIn: [0.4, 0, 1, 1], + easeOut: [0, 0, 0.2, 1], + easeInOut: [0.4, 0, 0.2, 1], +} as const + +export const TransitionVariants = { + scale: { + enter: { scale: 1 }, + exit: { scale: 0.95 }, + }, + fade: { + enter: { opacity: 1 }, + exit: { opacity: 0 }, + }, + pushLeft: { + enter: { x: '100%' }, + exit: { x: '-30%' }, + }, + pushRight: { + enter: { x: '-100%' }, + exit: { x: '30%' }, + }, + pushUp: { + enter: { y: '100%' }, + exit: { y: '-30%' }, + }, + pushDown: { + enter: { y: '-100%' }, + exit: { y: '30%' }, + }, + slideLeft: { + position: { left: 0, top: 0, bottom: 0, width: '100%' }, + enter: { x: 0 }, + exit: { x: '-100%' }, + }, + slideRight: { + position: { right: 0, top: 0, bottom: 0, width: '100%' }, + enter: { x: 0 }, + exit: { x: '100%' }, + }, + slideUp: { + position: { top: 0, left: 0, right: 0, maxWidth: '100vw' }, + enter: { y: 0 }, + exit: { y: '-100%' }, + }, + slideDown: { + position: { bottom: 0, left: 0, right: 0, maxWidth: '100vw' }, + enter: { y: 0 }, + exit: { y: '100%' }, + }, +} + +export type SlideDirection = 'top' | 'left' | 'bottom' | 'right' + +export function slideTransition(options?: { direction?: SlideDirection }) { + const side = options?.direction ?? 'right' + switch (side) { + case 'right': + return TransitionVariants.slideRight + case 'left': + return TransitionVariants.slideLeft + case 'bottom': + return TransitionVariants.slideDown + case 'top': + return TransitionVariants.slideUp + default: + return TransitionVariants.slideRight + } +} + +export const TransitionDefaults = { + enter: { + duration: 0.2, + ease: TransitionEasings.easeOut, + }, + exit: { + duration: 0.1, + ease: TransitionEasings.easeIn, + }, +} as const + +export type WithTransitionConfig<P extends object> = Omit<P, 'transition'> & { + /** + * If `true`, the element will unmount when `in={false}` and animation is done + */ + unmountOnExit?: boolean + /** + * Show the component; triggers the enter or exit states + */ + in?: boolean + /** + * Custom `transition` definition for `enter` and `exit` + */ + transition?: TransitionConfig + /** + * Custom `transitionEnd` definition for `enter` and `exit` + */ + transitionEnd?: TransitionEndConfig + /** + * Custom `delay` definition for `enter` and `exit` + */ + delay?: number | DelayConfig +} + +export const withDelay = { + enter: (transition: Transition, delay?: number | DelayConfig) => ({ + ...transition, + delay: isNumber(delay) ? delay : delay?.['enter'], + }), + exit: (transition: Transition, delay?: number | DelayConfig) => ({ + ...transition, + delay: isNumber(delay) ? delay : delay?.['exit'], + }), +} diff --git a/components/contextmenu.tsx b/components/contextmenu.tsx index bff4861..118b8bb 100644 --- a/components/contextmenu.tsx +++ b/components/contextmenu.tsx @@ -50,13 +50,12 @@ export default interface ContextMenuProps { background: Boolean target: OrgRoamNode | null nodeType?: string - coordinates: { [direction: string]: number } + coordinates: { [direction: string]: number | undefined } handleLocal: (node: OrgRoamNode, add: string) => void menuClose: () => void scope: { nodeIds: string[] } webSocket: any setPreviewNode: any - contextMenuRef: any } export const ContextMenu = (props: ContextMenuProps) => { @@ -70,7 +69,6 @@ export const ContextMenu = (props: ContextMenuProps) => { scope, webSocket, setPreviewNode, - contextMenuRef, } = props const { isOpen, onOpen, onClose } = useDisclosure() const copyRef = useRef<any>() |