rn-css 1.9.1 → 1.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/cssToRN/index.js +13 -1
  2. package/dist/features.d.ts +16 -1
  3. package/dist/features.js +45 -1
  4. package/dist/index.d.ts +2720 -3
  5. package/dist/index.js +56 -172
  6. package/dist/styleComponent.d.ts +9 -2
  7. package/dist/styleComponent.js +30 -6
  8. package/dist/types.d.ts +2 -0
  9. package/package.json +2 -2
  10. package/src/features.tsx +4 -4
  11. package/src/styleComponent.tsx +13 -13
  12. package/dist/app.json +0 -4
  13. package/dist/src/convertStyle.d.ts +0 -5
  14. package/dist/src/convertStyle.js +0 -56
  15. package/dist/src/convertUnits.d.ts +0 -5
  16. package/dist/src/convertUnits.js +0 -71
  17. package/dist/src/cssToRN/convert.d.ts +0 -55
  18. package/dist/src/cssToRN/convert.js +0 -418
  19. package/dist/src/cssToRN/index.d.ts +0 -8
  20. package/dist/src/cssToRN/index.js +0 -140
  21. package/dist/src/cssToRN/maths.d.ts +0 -4
  22. package/dist/src/cssToRN/maths.js +0 -86
  23. package/dist/src/cssToRN/mediaQueries.d.ts +0 -7
  24. package/dist/src/cssToRN/mediaQueries.js +0 -161
  25. package/dist/src/features.d.ts +0 -43
  26. package/dist/src/features.js +0 -130
  27. package/dist/src/generateHash.d.ts +0 -2
  28. package/dist/src/generateHash.js +0 -8
  29. package/dist/src/index.d.ts +0 -2720
  30. package/dist/src/index.js +0 -60
  31. package/dist/src/polyfill.d.ts +0 -3
  32. package/dist/src/polyfill.js +0 -23
  33. package/dist/src/rnToCss.d.ts +0 -3
  34. package/dist/src/rnToCss.js +0 -8
  35. package/dist/src/styleComponent.d.ts +0 -50
  36. package/dist/src/styleComponent.js +0 -181
  37. package/dist/src/types.d.ts +0 -86
  38. package/dist/src/types.js +0 -2
  39. package/dist/src/useTheme.d.ts +0 -18
  40. package/dist/src/useTheme.js +0 -33
@@ -1,418 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.cornerValue = exports.sideValue = exports.font = exports.transform = exports.textDecoration = exports.background = exports.placeContent = exports.flexFlow = exports.flex = exports.shadow = exports.borderLike = exports.border = void 0;
4
- /**
5
- * Check if the value is a number. Numbers start with a digit, a decimal point or calc(, max( ou min(.
6
- * Optionally accept "auto" value (for margins)
7
- * @param value The value to check
8
- * @param acceptAuto true if auto is an accepted value
9
- * @returns true if the value is a number
10
- */
11
- function isNumber(value, acceptAuto) {
12
- if (acceptAuto && value === 'auto')
13
- return true;
14
- return value.match(/^[+-]?(\.\d|\d|calc\(|max\(|min\()/mg);
15
- }
16
- /**
17
- * Check if the value is a number. Numbers start with a digit, a decimal point or calc(, max( ou min(.
18
- * Optionally accept "auto" value (for margins)
19
- * @param value The value to check
20
- * @param acceptAuto true if auto is an accepted value
21
- * @returns true if the value is a number
22
- */
23
- /**
24
- * Split the value into numbers values and non numbers values
25
- * @param value The value to check
26
- * @param acceptAuto true if auto is an accepted value
27
- * @returns An object containing the number and non number values as arrays.
28
- */
29
- function findNumbers(value, acceptAuto) {
30
- const result = {
31
- nonNumbers: [],
32
- numbers: []
33
- };
34
- let group = '';
35
- value.split(/\s+/mg).forEach(val => {
36
- // HACK: we prevent some parts of font-family names like "Rounded Mplus 1c" to be interpreted as numbers
37
- if (val.startsWith('"') || val.startsWith("'"))
38
- group = val.charAt(0);
39
- if (group && val.endsWith(group))
40
- group = '';
41
- if (group)
42
- result.nonNumbers.push(val);
43
- else
44
- result[isNumber(val, acceptAuto) ? 'numbers' : 'nonNumbers'].push(val);
45
- });
46
- return result;
47
- }
48
- /** Parse a css value for border */
49
- function border(value) {
50
- const values = value.split(/\s+/mg);
51
- const result = {
52
- borderWidth: '0',
53
- borderColor: 'black',
54
- borderStyle: 'solid'
55
- };
56
- values.forEach((value) => {
57
- if (['solid', 'dotted', 'dashed'].includes(value))
58
- result.borderStyle = value;
59
- else if (isNumber(value))
60
- result.borderWidth = value;
61
- // eslint-disable-next-line no-useless-return
62
- else if (value === 'none')
63
- return;
64
- else
65
- result.borderColor = value;
66
- });
67
- return {
68
- ...sideValue('border', result.borderWidth, 'Width'),
69
- ...sideValue('border', result.borderColor, 'Color'),
70
- ...sideValue('border', result.borderStyle, 'Style')
71
- };
72
- }
73
- exports.border = border;
74
- /** Parse a css value for border-like elements */
75
- function borderLike(prefixKey, value) {
76
- const values = value.split(/\s+/mg);
77
- const result = {
78
- [prefixKey + 'Width']: '0',
79
- [prefixKey + 'Color']: 'black',
80
- [prefixKey + 'Style']: 'solid'
81
- };
82
- if (value === 'none')
83
- return result;
84
- values.forEach((value) => {
85
- if (['solid', 'dotted', 'dashed'].includes(value))
86
- result[prefixKey + 'Style'] = value;
87
- else if (isNumber(value))
88
- result[prefixKey + 'Width'] = value;
89
- else
90
- result[prefixKey + 'Color'] = value;
91
- });
92
- return result;
93
- }
94
- exports.borderLike = borderLike;
95
- function shadow(prefix, value) {
96
- if (value === 'none')
97
- return shadow(prefix, '0 0 0 black');
98
- const { nonNumbers, numbers } = findNumbers(value);
99
- return {
100
- [prefix + 'Offset']: { width: numbers[0] || '0', height: numbers[1] || '0' },
101
- [prefix + 'Radius']: numbers[2] || '0',
102
- [prefix + 'Color']: nonNumbers[0] || 'black'
103
- };
104
- }
105
- exports.shadow = shadow;
106
- function flex(value) {
107
- const [flexGrow, flexShrink = '0', flexBasis = '0'] = value.split(/\s/g);
108
- // If the only property is a not a number, its value is flexBasis. See https://developer.mozilla.org/en-US/docs/Web/CSS/flex
109
- if ((parseFloat(flexGrow) + '') !== flexGrow)
110
- return { flexBasis: flexGrow };
111
- // If the second property is not a number, its value is flexBasis.
112
- if (((parseFloat(flexShrink) + '') !== flexShrink))
113
- return { flexGrow, flexBasis: flexShrink };
114
- return {
115
- flexGrow, flexShrink, flexBasis
116
- };
117
- }
118
- exports.flex = flex;
119
- function flexFlow(value) {
120
- const values = value.split(/\s/g);
121
- const result = {};
122
- values.forEach(val => {
123
- if (['wrap', 'nowrap', 'wrap-reverse'].includes(val))
124
- result.flexWrap = val;
125
- else if (['row', 'column', 'row-reverse', 'column-reverse'].includes(val))
126
- result.flexDirection = val;
127
- });
128
- return result;
129
- }
130
- exports.flexFlow = flexFlow;
131
- function placeContent(value) {
132
- const [alignContent, justifyContent = alignContent] = value.split(/\s/g);
133
- return { alignContent, justifyContent };
134
- }
135
- exports.placeContent = placeContent;
136
- function background(value) {
137
- const values = value.split(/\s+/mg);
138
- const color = values.pop();
139
- // The background-color is the only one that we support and it's the last value
140
- return { backgroundColor: isColor(color) ? color : 'transparent' };
141
- }
142
- exports.background = background;
143
- function textDecoration(value) {
144
- const values = value.split(/\s+/mg);
145
- const result = {
146
- textDecorationLine: 'none',
147
- textDecorationStyle: 'solid',
148
- textDecorationColor: 'black'
149
- };
150
- values.forEach(value => {
151
- if (['none', 'solid', 'double', 'dotted', 'dashed'].includes(value))
152
- result.textDecorationStyle = value;
153
- else if (['none', 'underline', 'line-through'].includes(value)) {
154
- // To accept 'underline line-throught' as a value, we need to concatenate
155
- if (result.textDecorationLine !== 'none')
156
- result.textDecorationLine += ' ' + value;
157
- else
158
- result.textDecorationLine = value;
159
- }
160
- else
161
- result.textDecorationColor = value;
162
- });
163
- return result;
164
- }
165
- exports.textDecoration = textDecoration;
166
- function read2D(prefix, value) {
167
- const [x, y = x] = value.split(',').map(val => val.trim());
168
- return [
169
- { [prefix + 'X']: x },
170
- { [prefix + 'Y']: y }
171
- ];
172
- }
173
- function read3D(prefix, value) {
174
- const [x, y, z] = value.split(',').map(val => val.trim());
175
- const transform = [];
176
- if (x)
177
- transform.push({ [prefix + 'X']: x });
178
- if (y)
179
- transform.push({ [prefix + 'Y']: y });
180
- if (z)
181
- transform.push({ [prefix + 'Z']: z });
182
- return transform;
183
- }
184
- function transform(value) {
185
- // Parse transform operations
186
- const transform = [...value.matchAll(/(\w+)\((.*?)\)/gm)].reduce((acc, val) => {
187
- const operation = val[1];
188
- const values = val[2].trim();
189
- if (['translate', 'scale', 'skew'].includes(operation))
190
- return acc.concat(read2D(operation, values));
191
- else if (operation === 'rotate3d')
192
- return acc.concat(read3D('rotate', values));
193
- else
194
- return acc.concat({ [operation]: values });
195
- }, []);
196
- return { transform };
197
- }
198
- exports.transform = transform;
199
- function font(value) {
200
- const { nonNumbers, numbers } = findNumbers(value);
201
- const result = {
202
- fontStyle: 'normal',
203
- fontWeight: 'normal'
204
- };
205
- for (let i = 0; i < nonNumbers.length; i++) {
206
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
207
- const val = nonNumbers.shift();
208
- if (val === 'italic')
209
- result.fontStyle = val;
210
- else if (val === 'bold')
211
- result.fontWeight = val;
212
- else if (val === 'normal')
213
- continue; // can be both fontStyle or fontWeight, but as it is the default we can just ignore.
214
- else if (['small-caps', 'oldstyle-nums', 'lining-nums', 'tabular-nums', 'proportional-nums'].includes(val))
215
- result.fontVariant = val;
216
- else {
217
- nonNumbers.unshift(val);
218
- break;
219
- }
220
- }
221
- // The font family is the last property and can contain spaces
222
- if (nonNumbers.length > 0)
223
- result.fontFamily = nonNumbers.join(' ');
224
- // The font size is always defined and is the last number
225
- const size = numbers.pop();
226
- if (!size)
227
- return result;
228
- const [fontSize, lineHeight] = size.split('/'); // We can define the line height like this : fontSize/lineHeight
229
- result.fontSize = fontSize;
230
- if (lineHeight)
231
- result.lineHeight = lineHeight;
232
- // The font size is always after the font weight
233
- if (numbers.length)
234
- result.fontWeight = numbers[0];
235
- return result;
236
- }
237
- exports.font = font;
238
- /** Parses a css value for the side of an element (border-width, margin, padding) */
239
- function sideValue(prefixKey, value, postFix = '') {
240
- if (value === 'none')
241
- return sideValue(prefixKey, '0', postFix);
242
- const [top = value, right = top, bottom = top, left = right] = findNumbers(value, prefixKey === 'margin').numbers;
243
- return {
244
- [prefixKey + 'Top' + postFix]: top,
245
- [prefixKey + 'Left' + postFix]: left,
246
- [prefixKey + 'Right' + postFix]: right,
247
- [prefixKey + 'Bottom' + postFix]: bottom
248
- };
249
- }
250
- exports.sideValue = sideValue;
251
- /** Parses a css value for the corner of an element (border-radius) */
252
- function cornerValue(prefixKey, value, postFix) {
253
- const [topLeft, topRight = topLeft, bottomRight = topLeft, bottomLeft = topRight] = findNumbers(value).numbers;
254
- return {
255
- [prefixKey + 'TopLeft' + postFix]: topLeft,
256
- [prefixKey + 'TopRight' + postFix]: topRight,
257
- [prefixKey + 'BottomLeft' + postFix]: bottomLeft,
258
- [prefixKey + 'BottomRight' + postFix]: bottomRight
259
- };
260
- }
261
- exports.cornerValue = cornerValue;
262
- function isColor(value) {
263
- if (!value)
264
- return false;
265
- if (value.startsWith('#') || value.startsWith('rgb') || value.startsWith('hsl'))
266
- return true;
267
- const CSS_COLOR_NAMES = [
268
- 'aliceblue',
269
- 'antiquewhite',
270
- 'aqua',
271
- 'aquamarine',
272
- 'azure',
273
- 'beige',
274
- 'bisque',
275
- 'black',
276
- 'blanchedalmond',
277
- 'blue',
278
- 'blueviolet',
279
- 'brown',
280
- 'burlywood',
281
- 'cadetblue',
282
- 'chartreuse',
283
- 'chocolate',
284
- 'coral',
285
- 'cornflowerblue',
286
- 'cornsilk',
287
- 'crimson',
288
- 'cyan',
289
- 'darkblue',
290
- 'darkcyan',
291
- 'darkgoldenrod',
292
- 'darkgray',
293
- 'darkgrey',
294
- 'darkgreen',
295
- 'darkkhaki',
296
- 'darkmagenta',
297
- 'darkolivegreen',
298
- 'darkorange',
299
- 'darkorchid',
300
- 'darkred',
301
- 'darksalmon',
302
- 'darkseagreen',
303
- 'darkslateblue',
304
- 'darkslategray',
305
- 'darkslategrey',
306
- 'darkturquoise',
307
- 'darkviolet',
308
- 'deeppink',
309
- 'deepskyblue',
310
- 'dimgray',
311
- 'dimgrey',
312
- 'dodgerblue',
313
- 'firebrick',
314
- 'floralwhite',
315
- 'forestgreen',
316
- 'fuchsia',
317
- 'gainsboro',
318
- 'ghostwhite',
319
- 'gold',
320
- 'goldenrod',
321
- 'gray',
322
- 'grey',
323
- 'green',
324
- 'greenyellow',
325
- 'honeydew',
326
- 'hotpink',
327
- 'indianred',
328
- 'indigo',
329
- 'ivory',
330
- 'khaki',
331
- 'lavender',
332
- 'lavenderblush',
333
- 'lawngreen',
334
- 'lemonchiffon',
335
- 'lightblue',
336
- 'lightcoral',
337
- 'lightcyan',
338
- 'lightgoldenrodyellow',
339
- 'lightgray',
340
- 'lightgrey',
341
- 'lightgreen',
342
- 'lightpink',
343
- 'lightsalmon',
344
- 'lightseagreen',
345
- 'lightskyblue',
346
- 'lightslategray',
347
- 'lightslategrey',
348
- 'lightsteelblue',
349
- 'lightyellow',
350
- 'lime',
351
- 'limegreen',
352
- 'linen',
353
- 'magenta',
354
- 'maroon',
355
- 'mediumaquamarine',
356
- 'mediumblue',
357
- 'mediumorchid',
358
- 'mediumpurple',
359
- 'mediumseagreen',
360
- 'mediumslateblue',
361
- 'mediumspringgreen',
362
- 'mediumturquoise',
363
- 'mediumvioletred',
364
- 'midnightblue',
365
- 'mintcream',
366
- 'mistyrose',
367
- 'moccasin',
368
- 'navajowhite',
369
- 'navy',
370
- 'oldlace',
371
- 'olive',
372
- 'olivedrab',
373
- 'orange',
374
- 'orangered',
375
- 'orchid',
376
- 'palegoldenrod',
377
- 'palegreen',
378
- 'paleturquoise',
379
- 'palevioletred',
380
- 'papayawhip',
381
- 'peachpuff',
382
- 'peru',
383
- 'pink',
384
- 'plum',
385
- 'powderblue',
386
- 'purple',
387
- 'rebeccapurple',
388
- 'red',
389
- 'rosybrown',
390
- 'royalblue',
391
- 'saddlebrown',
392
- 'salmon',
393
- 'sandybrown',
394
- 'seagreen',
395
- 'seashell',
396
- 'sienna',
397
- 'silver',
398
- 'skyblue',
399
- 'slateblue',
400
- 'slategray',
401
- 'slategrey',
402
- 'snow',
403
- 'springgreen',
404
- 'steelblue',
405
- 'tan',
406
- 'teal',
407
- 'thistle',
408
- 'tomato',
409
- 'turquoise',
410
- 'violet',
411
- 'wheat',
412
- 'white',
413
- 'whitesmoke',
414
- 'yellow',
415
- 'yellowgreen'
416
- ];
417
- return CSS_COLOR_NAMES.includes(value);
418
- }
@@ -1,8 +0,0 @@
1
- import { CompleteStyle, Style } from '../types';
2
- declare function cssToStyle(css: string): Style;
3
- export declare function cssToRNStyle(css: string, units?: {
4
- em?: number;
5
- width?: number;
6
- height?: number;
7
- }): CompleteStyle;
8
- export default cssToStyle;
@@ -1,140 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.cssToRNStyle = void 0;
7
- const react_native_1 = require("react-native");
8
- const convertStyle_1 = __importDefault(require("../convertStyle"));
9
- const convert_1 = require("./convert");
10
- const mediaQueries_1 = require("./mediaQueries");
11
- function kebab2camel(string) {
12
- return string.replace(/-./g, x => x.toUpperCase()[1]);
13
- }
14
- function stripSpaces(string) {
15
- return string.replace(/(calc|max|min|rgb|rgba)\(.*?\)/mg, res => res.replace(/\s/g, ''));
16
- }
17
- function cssToStyle(css) {
18
- const result = {};
19
- // Find media queries (We use [\s\S] instead of . because dotall flag (s) is not supported by react-native-windows)
20
- const cssWithoutMediaQueries = css.replace(/@media([\s\S]*?){[^{}]*}/gmi, res => {
21
- const { css, isValid } = (0, mediaQueries_1.createMedia)(res);
22
- const style = cssChunkToStyle(css);
23
- const mediaQuery = (context) => isValid(context) && style;
24
- if (!result.media)
25
- result.media = [];
26
- result.media.push(mediaQuery);
27
- return '';
28
- });
29
- // Find hover (we don't support hover within media queries) (We use [\s\S] instead of . because dotall flag (s) is not supported by react-native-windows)
30
- const cssWithoutHover = cssWithoutMediaQueries.replace(/&:hover\s*{([\s\S]*?)}/gmi, res => {
31
- const hoverInstructions = res.substring(0, res.length - 1).replace(/&:hover\s*{/mi, ''); // We remove the `&:hover {` and `}`
32
- result.hover = cssChunkToStyle(hoverInstructions);
33
- return '';
34
- });
35
- // Find active (we don't support active within media queries) (We use [\s\S] instead of . because dotall flag (s) is not supported by react-native-windows)
36
- const cssWithoutActive = cssWithoutHover.replace(/&:active\s*{([\s\S]*?)}/gmi, res => {
37
- const activeInstructions = res.substring(0, res.length - 1).replace(/&:active\s*{/mi, ''); // We remove the `&:active {` and `}`
38
- result.active = cssChunkToStyle(activeInstructions);
39
- return '';
40
- });
41
- // Find focus (we don't support focus within media queries) (We use [\s\S] instead of . because dotall flag (s) is not supported by react-native-windows)
42
- const cssWithoutFocus = cssWithoutActive.replace(/&:focus\s*{([\s\S]*?)}/gmi, res => {
43
- const activeInstructions = res.substring(0, res.length - 1).replace(/&:focus\s*{/mi, ''); // We remove the `&:focus {` and `}`
44
- result.focus = cssChunkToStyle(activeInstructions);
45
- return '';
46
- });
47
- Object.assign(result, cssChunkToStyle(cssWithoutFocus));
48
- return result;
49
- }
50
- function cssToRNStyle(css, units = {}) {
51
- const { width, height } = react_native_1.Dimensions.get('window');
52
- const finalUnits = {
53
- em: 16,
54
- '%': 0.01,
55
- vw: width / 100,
56
- vh: height / 100,
57
- vmin: Math.min(width, height) / 100,
58
- vmax: Math.max(width, height) / 100,
59
- width: 100,
60
- height: 100,
61
- rem: 16,
62
- px: 1,
63
- pt: 96 / 72,
64
- in: 96,
65
- pc: 16,
66
- cm: 96 / 2.54,
67
- mm: 96 / 25.4,
68
- ...units
69
- };
70
- const rnStyle = cssChunkToStyle(css);
71
- return (0, convertStyle_1.default)(rnStyle, finalUnits);
72
- }
73
- exports.cssToRNStyle = cssToRNStyle;
74
- function cssChunkToStyle(css) {
75
- const result = {};
76
- css.split(/\s*;\s*(?!base64)/mg).forEach((entry) => {
77
- const [rawKey, ...rest] = entry.split(':');
78
- const rawValue = rest.join(':');
79
- if (!rawValue)
80
- return;
81
- const key = kebab2camel(rawKey.trim());
82
- const value = stripSpaces(rawValue.trim()); // We need this to correctly read calc() values
83
- switch (key) {
84
- case 'border':
85
- Object.assign(result, (0, convert_1.border)(value));
86
- break;
87
- case 'borderTop':
88
- case 'borderLeft':
89
- case 'borderRight':
90
- case 'borderBottom':
91
- case 'outline':
92
- Object.assign(result, (0, convert_1.borderLike)(key, value));
93
- break;
94
- case 'borderStyle':
95
- case 'borderColor':
96
- case 'borderWidth':
97
- Object.assign(result, (0, convert_1.sideValue)('border', value, key.split('border').pop()));
98
- break;
99
- case 'background':
100
- Object.assign(result, (0, convert_1.background)(value));
101
- break;
102
- case 'padding':
103
- case 'margin':
104
- Object.assign(result, (0, convert_1.sideValue)(key, value));
105
- break;
106
- case 'borderRadius':
107
- Object.assign(result, (0, convert_1.cornerValue)('border', value, 'Radius'));
108
- break;
109
- case 'font':
110
- Object.assign(result, (0, convert_1.font)(value));
111
- break;
112
- case 'textDecoration':
113
- Object.assign(result, (0, convert_1.textDecoration)(value));
114
- break;
115
- case 'placeContent':
116
- Object.assign(result, (0, convert_1.placeContent)(value));
117
- break;
118
- case 'flex':
119
- Object.assign(result, (0, convert_1.flex)(value));
120
- break;
121
- case 'flexFlow':
122
- Object.assign(result, (0, convert_1.flexFlow)(value));
123
- break;
124
- case 'transform':
125
- Object.assign(result, (0, convert_1.transform)(value));
126
- break;
127
- case 'boxShadow':
128
- case 'textShadow':
129
- // We need to replace boxShadow by shadow
130
- Object.assign(result, (0, convert_1.shadow)(key === 'boxShadow' ? 'shadow' : key, value));
131
- break;
132
- // Other keys don't require any special treatment
133
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
134
- // @ts-ignore
135
- default: result[key] = value;
136
- }
137
- });
138
- return result;
139
- }
140
- exports.default = cssToStyle;
@@ -1,4 +0,0 @@
1
- /** Evaluate the string operation without relying on eval */
2
- export declare function calculate(string: string): number;
3
- export declare function min(string: string): number;
4
- export declare function max(string: string): number;
@@ -1,86 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.max = exports.min = exports.calculate = void 0;
4
- /** Evaluate the string operation without relying on eval */
5
- function calculate(string) {
6
- function applyOperator(left, op, right) {
7
- if (op === '+')
8
- return left + right;
9
- else if (op === '-')
10
- return left - right;
11
- else if (op === '*')
12
- return left * right;
13
- else if (op === '/')
14
- return left / right;
15
- else
16
- return right || left;
17
- }
18
- function evaluate(root) {
19
- switch (root.type) {
20
- case 'group': return evaluate(root.right);
21
- case 'additive':
22
- case 'multiplicative':
23
- return applyOperator(evaluate(root.left), root.operation, evaluate(root.right));
24
- case 'number': return parseFloat(root.value);
25
- }
26
- }
27
- const rootNode = { type: 'group' };
28
- let currentNode = rootNode;
29
- function openGroup() {
30
- const newGroup = { type: 'group', parent: currentNode };
31
- currentNode.right = newGroup;
32
- currentNode = newGroup;
33
- }
34
- function closeGroup() {
35
- while (currentNode.type !== 'group')
36
- currentNode = currentNode.parent;
37
- currentNode = currentNode.parent;
38
- }
39
- function addNumber(char) {
40
- const currentNumber = currentNode.right;
41
- if (currentNumber === undefined)
42
- currentNode.right = { type: 'number', value: char };
43
- else
44
- currentNumber.value += char;
45
- }
46
- function addOperator(char) {
47
- const additive = '+-'.includes(char);
48
- const priority = additive ? 1 : 2;
49
- // If it is a sign and not an operation, we add it to the comming number
50
- if (additive && !currentNode.right)
51
- return addNumber(char);
52
- while (currentNode.priority && (currentNode.priority >= priority))
53
- currentNode = currentNode.parent;
54
- const operator = {
55
- type: additive ? 'additive' : 'multiplicative',
56
- priority,
57
- parent: currentNode,
58
- operation: char,
59
- left: currentNode.right
60
- };
61
- currentNode.right = operator;
62
- currentNode = operator;
63
- }
64
- string.split('').forEach(char => {
65
- if (char === '(')
66
- openGroup();
67
- else if (char === ')')
68
- closeGroup();
69
- else if ('0123456789.'.includes(char))
70
- addNumber(char);
71
- else if ('+*-/'.includes(char))
72
- addOperator(char);
73
- });
74
- return evaluate(rootNode);
75
- }
76
- exports.calculate = calculate;
77
- function min(string) {
78
- const values = string.split(',').map(val => parseFloat(val.trim()));
79
- return Math.min(...values);
80
- }
81
- exports.min = min;
82
- function max(string) {
83
- const values = string.split(',').map(val => parseFloat(val.trim()));
84
- return Math.max(...values);
85
- }
86
- exports.max = max;
@@ -1,7 +0,0 @@
1
- import type { Units, Context } from '../types';
2
- export declare function createContext(units: Units): Context;
3
- export declare type Evaluation = (context: Context) => boolean;
4
- export declare const createMedia: (query: string) => {
5
- css: string;
6
- isValid: Evaluation;
7
- };