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)
})