From 95e33cf0f105c204e2165d87df37e613c9f3b955 Mon Sep 17 00:00:00 2001 From: "asamuzaK (Kazz)" Date: Sat, 8 Aug 2026 08:01:55 +0900 Subject: [PATCH] Fix min/max functions in calc expressions Add proper handling for CSS functions like min(), max(), and clamp() that contain commas as argument separators. These functions should not be sorted or treated like arithmetic operators. The fix checks for comma presence and detects function patterns beyond calc(), and normalizes comma spacing in the output. --- src/js/css-calc-var.ts | 19 ++++++++++++------- test/css-calc-var.test.ts | 14 ++++++++++++++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/js/css-calc-var.ts b/src/js/css-calc-var.ts index 219c905..2eb2bd4 100644 --- a/src/js/css-calc-var.ts +++ b/src/js/css-calc-var.ts @@ -713,21 +713,24 @@ const resolveNode = (node: CalcASTNode[], isRoot: boolean): string => { flatItems.push(item); } } + const hasComma = flatItems.includes(','); if (isRoot) { - if (flatItems.length >= TRIA) { + if (flatItems.length >= TRIA && !hasComma) { return sortCalcValues(flatItems, true); } - const joined = flatItems.join(''); - return joined.startsWith('calc(') ? joined : `calc(${joined})`; + const joined = flatItems.join('').replace(/,\s*/g, ', '); + return joined.startsWith('calc(') || /^[a-z-]+\(/.test(joined) + ? joined + : `calc(${joined})`; } - if (flatItems.length >= TRIA) { + if (flatItems.length >= TRIA && !hasComma) { let serialized = sortCalcValues(flatItems, false); if (REG_FN_VAR_START.test(serialized)) { serialized = calc(serialized, { toCanonicalUnits: true }); } return serialized; } - return flatItems.join(''); + return flatItems.join('').replace(/,\s*/g, ', '); }; /** @@ -810,12 +813,14 @@ export const serializeCalc = (value: string, opt: Options = {}): string => { flatItems.push(item); } } - if (flatItems.length >= TRIA) { + const hasComma = flatItems.includes(','); + if (flatItems.length >= TRIA && !hasComma) { serializedCalc = sortCalcValues(flatItems, true); } else { const firstItem = flatItems[0] || ''; serializedCalc = - isString(firstItem) && firstItem.startsWith('calc(') + isString(firstItem) && + (firstItem.startsWith('calc(') || /^[a-z-]+\(/.test(firstItem)) ? firstItem : `calc(${firstItem})`; } diff --git a/test/css-calc-var.test.ts b/test/css-calc-var.test.ts index 0c57110..7660656 100644 --- a/test/css-calc-var.test.ts +++ b/test/css-calc-var.test.ts @@ -1781,6 +1781,20 @@ describe('CSS calc()', () => { }); assert.strictEqual(res2, 'calc(0.666667)', 'result'); }); + + it('should get value', () => { + const res = func('min(180px, calc(80vw - 24px))', { + format: 'specifiedValue' + }); + assert.strictEqual(res, 'min(180px, calc(80vw - 24px))', 'result'); + }); + + it('should get value', () => { + const res = func('max(10px, calc(1vw + 1px))', { + format: 'specifiedValue' + }); + assert.strictEqual(res, 'max(10px, calc(1vw + 1px))', 'result'); + }); }); describe('serialize calc edge cases', () => {