Skip to content

Commit

Permalink
adding pressActive and hoverActive handling
Browse files Browse the repository at this point in the history
  • Loading branch information
mattgperry committed Jan 25, 2019
1 parent b9d8801 commit 75d5881
Show file tree
Hide file tree
Showing 16 changed files with 547 additions and 149 deletions.
2 changes: 1 addition & 1 deletion .prettierrc.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"printWidth": 120,
"printWidth": 80,
"tabWidth": 4,
"semi": false,
"trailingComma": "es5"
Expand Down
22 changes: 17 additions & 5 deletions _src/utils/create-value.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import { invariant } from "hey-listen"

const poseSpecialProps = new Set(["transition", "transitionEnd"])

export const createValuesFromPose = (values: MotionValueMap, { transition, transitionEnd, ...pose }: Pose) => {
export const createValuesFromPose = (
values: MotionValueMap,
{ transition, transitionEnd, ...pose }: Pose
) => {
const valuesToAdd = { ...pose, ...transitionEnd }
Object.keys(valuesToAdd).forEach(valueKey => {
if (!values.has(valueKey)) {
Expand All @@ -15,15 +18,18 @@ export const createValuesFromPose = (values: MotionValueMap, { transition, trans
})
}

export const bindValuesToRef = (values: MotionValueMap, ref: RefObject<Element>) => {
export const bindValuesToRef = (
values: MotionValueMap,
ref: RefObject<Element>
) => {
invariant(
ref.current !== null,
"No DOM reference found. Ensure custom components use `forwardRef` to forward the `ref` property to the host DOM component."
)

if (!ref.current) return

const domStyler = styler(ref.current)
const domStyler = styler(ref.current, { preparseOutput: false })

values.forEach((value, key) => {
if (!value.hasOnRender()) {
Expand All @@ -32,8 +38,14 @@ export const bindValuesToRef = (values: MotionValueMap, ref: RefObject<Element>)
})
}

export const checkForNewValues = (pose: Pose, values: MotionValueMap, ref: RefObject<Element>) => {
const newValueKeys = Object.keys(pose).filter(key => !poseSpecialProps.has(key) && !values.has(key))
export const checkForNewValues = (
pose: Pose,
values: MotionValueMap,
ref: RefObject<Element>
) => {
const newValueKeys = Object.keys(pose).filter(
key => !poseSpecialProps.has(key) && !values.has(key)
)

if (newValueKeys.length) {
createValuesFromPose(values, pose)
Expand Down
18 changes: 18 additions & 0 deletions dev/examples/gesturesActive.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as React from "react"
import { motion } from "@framer"

const style = {
width: 100,
height: 100,
background: "rgba(255, 0, 0, 1)",
}

export const App = () => {
return (
<motion.div
hoverActive={{ scale: 1.5 }}
pressActive={{ scale: 0.5, backgroundColor: "rgba(0, 255, 0, .5)" }}
style={style}
/>
)
}
11 changes: 8 additions & 3 deletions src/animation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,23 @@ export class AnimationManager {

setVariants(variants: Variants) {
this.variants = variants
this.componentControls.forEach(controls => controls.setVariants(variants))
this.componentControls.forEach(controls =>
controls.setVariants(variants)
)
}

setDefaultTransition(transition: Transition) {
this.defaultTransition = transition
this.componentControls.forEach(controls => controls.setDefaultTransition(transition))
this.componentControls.forEach(controls =>
controls.setDefaultTransition(transition)
)
}

subscribe(controls: AnimationControls) {
this.componentControls.add(controls)
if (this.variants) controls.setVariants(this.variants)
if (this.defaultTransition) controls.setDefaultTransition(this.defaultTransition)
if (this.defaultTransition)
controls.setDefaultTransition(this.defaultTransition)

return () => this.componentControls.delete(controls)
}
Expand Down
5 changes: 4 additions & 1 deletion src/animation/use-animation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { AnimationManager } from "."
import { useMemo, useEffect } from "react"
import { Transition, Variants } from "../types"

export const useAnimation = (variants?: Variants, defaultTransition?: Transition) => {
export const useAnimation = (
variants?: Variants,
defaultTransition?: Transition
) => {
const animationManager = useMemo(() => new AnimationManager(), [])

if (variants) {
Expand Down
41 changes: 34 additions & 7 deletions src/behaviours/use-draggable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,17 @@ export interface DraggableProps {
* @default false
*/
dragConstraints?: Constraints

/**
* Allow "overdragging" beyond the drag constraints
* @default false
*/
overdrag?: Overdrag

/**
* Allow smooth scrolling
* @default false
*/
dragMomentum?: boolean
}

Expand All @@ -64,7 +69,10 @@ function shouldDrag(
)
}

const getConstraints = (axis: "x" | "y", { top, right, bottom, left }: Constraints) => {
const getConstraints = (
axis: "x" | "y",
{ top, right, bottom, left }: Constraints
) => {
if (axis === "x") {
return { min: left, max: right }
} else {
Expand All @@ -83,8 +91,18 @@ export function useDraggable(
values: MotionValuesMap,
controls: AnimationControls
) {
const { dragEnabled = false, dragPropagation, dragLocksDirection, dragConstraints, overdrag, dragMomentum } = props
const point: Partial<{ x: MotionValue<number>; y: MotionValue<number> }> = {}
const {
dragEnabled = false,
dragPropagation,
dragLocksDirection,
dragConstraints,
overdrag,
dragMomentum,
} = props
const point: Partial<{
x: MotionValue<number>
y: MotionValue<number>
}> = {}
const origin = { x: 0, y: 0 }
let currentDirection: null | DragDirection = null
if (shouldDrag("x", dragEnabled, currentDirection)) {
Expand All @@ -104,9 +122,13 @@ export function useDraggable(
const { min, max } = getConstraints(axis, dragConstraints)

if (min !== undefined && current < min) {
current = overdrag ? applyOverdrag(min, current, overdrag) : Math.max(min, current)
current = overdrag
? applyOverdrag(min, current, overdrag)
: Math.max(min, current)
} else if (max !== undefined && current > max) {
current = overdrag ? applyOverdrag(max, current, overdrag) : Math.min(max, current)
current = overdrag
? applyOverdrag(max, current, overdrag)
: Math.min(max, current)
}
}

Expand Down Expand Up @@ -142,7 +164,10 @@ export function useDraggable(

const onPan: PanHandler = useMemo(
() => {
const updateDrag = (_event: MouseEvent | TouchEvent, { offset }: PanInfo) => {
const updateDrag = (
_event: MouseEvent | TouchEvent,
{ offset }: PanInfo
) => {
if (!dragPropagation && !openGlobalLock) {
return
}
Expand Down Expand Up @@ -170,7 +195,9 @@ export function useDraggable(
if (dragMomentum) {
const startMomentum = (axis: "x" | "y") => {
if (!shouldDrag(axis, dragEnabled, currentDirection)) return
const transition = dragConstraints ? getConstraints(axis, dragConstraints) : {}
const transition = dragConstraints
? getConstraints(axis, dragConstraints)
: {}

controls.start({
[axis]: 0,
Expand Down
47 changes: 39 additions & 8 deletions src/dom/unit-type-conversion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,19 @@ import { MotionValue } from "value"
import styler from "stylefire"
import { getValueType } from "./value-types"

const positionalKeys = new Set(["width", "height", "top", "left", "right", "bottom", "x", "y"])
const positionalKeys = new Set([
"width",
"height",
"top",
"left",
"right",
"bottom",
"x",
"y",
])
const isPositionalKey = (key: string) => positionalKeys.has(key)
const hasPositionalKey = (target: Target) => Object.keys(target).some(isPositionalKey)
const hasPositionalKey = (target: Target) =>
Object.keys(target).some(isPositionalKey)

const setAndResetVelocity = (value: MotionValue, to: string | number) => {
// Looks odd but setting it twice doesn't render, it'll just
Expand All @@ -27,11 +37,18 @@ export enum BoundingBoxDimension {
bottom = "bottom",
}

type GetActualMeasurementInPixels = (bbox: ClientRect | DOMRect, computedStyle: Partial<CSSStyleDeclaration>) => number
type GetActualMeasurementInPixels = (
bbox: ClientRect | DOMRect,
computedStyle: Partial<CSSStyleDeclaration>
) => number

const getPosFromMatrix = (matrix: string, pos: number) => parseFloat(matrix.split(", ")[pos])
const getPosFromMatrix = (matrix: string, pos: number) =>
parseFloat(matrix.split(", ")[pos])

const getTranslateFromMatrix = (pos2: number, pos3: number): GetActualMeasurementInPixels => (_bbox, { transform }) => {
const getTranslateFromMatrix = (
pos2: number,
pos3: number
): GetActualMeasurementInPixels => (_bbox, { transform }) => {
if (transform === "none" || !transform) return 0

const matrix3d = transform.match(/^matrix3d\((.+)\)$/)
Expand Down Expand Up @@ -81,7 +98,10 @@ const convertChangedValueTypes = (
// Restore styles to their **calculated computed style**, not their actual
// originally set style. This allows us to animate between equivalent pixel units.
const value = values.get(key) as MotionValue
setAndResetVelocity(value, positionalValues[key](originBbox, originComputedStyle))
setAndResetVelocity(
value,
positionalValues[key](originBbox, originComputedStyle)
)
pose[key] = positionalValues[key](targetBbox, elementComputedStyle)
})

Expand Down Expand Up @@ -110,7 +130,10 @@ const checkAndConvertChangedValueTypes = (

if (fromType !== toType) {
acc.push(key)
transitionEnd[key] = transitionEnd[key] !== undefined ? transitionEnd[key] : target[key]
transitionEnd[key] =
transitionEnd[key] !== undefined
? transitionEnd[key]
: target[key]
setAndResetVelocity(value, to)
}

Expand All @@ -120,7 +143,15 @@ const checkAndConvertChangedValueTypes = (
)

return changedValueTypeKeys.length
? { target: convertChangedValueTypes(target, values, ref, changedValueTypeKeys), transitionEnd }
? {
target: convertChangedValueTypes(
target,
values,
ref,
changedValueTypeKeys
),
transitionEnd,
}
: { target, transitionEnd }
}

Expand Down
45 changes: 45 additions & 0 deletions src/gestures/use-hover-gesture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { useMemo, SyntheticEvent } from "react"
import { AnimationControls } from "../motion"
import { getGesturePriority } from "./utils/gesture-priority"
import { TargetAndTransition } from "../types"

export type HoverProps = {
hoverActive: TargetAndTransition
onMouseEnter: (e: SyntheticEvent) => void
onMouseLeave: (e: SyntheticEvent) => void
}

const hoverPriority = getGesturePriority("hover")

export const useHover = (
{ hoverActive, onMouseEnter, onMouseLeave }: HoverProps,
controls: AnimationControls
) => {
return useMemo(
() => {
if (!hoverActive) {
return {}
}

return {
onMouseEnter: (e: SyntheticEvent) => {
if (onMouseEnter) onMouseEnter(e)

if (hoverActive) {
controls.start(hoverActive, {
priority: hoverPriority,
})
}
},
onMouseLeave: (e: SyntheticEvent) => {
if (onMouseLeave) onMouseLeave(e)

if (hoverActive) {
controls.clearOverride(hoverPriority)
}
},
}
},
[hoverActive, onMouseEnter, onMouseLeave]
)
}
Loading

0 comments on commit 75d5881

Please sign in to comment.