From 37b0abb01fde0d428178a927a655191c8073e56c Mon Sep 17 00:00:00 2001 From: "asamuzaK (Kazz)" Date: Sat, 21 Dec 2024 00:27:13 +0900 Subject: [PATCH] Support nested var() and nested calc() Fixes #125, closes #127 --- lib/CSSStyleDeclaration.js | 4 ++- lib/parsers.js | 10 +++---- package-lock.json | 8 +++--- package.json | 2 +- test/CSSStyleDeclaration.js | 57 +++++++++++++++++++++++++++++++++++++ test/parsers.js | 36 +++++++++++++++++++++++ 6 files changed, 106 insertions(+), 11 deletions(-) diff --git a/lib/CSSStyleDeclaration.js b/lib/CSSStyleDeclaration.js index 0a180f6..d7a7566 100644 --- a/lib/CSSStyleDeclaration.js +++ b/lib/CSSStyleDeclaration.js @@ -53,7 +53,9 @@ CSSStyleDeclaration.prototype = { this.removeProperty(name); return; } - var isCustomProperty = name.indexOf('--') === 0; + var isCustomProperty = + name.indexOf('--') === 0 || + (typeof value === 'string' && /^var\(--[-\w]+,?.*\)$/.test(value)); if (isCustomProperty) { this._setProperty(name, value, priority); return; diff --git a/lib/parsers.js b/lib/parsers.js index 3478658..f5107be 100644 --- a/lib/parsers.js +++ b/lib/parsers.js @@ -4,7 +4,7 @@ ********************************************************************/ 'use strict'; -const { isColor, resolve } = require('@asamuzakjp/css-color'); +const { cssCalc, isColor, resolve } = require('@asamuzakjp/css-color'); exports.TYPES = { INTEGER: 1, @@ -27,7 +27,7 @@ var lengthRegEx = /^(0|[-+]?[0-9]*\.?[0-9]+(in|cm|em|mm|pt|pc|px|ex|rem|vh|vw|ch var percentRegEx = /^[-+]?[0-9]*\.?[0-9]+%$/; var urlRegEx = /^url\(\s*([^)]*)\s*\)$/; var stringRegEx = /^("[^"]*"|'[^']*')$/; -var calcRegEx = /^calc\(([^)]*)\)$/; +var calcRegEx = /^(?:abs|calc|sign)\(/; var angleRegEx = /^([-+]?[0-9]*\.?[0-9]+)(deg|grad|rad)$/; // This will return one of the above types based on the passed in string @@ -38,11 +38,9 @@ exports.valueType = function valueType(val) { if (typeof val === 'number') { val = val.toString(); } - if (typeof val !== 'string') { return undefined; } - if (integerRegEx.test(val)) { return exports.TYPES.INTEGER; } @@ -161,7 +159,9 @@ exports.parsePercent = function parsePercent(val) { exports.parseMeasurement = function parseMeasurement(val) { var type = exports.valueType(val); if (type === exports.TYPES.CALC) { - return val; + return cssCalc(val, { + format: 'specifiedValue', + }); } var length = exports.parseLength(val); diff --git a/package-lock.json b/package-lock.json index 454e249..f5f5a54 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "4.1.0", "license": "MIT", "dependencies": { - "@asamuzakjp/css-color": "^2.5.0", + "@asamuzakjp/css-color": "^2.6.5", "rrweb-cssom": "^0.7.1" }, "devDependencies": { @@ -30,9 +30,9 @@ } }, "node_modules/@asamuzakjp/css-color": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-2.5.0.tgz", - "integrity": "sha512-LuUSDuz8MPTAPOb9Zvd6b/D2nUyG7NZaI8OGZhu45xgQTqLQOC29HLfadPMrs5C7JY784WRtLMvLmQhTpIY0Pw==", + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-2.6.5.tgz", + "integrity": "sha512-MIF+O+I0TadFOcvMTxAKvxz5s/2AeqX0Zk546llW1Sc62rH7zBTF5i21r3sJYhoFEZvHb76tNQfnWqesn29h8w==", "license": "MIT", "dependencies": { "@csstools/css-calc": "^2.1.0", diff --git a/package.json b/package.json index 0f8e70c..4618caa 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ ], "main": "./lib/CSSStyleDeclaration.js", "dependencies": { - "@asamuzakjp/css-color": "^2.5.0", + "@asamuzakjp/css-color": "^2.6.5", "rrweb-cssom": "^0.7.1" }, "devDependencies": { diff --git a/test/CSSStyleDeclaration.js b/test/CSSStyleDeclaration.js index 62f35d0..3fe57dd 100644 --- a/test/CSSStyleDeclaration.js +++ b/test/CSSStyleDeclaration.js @@ -748,4 +748,61 @@ describe('CSSStyleDeclaration', () => { assert.strictEqual(style.getPropertyValue(property), 'calc(100% - 100px)'); }); } + + it('supports nested calc', () => { + const style = new CSSStyleDeclaration(); + style.setProperty('width', 'calc(100% - calc(200px - 100px))'); + assert.strictEqual(style.getPropertyValue('width'), 'calc(100% - 100px)'); + }); + + it('supports nested calc', () => { + const style = new CSSStyleDeclaration(); + style.setProperty('width', 'calc(100% * calc(2 / 3))'); + assert.strictEqual(style.getPropertyValue('width'), 'calc(66.6667%)'); + }); + + it('supports var', () => { + const style = new CSSStyleDeclaration(); + style.setProperty('width', 'var(--foo)'); + assert.strictEqual(style.getPropertyValue('width'), 'var(--foo)'); + }); + + it('supports var with fallback', () => { + const style = new CSSStyleDeclaration(); + style.setProperty('width', 'var(--foo, 100px)'); + assert.strictEqual(style.getPropertyValue('width'), 'var(--foo, 100px)'); + }); + + it('supports var with var fallback', () => { + const style = new CSSStyleDeclaration(); + style.setProperty('width', 'var(--foo, var(--bar))'); + assert.strictEqual(style.getPropertyValue('width'), 'var(--foo, var(--bar))'); + }); + + it('supports calc with var inside', () => { + const style = new CSSStyleDeclaration(); + style.setProperty('width', 'calc(100% - var(--foo))'); + assert.strictEqual(style.getPropertyValue('width'), 'calc(100% - var(--foo))'); + }); + + it('supports var with calc inside', () => { + const style = new CSSStyleDeclaration(); + style.setProperty('width', 'var(--foo, calc(var(--bar) + 3px))'); + assert.strictEqual(style.getPropertyValue('width'), 'var(--foo, calc(var(--bar) + 3px))'); + }); + + it('supports color var', () => { + const style = new CSSStyleDeclaration(); + style.setProperty('color', 'var(--foo)'); + assert.strictEqual(style.getPropertyValue('color'), 'var(--foo)'); + }); + + it('should not normalize if var() is included', () => { + const style = new CSSStyleDeclaration(); + style.setProperty('width', 'calc( /* comment */ 100% - calc(var(--foo) *2 ))'); + assert.strictEqual( + style.getPropertyValue('width'), + 'calc( /* comment */ 100% - calc(var(--foo) *2 ))' + ); + }); }); diff --git a/test/parsers.js b/test/parsers.js index 4f0fa97..00a4049 100644 --- a/test/parsers.js +++ b/test/parsers.js @@ -74,7 +74,43 @@ describe('valueType', () => { assert.strictEqual(output, parsers.TYPES.CALC); }); + + it('returns calc from calc(100px * calc(2 * 1))', () => { + let input = 'calc(100px * calc(2 * 1))'; + let output = parsers.valueType(input); + + assert.strictEqual(output, parsers.TYPES.CALC); + }); + + it('returns calc from calc(100px * var(--foo))', () => { + let input = 'calc(100px * var(--foo))'; + let output = parsers.valueType(input); + + assert.strictEqual(output, parsers.TYPES.CALC); + }); + + it('returns var from var(--foo)', () => { + let input = 'var(--foo)'; + let output = parsers.valueType(input); + + assert.strictEqual(output, parsers.TYPES.KEYWORD); + }); + + it('returns var from var(--foo, var(--bar))', () => { + let input = 'var(--foo, var(--bar))'; + let output = parsers.valueType(input); + + assert.strictEqual(output, parsers.TYPES.KEYWORD); + }); + + it('returns var from var(--foo, calc(var(--bar) * 2))', () => { + let input = 'var(--foo, calc(var(--bar) * 2))'; + let output = parsers.valueType(input); + + assert.strictEqual(output, parsers.TYPES.KEYWORD); + }); }); + describe('parseInteger', () => { it.todo('test'); });