@stylexjs/stylex 0.2.0-beta.20 → 0.2.0-beta.21

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.
@@ -4,22 +4,24 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.CSSCustomPropertyValue = void 0;
7
- exports.isCustomPropertyValue = isCustomPropertyValue;
8
- const CUSTOM_PROPERTY_REGEX = /^var\(--(.+)\)$/;
7
+ exports.createCSSCustomPropertyValue = createCSSCustomPropertyValue;
8
+ const CUSTOM_PROPERTY_REGEX = /^var\(--([\w-]+) *(?:\)|, *(.+)\))$/;
9
9
  function camelize(s) {
10
10
  return s.replace(/-./g, x => x.toUpperCase()[1]);
11
11
  }
12
- function isCustomPropertyValue(value) {
13
- return typeof value === "string" && CUSTOM_PROPERTY_REGEX.test(value);
12
+ function createCSSCustomPropertyValue(value) {
13
+ if (typeof value === "string") {
14
+ const match = CUSTOM_PROPERTY_REGEX.exec(value);
15
+ if (match) {
16
+ return new CSSCustomPropertyValue(match[1], match[2]);
17
+ }
18
+ }
19
+ return null;
14
20
  }
15
21
  class CSSCustomPropertyValue {
16
- constructor(value) {
17
- const found = value.match(CUSTOM_PROPERTY_REGEX);
18
- if (found == null) {
19
- throw new Error("[stylex]: Unable to find custom property reference in input string");
20
- }
21
- const [, kebabCasePropName] = found;
22
+ constructor(kebabCasePropName, fallback) {
22
23
  this.name = camelize(kebabCasePropName);
24
+ this.defaultValue = fallback ?? null;
23
25
  }
24
26
  }
25
27
  exports.CSSCustomPropertyValue = CSSCustomPropertyValue;
@@ -7,9 +7,21 @@
7
7
  * @flow strict
8
8
  */
9
9
 
10
- declare export function isCustomPropertyValue(value: mixed): boolean;
10
+ /**
11
+ * Either create a custom property value or return null if the input is not a string
12
+ * containing a 'var(--name)' or 'var(--name, default)' sequence.
13
+ *
14
+ * Made this a single function to test and create to avoid parsing the RegExp twice.
15
+ */
16
+ declare export function createCSSCustomPropertyValue(
17
+ value: string,
18
+ ): CSSCustomPropertyValue | null;
11
19
 
20
+ /**
21
+ * Class representing a custom property value with an optional fallback.
22
+ */
12
23
  declare export class CSSCustomPropertyValue {
13
24
  name: string;
14
- constructor(value: string): void;
25
+ defaultValue: mixed;
26
+ constructor(kebabCasePropName: string, fallback: mixed): void;
15
27
  }
@@ -7,16 +7,12 @@
7
7
  *
8
8
  */
9
9
 
10
+ import type { SpreadOptions } from './SpreadOptions';
10
11
  type CSSLengthUnitType = 'em' | 'px' | 'rem' | 'vh' | 'vmax' | 'vmin' | 'vw';
11
12
  export declare class CSSLengthUnitValue {
12
13
  static parse(inp: string): [number, CSSLengthUnitType] | null;
13
14
  value: number;
14
15
  unit: CSSLengthUnitType;
15
16
  constructor(value: number, unit: CSSLengthUnitType);
16
- resolvePixelValue(
17
- viewportWidth: number,
18
- viewportHeight: number,
19
- fontScale: number,
20
- inheritedFontSize: null | undefined | number,
21
- ): number;
17
+ resolvePixelValue(options: SpreadOptions): number;
22
18
  }
@@ -19,7 +19,13 @@ class CSSLengthUnitValue {
19
19
  this.value = value;
20
20
  this.unit = unit;
21
21
  }
22
- resolvePixelValue(viewportWidth, viewportHeight, fontScale, inheritedFontSize) {
22
+ resolvePixelValue(options) {
23
+ const {
24
+ viewportWidth,
25
+ viewportHeight,
26
+ fontScale = 1,
27
+ inheritedFontSize
28
+ } = options;
23
29
  const unit = this.unit;
24
30
  const value = this.value;
25
31
  const valuePercent = value / 100;
@@ -7,6 +7,8 @@
7
7
  * @flow strict
8
8
  */
9
9
 
10
+ import type { SpreadOptions } from './SpreadOptions';
11
+
10
12
  type CSSLengthUnitType = 'em' | 'px' | 'rem' | 'vh' | 'vmax' | 'vmin' | 'vw';
11
13
 
12
14
  // TODO: this only works on simple values
@@ -15,10 +17,5 @@ declare export class CSSLengthUnitValue {
15
17
  value: number;
16
18
  unit: CSSLengthUnitType;
17
19
  constructor(value: number, unit: CSSLengthUnitType): void;
18
- resolvePixelValue(
19
- viewportWidth: number,
20
- viewportHeight: number,
21
- fontScale: number,
22
- inheritedFontSize: ?number,
23
- ): number;
20
+ resolvePixelValue(options: SpreadOptions): number;
24
21
  }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ *
8
+ */
9
+
10
+ export type SpreadOptions = {
11
+ customProperties: {};
12
+ inheritedFontSize: null | undefined | number;
13
+ fontScale: number | void;
14
+ passthroughProperties: Array<string>;
15
+ viewportHeight: number;
16
+ viewportWidth: number;
17
+ writingDirection: 'ltr' | 'rtl';
18
+ };
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow strict
8
+ */
9
+
10
+ export type SpreadOptions = {|
11
+ customProperties: {},
12
+ inheritedFontSize: ?number,
13
+ fontScale: number | void,
14
+ passthroughProperties: Array<string>,
15
+ viewportHeight: number,
16
+ viewportWidth: number,
17
+ writingDirection: 'ltr' | 'rtl',
18
+ |};
@@ -0,0 +1,48 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`stylex CSSCustomProperty value test falls back to a default value with spaces 1`] = `
4
+ {
5
+ "style": {
6
+ "shadowColor": "0px 0px 0px black",
7
+ "shadowOffset": {
8
+ "height": undefined,
9
+ "width": undefined,
10
+ },
11
+ "shadowOpacity": 1,
12
+ },
13
+ }
14
+ `;
15
+
16
+ exports[`stylex CSSCustomProperty value test parses a variable with a default value with spaces 1`] = `
17
+ {
18
+ "style": {
19
+ "shadowColor": "5px 5px 5px black",
20
+ "shadowOffset": {
21
+ "height": undefined,
22
+ "width": undefined,
23
+ },
24
+ "shadowOpacity": 1,
25
+ },
26
+ }
27
+ `;
28
+
29
+ exports[`stylex CSSCustomProperty value test parses and falls back to a default value containing spaces and embedded variables 1`] = `
30
+ {
31
+ "style": {
32
+ "shadowColor": "var(--boxShadowVarNotFound",
33
+ "shadowOffset": {
34
+ "height": undefined,
35
+ "width": undefined,
36
+ },
37
+ "shadowOpacity": 1,
38
+ },
39
+ }
40
+ `;
41
+
42
+ exports[`stylex CSSCustomProperty value test parses and falls back to default value containing a variable 1`] = `
43
+ {
44
+ "style": {
45
+ "color": "blue",
46
+ },
47
+ }
48
+ `;
@@ -594,6 +594,17 @@ exports[`styles box-sizing: content-box: allDifferent 1`] = `
594
594
  }
595
595
  `;
596
596
 
597
+ exports[`styles box-sizing: content-box: auto 1`] = `
598
+ {
599
+ "style": {
600
+ "borderWidth": 2,
601
+ "height": 74,
602
+ "padding": 10,
603
+ "width": "auto",
604
+ },
605
+ }
606
+ `;
607
+
597
608
  exports[`styles box-sizing: content-box: height 1`] = `
598
609
  {
599
610
  "style": {
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+
3
+ var _stylex = require("../stylex");
4
+ const mockOptions = {
5
+ customProperties: {
6
+ testVar: "red",
7
+ testVar2: "blue",
8
+ boxShadowVar1: "5px 5px 5px black",
9
+ rawNumber: 10,
10
+ pixelNumber: "10px",
11
+ emNumber: "10em",
12
+ refToRawNumber: "var(--rawNumber)",
13
+ refToPixelNumber: "var(--pixelNumber)",
14
+ refToRefToRawNumber: "var(--refToRawNumber)"
15
+ },
16
+ viewportHeight: 600,
17
+ viewportWidth: 320
18
+ };
19
+ function resolveColorValue(colorValue) {
20
+ const styles = _stylex.stylex.create({
21
+ root: {
22
+ color: colorValue
23
+ }
24
+ });
25
+ return _stylex.stylex.spread(styles.root, mockOptions).style.color;
26
+ }
27
+ describe("stylex CSSCustomProperty value test", () => {
28
+ beforeEach(() => {
29
+ jest.spyOn(console, "warn");
30
+ console.warn.mockImplementation(() => {});
31
+ });
32
+ afterEach(() => {
33
+ console.warn.mockRestore();
34
+ });
35
+ test("parses a basic variable correctly", () => {
36
+ expect(resolveColorValue("var(--testVar)")).toEqual("red");
37
+ });
38
+ test("parses kebab case to camel case", () => {
39
+ expect(resolveColorValue("var(--test-var)")).toEqual("red");
40
+ });
41
+ test("parses a variable with a default value", () => {
42
+ expect(resolveColorValue("var(--testVar, blue)")).toEqual("red");
43
+ expect(resolveColorValue("var(--notFound, blue)")).toEqual("blue");
44
+ });
45
+ test("parses kebab case with a default value", () => {
46
+ expect(resolveColorValue("var(--test-var, blue)")).toEqual("red");
47
+ expect(resolveColorValue("var(--not-found, blue)")).toEqual("blue");
48
+ });
49
+ test("parses a variable with a default value with spaces", () => {
50
+ const styles = _stylex.stylex.create({
51
+ root: {
52
+ boxShadow: "var(--boxShadowVar1, 0px 0px 0px black)"
53
+ }
54
+ });
55
+ expect(_stylex.stylex.spread(styles.root, mockOptions)).toMatchSnapshot();
56
+ });
57
+ test("falls back to a default value with spaces", () => {
58
+ const styles = _stylex.stylex.create({
59
+ root: {
60
+ boxShadow: "var(--boxShadowVarNotFound, 0px 0px 0px black)"
61
+ }
62
+ });
63
+ expect(_stylex.stylex.spread(styles.root, mockOptions)).toMatchSnapshot();
64
+ });
65
+ test("parses and falls back to default value containing a variable", () => {
66
+ const styles = _stylex.stylex.create({
67
+ root: {
68
+ color: "var(--colorNotFound, var(--testVar2))"
69
+ }
70
+ });
71
+ expect(_stylex.stylex.spread(styles.root, mockOptions)).toMatchSnapshot();
72
+ });
73
+ test("parses and falls back to a default value containing spaces and embedded variables", () => {
74
+ const styles = _stylex.stylex.create({
75
+ root: {
76
+ boxShadow: "var(--boxShadowVarNotFound, 0px 0px 0px var(--testVar2))"
77
+ }
78
+ });
79
+ expect(_stylex.stylex.spread(styles.root, mockOptions)).toMatchSnapshot();
80
+ });
81
+ test("does not parse malformed vars", () => {
82
+ expect(resolveColorValue("var(--testUnfinished")).toEqual("var(--testUnfinished");
83
+ expect(resolveColorValue("var(bad--input)")).toEqual("var(bad--input)");
84
+ expect(resolveColorValue("--testMulti")).toEqual("--testMulti");
85
+ expect(resolveColorValue("var ( --testMulti)")).toEqual("var ( --testMulti)");
86
+ });
87
+ test("basic value lookup works", () => {
88
+ const styles = _stylex.stylex.create({
89
+ root: {
90
+ borderWidth: 10
91
+ },
92
+ withVars: {
93
+ borderWidth: "var(--rawNumber)"
94
+ }
95
+ });
96
+ const rootStyle = _stylex.stylex.spread(styles.root, mockOptions).style;
97
+ expect(rootStyle.borderWidth).toEqual(10);
98
+ expect(_stylex.stylex.spread(styles.withVars, mockOptions).style.borderWidth).toEqual(rootStyle.borderWidth);
99
+ });
100
+ test("value lookup with pixel prop conversion", () => {
101
+ const styles = _stylex.stylex.create({
102
+ root: {
103
+ borderWidth: "10px"
104
+ },
105
+ withVars: {
106
+ borderWidth: "var(--pixelNumber)"
107
+ }
108
+ });
109
+ const rootStyle = _stylex.stylex.spread(styles.root, mockOptions).style;
110
+ expect(rootStyle.borderWidth).toEqual(10);
111
+ expect(_stylex.stylex.spread(styles.withVars, mockOptions).style.borderWidth).toEqual(rootStyle.borderWidth);
112
+ });
113
+ test("value lookup with em prop conversion", () => {
114
+ const styles = _stylex.stylex.create({
115
+ root: {
116
+ fontSize: "10em"
117
+ },
118
+ withVars: {
119
+ fontSize: "var(--emNumber)"
120
+ }
121
+ });
122
+ const rootStyle = _stylex.stylex.spread(styles.root, mockOptions).style;
123
+ expect(rootStyle.fontSize).toEqual(160);
124
+ expect(_stylex.stylex.spread(styles.withVars, mockOptions).style.fontSize).toEqual(rootStyle.fontSize);
125
+ });
126
+ test("prop lookup with ref", () => {
127
+ const styles = _stylex.stylex.create({
128
+ root: {
129
+ borderWidth: "var(--refToRawNumber)"
130
+ },
131
+ withVars: {
132
+ borderWidth: "var(--refToPixelNumber)"
133
+ }
134
+ });
135
+ const rootStyle = _stylex.stylex.spread(styles.root, mockOptions).style;
136
+ expect(rootStyle.borderWidth).toEqual(10);
137
+ expect(_stylex.stylex.spread(styles.withVars, mockOptions).style.borderWidth).toEqual(rootStyle.borderWidth);
138
+ });
139
+ test("prop lookup with ref to ref", () => {
140
+ const styles = _stylex.stylex.create({
141
+ root: {
142
+ borderWidth: "var(--refToRefToRawNumber)"
143
+ }
144
+ });
145
+ const rootStyle = _stylex.stylex.spread(styles.root, mockOptions).style;
146
+ expect(rootStyle.borderWidth).toEqual(10);
147
+ });
148
+ });
@@ -132,6 +132,13 @@ describe("styles", () => {
132
132
  paddingLeft: 40,
133
133
  width: 100,
134
134
  height: 100
135
+ },
136
+ auto: {
137
+ boxSizing: "content-box",
138
+ borderWidth: 2,
139
+ padding: 10,
140
+ height: 50,
141
+ width: "auto"
135
142
  }
136
143
  });
137
144
  expect(_stylex.stylex.spread(styles.width, mockOptions)).toMatchSnapshot("width");
@@ -142,6 +149,7 @@ describe("styles", () => {
142
149
  expect(_stylex.stylex.spread(styles.minHeight, mockOptions)).toMatchSnapshot("minHeight");
143
150
  expect(_stylex.stylex.spread(styles.units, mockOptions)).toMatchSnapshot("units");
144
151
  expect(_stylex.stylex.spread(styles.allDifferent, mockOptions)).toMatchSnapshot("allDifferent");
152
+ expect(_stylex.stylex.spread(styles.auto, mockOptions)).toMatchSnapshot("auto");
145
153
  });
146
154
  test("direction", () => {
147
155
  const styles = _stylex.stylex.create({
@@ -42,6 +42,10 @@ function fixContentBox(flatStyle) {
42
42
  nextStyle[styleProp] = null;
43
43
  continue;
44
44
  }
45
+ if (styleValue === "auto") {
46
+ nextStyle[styleProp] = styleValue;
47
+ continue;
48
+ }
45
49
  if (typeof styleValue !== "number") {
46
50
  (0, _errorMsg.warnMsg)(`"boxSizing:'content-box'" does not support value "${String(styleValue)}" for property "${styleProp}". Expected a value that resolves to a number. Percentage values can only be used with "boxSizing:'border-box'".`);
47
51
  return flatStyle;
@@ -7,6 +7,7 @@
7
7
  *
8
8
  */
9
9
 
10
+ import { type SpreadOptions } from './SpreadOptions';
10
11
  /**
11
12
  * The create method shim should do initial transforms like
12
13
  * renaming/expanding/validating properties, essentially all the steps
@@ -23,21 +24,10 @@ export declare function keyframes(): void;
23
24
  /**
24
25
  * The spread method shim
25
26
  */
26
- /**
27
- * The spread method shim
28
- */
29
- type SpreadOptions = {
30
- customProperties: {};
31
- inheritedFontSize: null | undefined | number;
32
- fontScale: number | void;
33
- passthroughProperties: Array<string>;
34
- viewportHeight: number;
35
- viewportWidth: number;
36
- writingDirection: 'ltr' | 'rtl';
37
- };
27
+
38
28
  export declare function spread(
39
29
  style: null | undefined | { [key: string]: unknown },
40
- $$PARAM_1$$: SpreadOptions,
30
+ options: SpreadOptions,
41
31
  ): { [$$Key$$: string]: {} };
42
32
  export type IStyleX = {
43
33
  create: typeof create;
@@ -39,12 +39,13 @@ function isReactNativeStyleValue(propValue) {
39
39
  }
40
40
  function preprocessPropertyValue(propValue) {
41
41
  if (typeof propValue === "string") {
42
- if ((0, _CSSCustomPropertyValue.isCustomPropertyValue)(propValue)) {
43
- return new _CSSCustomPropertyValue.CSSCustomPropertyValue(propValue);
42
+ const customPropValue = (0, _CSSCustomPropertyValue.createCSSCustomPropertyValue)(propValue);
43
+ if (customPropValue != null) {
44
+ return customPropValue;
44
45
  }
45
46
  const maybeLengthUnitValue = _CSSLengthUnitValue.CSSLengthUnitValue.parse(propValue);
46
47
  if (maybeLengthUnitValue != null) {
47
- return new _CSSLengthUnitValue.CSSLengthUnitValue(...maybeLengthUnitValue);
48
+ return maybeLengthUnitValue[1] === "px" ? maybeLengthUnitValue[0] : new _CSSLengthUnitValue.CSSLengthUnitValue(...maybeLengthUnitValue);
48
49
  }
49
50
  }
50
51
  return propValue;
@@ -115,6 +116,22 @@ function preprocessCreate(style) {
115
116
  }
116
117
  return processedStyle;
117
118
  }
119
+ function finalizeValue(unfinalizedValue, options) {
120
+ let styleValue = unfinalizedValue;
121
+ while (styleValue instanceof _CSSCustomPropertyValue.CSSCustomPropertyValue) {
122
+ const customProperties = options.customProperties || {};
123
+ const resolvedValue = customProperties[styleValue.name] ?? styleValue.defaultValue;
124
+ if (resolvedValue == null) {
125
+ (0, _errorMsg.errorMsg)(`Unrecognized custom property "--${styleValue.name}"`);
126
+ return null;
127
+ }
128
+ styleValue = preprocessPropertyValue(resolvedValue);
129
+ }
130
+ if (styleValue instanceof _CSSLengthUnitValue.CSSLengthUnitValue) {
131
+ styleValue = styleValue.resolvePixelValue(options);
132
+ }
133
+ return styleValue;
134
+ }
118
135
  function create(styles) {
119
136
  const result = {};
120
137
  for (const styleName in styles) {
@@ -130,16 +147,7 @@ function keyframes() {
130
147
  (0, _errorMsg.errorMsg)("keyframes are not supported in React Native.");
131
148
  }
132
149
  const timeValuedProperties = ["animationDelay", "animationDuration", "transitionDelay", "transitionDuration"];
133
- function spread(style, _ref) {
134
- let {
135
- customProperties = {},
136
- inheritedFontSize,
137
- fontScale = 1,
138
- passthroughProperties = [],
139
- viewportHeight,
140
- viewportWidth,
141
- writingDirection
142
- } = _ref;
150
+ function spread(style, options) {
143
151
  let {
144
152
  lineClamp,
145
153
  ...flatStyle
@@ -147,6 +155,12 @@ function spread(style, _ref) {
147
155
  let prevStyle = {
148
156
  ...flatStyle
149
157
  };
158
+ const {
159
+ passthroughProperties = [],
160
+ viewportHeight,
161
+ viewportWidth,
162
+ writingDirection
163
+ } = options;
150
164
  const nativeProps = {};
151
165
  for (const styleProp in flatStyle) {
152
166
  let styleValue = flatStyle[styleProp];
@@ -160,18 +174,10 @@ function spread(style, _ref) {
160
174
  continue;
161
175
  }
162
176
  }
163
- if (styleValue instanceof _CSSCustomPropertyValue.CSSCustomPropertyValue) {
164
- const resolvedValue = customProperties[styleValue.name];
165
- if (resolvedValue == null) {
166
- (0, _errorMsg.errorMsg)(`Unrecognized custom property "--${styleValue.name}"`);
167
- delete flatStyle[styleProp];
168
- continue;
169
- }
170
- styleValue = resolvedValue;
171
- }
172
- if (styleValue instanceof _CSSLengthUnitValue.CSSLengthUnitValue) {
173
- const resolvedValue = styleValue.resolvePixelValue(viewportWidth, viewportHeight, fontScale, inheritedFontSize);
174
- styleValue = resolvedValue;
177
+ styleValue = finalizeValue(styleValue, options);
178
+ if (styleValue == null) {
179
+ delete flatStyle[styleProp];
180
+ continue;
175
181
  }
176
182
  if (!isReactNativeStyleProp(styleProp) && passthroughProperties.indexOf(styleProp) === -1) {
177
183
  if (styleProp === "blockSize") {
@@ -7,6 +7,8 @@
7
7
  * @flow strict
8
8
  */
9
9
 
10
+ import { type SpreadOptions } from './SpreadOptions';
11
+
10
12
  /**
11
13
  * The create method shim should do initial transforms like
12
14
  * renaming/expanding/validating properties, essentially all the steps
@@ -26,19 +28,10 @@ declare export function keyframes(): void;
26
28
  /**
27
29
  * The spread method shim
28
30
  */
29
- type SpreadOptions = {|
30
- customProperties: {},
31
- inheritedFontSize: ?number,
32
- fontScale: number | void,
33
- passthroughProperties: Array<string>,
34
- viewportHeight: number,
35
- viewportWidth: number,
36
- writingDirection: 'ltr' | 'rtl',
37
- |};
38
31
 
39
32
  declare export function spread(
40
33
  style: ?{ [key: string]: mixed },
41
- SpreadOptions,
34
+ options: SpreadOptions,
42
35
  ): { [string]: { ... } };
43
36
 
44
37
  export type IStyleX = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stylexjs/stylex",
3
- "version": "0.2.0-beta.20",
3
+ "version": "0.2.0-beta.21",
4
4
  "description": "A library for defining styles for optimized user interfaces.",
5
5
  "main": "lib/stylex.js",
6
6
  "react-native": "lib/native/stylex.js",
@@ -20,7 +20,7 @@
20
20
  "utility-types": "^3.10.0"
21
21
  },
22
22
  "devDependencies": {
23
- "@stylexjs/scripts": "0.2.0-beta.20"
23
+ "@stylexjs/scripts": "0.2.0-beta.21"
24
24
  },
25
25
  "jest": {},
26
26
  "files": [