Skip to content

A custom property stores 5px, 5ms and 5 all as 5, so transition-duration: var(--v) over --v: 5px applies 5ms #551

Open

Description

@YevheniiKotyrlo

Before submitting a new issue

  • I tested using the latest version of the library, as the bug might be already fixed.
  • I tested using a supported version of react native.
  • I checked for possible duplicate issues, with possible answers.

Bug summary

A custom property's value loses its unit when the sheet compiles: --v: 5ms, --v: 5px and --v: 5 all store 5, and --v: 5s stores 5000. So a property that reads the variable can't tell a length from a time or a number: with variables kept (inlineVariables: false), transition-duration: var(--v) over --v: 5px applies transitionDuration: 5, the same as over 5ms, and animation-iteration-count: var(--v) over --v: 2px applies animationIterationCount: 2.

In CSS a var() whose value doesn't fit the property's grammar makes the declaration invalid at computed-value time (css-variables-1 §3), so the property takes its initial value: Chromium 156, Firefox 157 and WebKit 27.2 compute transition-duration: 0s and animation-iteration-count: 1 for these. 5em and 5deg keep their unit ([{}, "em", 5, 1] and "5deg"), so only px lengths and times lose it.

--v: 5ms -> [["v",5]]
--v: 5 -> [["v",5]]
--v: 5px -> [["v",5]]
--v: 5s -> [["v",5000]]
--v: 5em -> [["v",[{},"em",5,1]]]
--v: 5deg -> [["v","5deg"]]
.a { --v: 5px; transition-duration: var(--v); } -> {"transitionDuration":5}
.a { --v: 5ms; transition-duration: var(--v); } -> {"transitionDuration":5}
.a { --v: 2px; animation-iteration-count: var(--v); } -> {"animationIterationCount":2}
.a { --v: 2; animation-iteration-count: var(--v); } -> {"animationIterationCount":2}

parseUnparsed (src/compiler/declarations.ts) turns a px length token and a time token into a bare number (through parseLength and parseTime), as a declaration's own parser does once it knows its property. A custom property's value has no property yet, so its kind is gone before any reader sees it.

Library version

main at a37903f (0.0.0-nightly.a37903f)

Environment info

Windows 11 10.0.26300, Node 26.12.1, Yarn 4.9.2, react-native 0.86.3 (the repository's dev dependency).
No app or native build is involved: the output comes from the repository's jest setup.

Steps to reproduce

  1. Clone the reproducer branch, which is main at a37903f with one file added, src/__tests__/native/custom-property-unit.test.tsx, and install:
    git clone --branch repro/551-custom-property-keeps-no-unit https://github.com/YevheniiKotyrlo/react-native-css
    cd react-native-css
    yarn install
  2. Run yarn jest src/__tests__/native/custom-property-unit.test.tsx and read the logged lines.

src/__tests__/native/custom-property-unit.test.tsx:

import { StyleSheet } from "react-native";

import { render, screen } from "@testing-library/react-native";
import { compile } from "react-native-css/compiler";
import { View } from "react-native-css/components/View";
import { registerCSS, testID } from "react-native-css/jest";

jest.mock("../../native/reanimated", () => ({
  animatedComponentFamily: (component: unknown) => component,
}));

test.each(["5ms", "5", "5px", "5s", "5em", "5deg"])(
  "the stored value of --v: %s",
  (value) => {
    const sheet = compile(`.a { --v: ${value}; }`, {
      inlineVariables: false,
    }).stylesheet();
    console.log(`--v: ${value} -> ${JSON.stringify(sheet.s?.[0]?.[1][0]?.v)}`);
  },
);

test.each([
  ["5px", "transition-duration"],
  ["5ms", "transition-duration"],
  ["2px", "animation-iteration-count"],
  ["2", "animation-iteration-count"],
])("--v: %s read by %s: var(--v)", (value, property) => {
  registerCSS(`.a { --v: ${value}; ${property}: var(--v); }`, {
    inlineVariables: false,
  });
  render(<View testID={testID} className="a" />);
  console.log(
    `.a { --v: ${value}; ${property}: var(--v); } -> ${JSON.stringify(StyleSheet.flatten(screen.getByTestId(testID).props.style))}`,
  );
  screen.unmount();
});

Expected: the stored value keeps its kind, so transition-duration: var(--v) over --v: 5px and animation-iteration-count: var(--v) over --v: 2px are refused and the properties take their initial values, 0s and 1, as in the browsers.

Actual: 5px and 5ms both store 5, and both apply transitionDuration: 5; 2px applies animationIterationCount: 2.

The run's output on main at a37903f, Windows 11, Node 26.12.1
  console.log
    --v: 5ms -> [["v",5]]

      at log (src/__tests__/native/custom-property-unit.test.tsx:18:13)

  console.log
    --v: 5 -> [["v",5]]

      at log (src/__tests__/native/custom-property-unit.test.tsx:18:13)

  console.log
    --v: 5px -> [["v",5]]

      at log (src/__tests__/native/custom-property-unit.test.tsx:18:13)

  console.log
    --v: 5s -> [["v",5000]]

      at log (src/__tests__/native/custom-property-unit.test.tsx:18:13)

  console.log
    --v: 5em -> [["v",[{},"em",5,1]]]

      at log (src/__tests__/native/custom-property-unit.test.tsx:18:13)

  console.log
    --v: 5deg -> [["v","5deg"]]

      at log (src/__tests__/native/custom-property-unit.test.tsx:18:13)

  console.log
    .a { --v: 5px; transition-duration: var(--v); } -> {"transitionDuration":5}

      at log (src/__tests__/native/custom-property-unit.test.tsx:32:11)

  console.log
    .a { --v: 5ms; transition-duration: var(--v); } -> {"transitionDuration":5}

      at log (src/__tests__/native/custom-property-unit.test.tsx:32:11)

  console.log
    .a { --v: 2px; animation-iteration-count: var(--v); } -> {"animationIterationCount":2}

      at log (src/__tests__/native/custom-property-unit.test.tsx:32:11)

  console.log
    .a { --v: 2; animation-iteration-count: var(--v); } -> {"animationIterationCount":2}

      at log (src/__tests__/native/custom-property-unit.test.tsx:32:11)

PASS src/__tests__/native/custom-property-unit.test.tsx
  √ the stored value of --v: 5ms (15 ms)
  √ the stored value of --v: 5 (1 ms)
  √ the stored value of --v: 5px (1 ms)
  √ the stored value of --v: 5s (1 ms)
  √ the stored value of --v: 5em (1 ms)
  √ the stored value of --v: 5deg (1 ms)
  √ --v: 5px read by transition-duration: var(--v) (8 ms)
  √ --v: 5ms read by transition-duration: var(--v) (2 ms)
  √ --v: 2px read by animation-iteration-count: var(--v) (1 ms)
  √ --v: 2 read by animation-iteration-count: var(--v) (2 ms)

Test Suites: 1 passed, 1 total
Tests:       10 passed, 10 total
Snapshots:   0 total
Time:        1.126 s, estimated 10 s
Ran all test suites matching /src\\__tests__\\native\\custom-property-unit.test.tsx/i.

Reproducible example repository

https://github.com/YevheniiKotyrlo/react-native-css/tree/repro/551-custom-property-keeps-no-unit

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions