diff --git a/CHANGELOG.md b/CHANGELOG.md index ca5a11c79d..668b86469a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,11 @@ Framer Motion adheres to [Semantic Versioning](http://semver.org/). ## [5.0.2] 2021-11-02 +### Fixed + - Convert x/y from percent to pixels before drag. [Issue](https://github.com/framer/motion/issues/424) - Dynamic functions passed to `controls.start()` can now return variant names. [Issue](https://github.com/framer/motion/issues/503) +- Factors in padding when measuring elements for `width`/`height` unit conversion. [Issue](https://github.com/framer/motion/issues/368) ## [5.0.1] 2021-11-01 diff --git a/dev/examples/Animation-height-auto-padding.tsx b/dev/examples/Animation-height-auto-padding.tsx new file mode 100644 index 0000000000..d126bcf531 --- /dev/null +++ b/dev/examples/Animation-height-auto-padding.tsx @@ -0,0 +1,59 @@ +import * as React from "react" +import { useState } from "react" +import { motion, AnimatePresence } from "@framer" + +export const App = () => { + const [isExpanded, setExpanded] = useState(false) + + return ( +
+ + {isExpanded ? ( + + Test + + ) : null} + + + +
+ ) +} + +const styles = `body { + background: white!important; + background-repeat: no-repeat; + padding: 0; + margin: 0; + display: flex; + justify-content: flex-start; + align-items: flex-start; +} + +.example-container { + width: 320px; + padding: 20px; +} +}` diff --git a/src/render/dom/utils/__tests__/unit-conversion.test.ts b/src/render/dom/utils/__tests__/unit-conversion.test.ts new file mode 100644 index 0000000000..8765f579eb --- /dev/null +++ b/src/render/dom/utils/__tests__/unit-conversion.test.ts @@ -0,0 +1,25 @@ +import { positionalValues } from "../unit-conversion" + +describe("Unit conversion", () => { + test("Correctly factors in padding when measuring width/height", () => { + const testDimensions = { + x: { min: 0, max: 100 }, + y: { min: 0, max: 300 }, + } + expect( + positionalValues.width(testDimensions, { paddingLeft: "50px" }) + ).toBe(50) + + expect( + positionalValues.width(testDimensions, { paddingRight: "25px" }) + ).toBe(75) + + expect( + positionalValues.height(testDimensions, { paddingTop: "50px" }) + ).toBe(250) + + expect( + positionalValues.height(testDimensions, { paddingBottom: "25px" }) + ).toBe(275) + }) +}) diff --git a/src/render/dom/utils/unit-conversion.ts b/src/render/dom/utils/unit-conversion.ts index 06ae02650d..f883777d01 100644 --- a/src/render/dom/utils/unit-conversion.ts +++ b/src/render/dom/utils/unit-conversion.ts @@ -93,20 +93,24 @@ function removeNonTranslationalTransform(visualElement: VisualElement) { return removedTransforms } -const positionalValues: { [key: string]: GetActualMeasurementInPixels } = { - // Dimensions - width: ({ x }) => x.max - x.min, - height: ({ y }) => y.max - y.min, - - top: (_bbox, { top }) => parseFloat(top as string), - left: (_bbox, { left }) => parseFloat(left as string), - bottom: ({ y }, { top }) => parseFloat(top as string) + (y.max - y.min), - right: ({ x }, { left }) => parseFloat(left as string) + (x.max - x.min), - - // Transform - x: getTranslateFromMatrix(4, 13), - y: getTranslateFromMatrix(5, 14), -} +export const positionalValues: { [key: string]: GetActualMeasurementInPixels } = + { + // Dimensions + width: ({ x }, { paddingLeft = "0", paddingRight = "0" }) => + x.max - x.min - parseFloat(paddingLeft) - parseFloat(paddingRight), + height: ({ y }, { paddingTop = "0", paddingBottom = "0" }) => + y.max - y.min - parseFloat(paddingTop) - parseFloat(paddingBottom), + + top: (_bbox, { top }) => parseFloat(top as string), + left: (_bbox, { left }) => parseFloat(left as string), + bottom: ({ y }, { top }) => parseFloat(top as string) + (y.max - y.min), + right: ({ x }, { left }) => + parseFloat(left as string) + (x.max - x.min), + + // Transform + x: getTranslateFromMatrix(4, 13), + y: getTranslateFromMatrix(5, 14), + } const convertChangedValueTypes = ( target: TargetWithKeyframes, @@ -116,9 +120,7 @@ const convertChangedValueTypes = ( const originBbox = visualElement.measureViewportBox() const element = visualElement.getInstance() const elementComputedStyle = getComputedStyle(element) - const { display, top, left, bottom, right, transform } = - elementComputedStyle - const originComputedStyle = { top, left, bottom, right, transform } + const { display } = elementComputedStyle // If the element is currently set to display: "none", make it visible before // measuring the target bounding box @@ -140,7 +142,7 @@ const convertChangedValueTypes = ( const value = visualElement.getValue(key) as MotionValue setAndResetVelocity( value, - positionalValues[key](originBbox, originComputedStyle) + positionalValues[key](originBbox, elementComputedStyle) ) target[key] = positionalValues[key](targetBbox, elementComputedStyle) })