All files / src/projection/styles scale-box-shadow.ts

100% Statements 36/36
83.33% Branches 10/12
100% Functions 3/3
100% Lines 34/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 7035x 35x 35x     35x   35x 4x 4x         4x 4x 4x 2x 2x 2x       4x     4x   3x 3x     3x 3x     3x 3x               3x     3x 3x     3x 3x   3x   3x 1x 1x 1x 1x 1x       3x      
import { mix } from "popmotion"
import { complex } from "style-value-types"
import { cssVariableRegex } from "../../render/dom/utils/css-variables-conversion"
import { ScaleCorrectorDefinition } from "./types"
 
const varToken = "_$css"
 
export const correctBoxShadow: ScaleCorrectorDefinition = {
    correct: (latest: string, { treeScale, projectionDelta }) => {
        const original = latest
 
        /**
         * We need to first strip and store CSS variables from the string.
         */
        const containsCSSVariables = latest.includes("var(")
        const cssVariables: string[] = []
        if (containsCSSVariables) {
            latest = latest.replace(cssVariableRegex, (match) => {
                cssVariables.push(match)
                return varToken
            })
        }
 
        const shadow = complex.parse(latest)
 
        // TODO: Doesn't support multiple shadows
        if (shadow.length > 5) return original
 
        const template = complex.createTransformer(latest)
        const offset = typeof shadow[0] !== "number" ? 1 : 0
 
        // Calculate the overall context scale
        const xScale = projectionDelta!.x.scale * treeScale!.x
        const yScale = projectionDelta!.y.scale * treeScale!.y
 
        // Scale x/y
        ;(shadow[0 + offset] as number) /= xScale
        ;(shadow[1 + offset] as number) /= yScale
 
        /**
         * Ideally we'd correct x and y scales individually, but because blur and
         * spread apply to both we have to take a scale average and apply that instead.
         * We could potentially improve the outcome of this by incorporating the ratio between
         * the two scales.
         */
        const averageScale = mix(xScale, yScale, 0.5)
 
        // Blur
        Eif (typeof shadow[2 + offset] === "number")
            (shadow[2 + offset] as number) /= averageScale
 
        // Spread
        Eif (typeof shadow[3 + offset] === "number")
            (shadow[3 + offset] as number) /= averageScale
 
        let output = template(shadow)
 
        if (containsCSSVariables) {
            let i = 0
            output = output.replace(varToken, () => {
                const cssVariable = cssVariables[i]
                i++
                return cssVariable
            })
        }
 
        return output
    },
}