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 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | 35x 551x 35x 35x 7x 7x 7x 7x 35x 4x 2x 2x 2x 2x 2x 2x 35x 249x 249x 249x 248x 7x 248x 282x 282x 1x 1x 248x 269x 269x 1x 1x 1x 1x 248x | import { Target, TargetWithKeyframes } from "../../../types" import { invariant } from "hey-listen" import { VisualElement } from "../../types" function isCSSVariable(value: any): value is string { return typeof value === "string" && value.startsWith("var(--") } /** * Parse Framer's special CSS variable format into a CSS token and a fallback. * * ``` * `var(--foo, #fff)` => [`--foo`, '#fff'] * ``` * * @param current */ export const cssVariableRegex = /var\((--[a-zA-Z0-9-_]+),? ?([a-zA-Z0-9 ()%#.,-]+)?\)/ export function parseCSSVariable(current: string) { const match = cssVariableRegex.exec(current) Iif (!match) return [,] const [, token, fallback] = match return [token, fallback] } const maxDepth = 4 function getVariableValue( current: string, element: Element, Edepth = 1 ): string | undefined { invariant( depth <= maxDepth, `Max CSS variable fallback depth detected in property "${current}". This may indicate a circular fallback dependency.` ) const [token, fallback] = parseCSSVariable(current) // No CSS variable detected Iif (!token) return // Attempt to read this CSS variable off the element const resolved = window.getComputedStyle(element).getPropertyValue(token) Eif (resolved) { return resolved.trim() } else if (isCSSVariable(fallback)) { // The fallback might itself be a CSS variable, in which case we attempt to resolve it too. return getVariableValue(fallback, element, depth + 1) } else { return fallback } } /** * Resolve CSS variables from * * @internal */ export function resolveCSSVariables( visualElement: VisualElement, { ...target }: TargetWithKeyframes, transitionEnd: Target | undefined ): { target: TargetWithKeyframes; transitionEnd?: Target } { const element = visualElement.getInstance() if (!(element instanceof Element)) return { target, transitionEnd } // If `transitionEnd` isn't `undefined`, clone it. We could clone `target` and `transitionEnd` // only if they change but I think this reads clearer and this isn't a performance-critical path. if (transitionEnd) { transitionEnd = { ...transitionEnd } } // Go through existing `MotionValue`s and ensure any existing CSS variables are resolved visualElement.forEachValue((value) => { const current = value.get() if (!isCSSVariable(current)) return const resolved = getVariableValue(current, element) Eif (resolved) value.set(resolved) }) // Cycle through every target property and resolve CSS variables. Currently // we only read single-var properties like `var(--foo)`, not `calc(var(--foo) + 20px)` for (const key in target) { const current = target[key] if (!isCSSVariable(current)) continue const resolved = getVariableValue(current, element) Iif (!resolved) continue // Clone target if it hasn't already been target[key] = resolved // If the user hasn't already set this key on `transitionEnd`, set it to the unresolved // CSS variable. This will ensure that after the animation the component will reflect // changes in the value of the CSS variable. Iif (transitionEnd) transitionEnd[key] ??= current } return { target, transitionEnd } } |