1- import { isNumber } from '@react-universal/utils' ;
1+ import { isNumber , isString } from '@react-universal/utils' ;
22import { isWeb } from '@tamagui/constants' ;
33import { parseRem } from './utils/parseRem' ;
44
55type Operand = string | number | { toString : ( ) => string } ;
66
7+ const operators = {
8+ '+' : ( a : number , b : number ) : number => a + b ,
9+ '-' : ( a : number , b : number ) : number => a - b ,
10+ '/' : ( a : number , b : number ) : number => a / b ,
11+ '*' : ( a : number , b : number ) : number => a * b ,
12+ } ;
13+
14+ type Operator = keyof typeof operators ;
15+
716function parsePx ( value : Operand ) {
817 return isNumber ( value ) ? `${ value } px` : value . toString ( ) ;
918}
@@ -25,3 +34,33 @@ export function clamp(min: Operand, value: Operand, max: Operand) {
2534 ? `clamp(${ parsePx ( min ) } ,${ parsePx ( value ) } ,${ parsePx ( max ) } )`
2635 : Math . min ( Math . max ( parseRem ( value ) , parseRem ( min ) ) , parseRem ( max ) ) ;
2736}
37+
38+ export function calc ( ...valuesAndOperators : ( Operand | Operator ) [ ] ) : string | number {
39+ if ( isWeb ) {
40+ let result = 'calc(' ;
41+ for ( const value of valuesAndOperators ) {
42+ if ( isString ( value ) && value in operators ) {
43+ result += ` ${ value } ` ; // spaces are significant
44+ } else {
45+ result += parsePx ( value ) ;
46+ }
47+ }
48+ return `${ result } )` ;
49+ }
50+
51+ let result = 0 ;
52+ let operator : ( ( a : number , b : number ) => number ) | undefined ;
53+
54+ for ( const value of valuesAndOperators ) {
55+ if ( isString ( value ) && value in operators ) {
56+ operator = operators [ value as Operator ] ;
57+ } else if ( operator ) {
58+ result = operator ( result , parseRem ( value ) ) ;
59+ operator = undefined ;
60+ } else {
61+ result = parseRem ( value ) ;
62+ }
63+ }
64+
65+ return result ;
66+ }
0 commit comments