add tests for parsing css value input

This commit is contained in:
Oleg Isonen committed 2022-04-14 11:40:26 +01:00
1 parent 49187a07c4
commit 8748d93eb6
3 files changed
+134 -20

No files matched your search

@@ -0,0 +1,120 @@
import { parseCssValue } from "./parse-css-value";
describe("Parse CSS value", () => {
describe("number value", () => {
test("unitless", () => {
expect(parseCssValue("lineHeight", "10")).toEqual({
type: "unit",
unit: "number",
value: 10,
});
});
});
describe("unit value", () => {
test("with unit", () => {
expect(parseCssValue("width", "10px")).toEqual({
type: "unit",
unit: "px",
value: 10,
});
});
test("with default unit", () => {
expect(parseCssValue("width", "10", "px")).toEqual({
type: "unit",
unit: "px",
value: 10,
});
});
test("with unit and default unit", () => {
expect(parseCssValue("width", "10px", "rem")).toEqual({
type: "unit",
unit: "px",
value: 10,
});
});
test("empty input", () => {
expect(parseCssValue("width", "")).toEqual({
type: "invalid",
value: "",
});
});
test("empty input with default unit", () => {
expect(parseCssValue("width", "", "px")).toEqual({
type: "invalid",
value: "",
});
});
});
describe("keyword value", () => {
test("keyword", () => {
expect(parseCssValue("width", "auto")).toEqual({
type: "keyword",
value: "auto",
});
});
test("keyword with unit", () => {
expect(parseCssValue("width", "autopx")).toEqual({
type: "keyword",
value: "autopx",
});
});
test("incomplete", () => {
// This will return invalid unit when `CSSStyleValue.parse` is available
expect(parseCssValue("width", "10p")).toEqual({
type: "unit",
unit: "number",
value: 10,
});
});
});
describe("math expression", () => {
test("addition with unit", () => {
expect(parseCssValue("width", "10+1px")).toEqual({
type: "unit",
unit: "px",
value: 11,
});
});
test("addition without unit", () => {
expect(parseCssValue("width", "10+1", "px")).toEqual({
type: "unit",
unit: "px",
value: 11,
});
});
test("subtraction with unit", () => {
expect(parseCssValue("width", "10-1px")).toEqual({
type: "unit",
unit: "px",
value: 9,
});
});
test("multiplication with unit", () => {
expect(parseCssValue("width", "2*2px")).toEqual({
type: "unit",
unit: "px",
value: 4,
});
});
test("division with unit", () => {
expect(parseCssValue("width", "4/2px")).toEqual({
type: "unit",
unit: "px",
value: 2,
});
});
});
});
@@ -1,6 +1,6 @@
import hyphenate from "hyphenate-style-name";
import { units } from "@webstudio-is/sdk";
import type { Style, StyleProperty, StyleValue, Unit } from "@webstudio-is/sdk";
import type { StyleProperty, StyleValue, Unit } from "@webstudio-is/sdk";
const unitRegex = new RegExp(`${units.join("|")}`);
@@ -55,10 +55,10 @@ const evaluate = (input: string, parsedUnit: [Unit] | null) => {
// - 10px > px as unit
// - empty string
// - a keyword
export const parseValue = (
export const parseCssValue = (
property: StyleProperty,
input: string,
style: Style
defaultUnit?: Unit
): StyleValue => {
const invalidValue = {
type: "invalid",
@@ -84,20 +84,11 @@ export const parseValue = (
return invalidValue;
}
const previousValue = style[property];
// If user didn't enter a unit, use the previous known unit otherwise fallback to px.
const defaultUnit: Unit =
previousValue !== undefined && "unit" in previousValue
? previousValue.unit
: "number";
const [unit] = parsedUnit || [defaultUnit];
const fallbackUnit: Unit = defaultUnit ?? "number";
const [unit] = parsedUnit || [fallbackUnit];
if (
isValid(property, input) ||
isValid(property, input + unit) ||
isValid(property, number) ||
isValid(property, number + unit)
) {
if (isValid(property, number) || isValid(property, number + unit)) {
return {
type: "unit",
unit,
@@ -3,7 +3,7 @@ import type { SelectedInstanceData, StyleUpdates } from "~/shared/component";
import { type Style, type StyleProperty } from "@webstudio-is/sdk";
import { type Publish } from "~/designer/features/canvas-iframe";
import { useRootInstance } from "../../shared/nano-values";
import { parseValue } from "./parse-value";
import { parseCssValue } from "./parse-css-value";
import { getInheritedStyle, type InheritedStyle } from "./get-inherited-style";
type UseStyleData = {
@@ -64,13 +64,16 @@ export const useStyleData = ({
const setProperty: SetProperty = (property) => {
return (input, options = { isEphemeral: false }) => {
if (currentStyle === undefined) return;
const value = parseValue(property, input, currentStyle);
if (value.type !== "invalid") {
const updates = [{ property, value }];
const currentValue = currentStyle[property];
const defaultUnit =
currentValue?.type === "unit" ? currentValue?.unit : undefined;
const nextValue = parseCssValue(property, input, defaultUnit);
if (nextValue.type !== "invalid") {
const updates = [{ property, value: nextValue }];
const type = options.isEphemeral ? "preview" : "update";
publishUpdates(type, updates);
}
setCurrentStyle({ ...currentStyle, [property]: value });
setCurrentStyle({ ...currentStyle, [property]: nextValue });
};
};