-
Notifications
You must be signed in to change notification settings - Fork 28
/
transforms.js
130 lines (115 loc) · 3.75 KB
/
transforms.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import get from './get';
import toCSSVariable from './toCSSVariable';
// Check if a value is a simple CSS variable
// e.g. var(--tonic-spacing-1)
const isSimpleCSSVariable = (value) => {
const re = /^var\(\s*([a-zA-Z0-9\-_]+)\s*\)$/;
return re.test(String(value ?? '').trim());
};
// Negate the value, handling CSS variables and numeric values
const toNegativeValue = (scale, absoluteValue, options) => {
const theme = options?.props?.theme;
const useCSSVariables = !!(theme?.config?.useCSSVariables); // defaults to false
const n = getter(scale, absoluteValue, options);
// Handle CSS variables for negative values
if (useCSSVariables && isSimpleCSSVariable(n)) {
// https://stackoverflow.com/questions/49469344/using-negative-css-custom-properties
return `calc(0px - ${n})`;
}
// Handle numeric value
if (typeof n === 'number' && Number.isFinite(n)) {
return n * -1;
}
return `-${n}`;
};
export const getter = (scale, value, options) => {
const theme = options?.props?.theme;
const prefix = theme?.config?.prefix; // defaults to 'tonic'
const useCSSVariables = !!(theme?.config?.useCSSVariables); // defaults to false
const result = get(scale, value);
if (result !== undefined && useCSSVariables) {
const contextScale = options?.context?.scale;
const cssVariable = toCSSVariable(
// | contextScale | value |
// | ------------ | --------- |
// | colors | 'blue:50' |
// | space | 0 |
[contextScale, String(value ?? '')].filter(Boolean).join('.'), // => 'colors.blue:50'
{ prefix, delimiter: '-' },
); // => '--tonic-colors-blue-50'
const cssVariableValue = theme?.__cssVariableMap?.[cssVariable]; // => '#578aef'
if (cssVariableValue !== undefined) {
// => Replace '#578aef' with 'var(--tonic-colors-blue-50)'
return String(result ?? '').replaceAll(cssVariableValue, `var(${cssVariable})`);
}
// fallback to the original value
}
return result ?? value; // fallback to value if result is null or undefined
};
export const positiveOrNegative = (scale, value, options) => {
/**
* Scale object
*
* ```js
* {
* '1x': '0.25rem',
* '2x': 8,
* }
* ```
*
* Example
*
* ```jsx
* <Box margin="1x" />
* // => margin: 0.25rem
* <Box margin="2x" />
* // => margin: 8px
* <Box margin="-1x" />
* // => margin: -0.25rem
* <Box margin="-2x" />
* // => margin: -8px
* ```
*/
if (typeof value === 'string') {
const absoluteValue = (value.startsWith('+') || value.startsWith('-')) ? value.slice(1) : value;
const isNonNegative = !value.startsWith('-');
// Return the result if the value is non-negative or if the scale object does not contain the absolute value
if (isNonNegative || !Object.prototype.hasOwnProperty.call(scale, absoluteValue)) {
return getter(scale, value, options);
}
return toNegativeValue(scale, absoluteValue, options);
}
/**
* Scale object
*
* ```js
* {
* 4: '0.25rem',
* 8: 8,
* }
* ```
*
* Example
*
* ```jsx
* <Box margin={4} />
* // => margin: 0.25rem
* <Box margin={8} />
* // => margin: 8px
* <Box margin={-4} />
* // => margin: -0.25rem
* <Box margin={-8} />
* // => margin: -8px
* ```
*/
if (typeof value === 'number' && Number.isFinite(value)) {
const absoluteValue = Math.abs(value);
const isNonNegative = !(value < 0);
// Return the result if the value is non-negative or if the scale object does not contain the absolute value
if (isNonNegative || !Object.prototype.hasOwnProperty.call(scale, absoluteValue)) {
return getter(scale, value, options);
}
return toNegativeValue(scale, absoluteValue, options);
}
return getter(scale, value, options);
};