@stylexjs/stylex 0.1.0-beta.7 → 0.2.0-beta.11

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.
@@ -0,0 +1,283 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.create = create;
7
+ exports.firstThatWorks = exports.default = void 0;
8
+ exports.keyframes = keyframes;
9
+ exports.spread = spread;
10
+ exports.stylex = void 0;
11
+ var _CSSCustomPropertyValue = require("./CSSCustomPropertyValue");
12
+ var _CSSLengthUnitValue = require("./CSSLengthUnitValue");
13
+ var _CSSMediaQuery = require("./CSSMediaQuery");
14
+ var _errorMsg = require("./errorMsg");
15
+ var _flattenStyle = require("./flattenStyle");
16
+ var _parseShadow = require("./parseShadow");
17
+ /**
18
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
19
+ *
20
+ * This source code is licensed under the MIT license found in the
21
+ * LICENSE file in the root directory of this source tree.
22
+ *
23
+ *
24
+ */
25
+
26
+ const stylePropertyAllowlistSet = new Set(['alignContent', 'alignItems', 'alignSelf', 'aspectRatio', 'backfaceVisibility', 'backgroundColor', 'borderBlockColor', 'borderBlockStyle', 'borderBlockWidth', 'borderBlockEndColor', 'borderBlockEndStyle', 'borderBlockEndWidth', 'borderBlockStartColor', 'borderBlockStartStyle', 'borderBlockStartWidth', 'borderBottomColor', 'borderBottomLeftRadius', 'borderBottomRightRadius', 'borderBottomStyle', 'borderBottomWidth', 'borderEndEndRadius', 'borderEndStartRadius', 'borderColor', 'borderInlineColor', 'borderInlineStyle', 'borderInlineWidth', 'borderInlineEndColor', 'borderInlineEndStyle', 'borderInlineEndWidth', 'borderInlineStartColor', 'borderInlineStartStyle', 'borderInlineStartWidth', 'borderLeftColor', 'borderLeftStyle', 'borderLeftWidth', 'borderRadius', 'borderRightColor', 'borderRightStyle', 'borderRightWidth', 'borderStartEndRadius', 'borderStartStartRadius', 'borderStyle', 'borderTopColor', 'borderTopLeftRadius', 'borderTopRightRadius', 'borderTopStyle', 'borderTopWidth', 'borderWidth', 'bottom', 'color', 'direction', 'display', 'end', 'flex', 'flexBasis', 'flexDirection', 'flexGrow', 'flexShrink', 'flexWrap', 'fontFamily', 'fontSize', 'fontStyle', 'fontWeight', 'fontVariant', 'gap', 'gapColumn', 'gapRow', 'height',
27
+ // 'includeFontPadding', Android Only
28
+ 'inset', 'insetBlock', 'insetBlockEnd', 'insetBlockStart', 'insetInline', 'insetInlineEnd', 'insetInlineStart', 'justifyContent', 'left', 'letterSpacing', 'lineHeight', 'margin', 'marginBlock', 'marginBlockEnd', 'marginBlockStart', 'marginBottom', 'marginInline', 'marginInlineEnd', 'marginInlineStart', 'marginLeft', 'marginRight', 'marginStart', 'marginTop', 'maxHeight', 'maxWidth', 'minHeight', 'minWidth', 'objectFit', 'opacity', 'overflow', 'padding', 'paddingBlock', 'paddingBlockEnd', 'paddingBlockStart', 'paddingBottom', 'paddingEnd', 'paddingInline', 'paddingInlineEnd', 'paddingInlineStart', 'paddingLeft', 'paddingRight', 'paddingStart', 'paddingTop', 'pointerEvents', 'position', 'resizeMode', 'right', 'shadowColor', 'shadowOffset', 'shadowOpacity', 'shadowRadius', 'shadowWidth', 'start', 'textAlign', 'textDecorationLine', 'textDecorationColor',
29
+ // iOS Only
30
+ 'textDecorationStyle',
31
+ // iOS Only
32
+ 'textShadowColor', 'textShadowOffset', 'textShadowRadius', 'textTransform', 'tintColor', 'transform', 'top', 'userSelect', 'verticalAlign',
33
+ // Android Only
34
+ 'width', 'writingDirection',
35
+ // iOS Only
36
+ 'zIndex']);
37
+ function isReactNativeStyleProp(propName) {
38
+ return stylePropertyAllowlistSet.has(propName) || propName.startsWith('--');
39
+ }
40
+ function isReactNativeStyleValue(propValue) {
41
+ if (typeof propValue === 'string') {
42
+ // RN doesn't have an inherit keyword
43
+ if (propValue === 'inherit') {
44
+ return false;
45
+ }
46
+ // RN doesn't have an inherit keyword
47
+ if (propValue === 'initial') {
48
+ return false;
49
+ }
50
+ //if (propValue.endsWith('em')) {
51
+ // return false;
52
+ //}
53
+ //if (propValue.endsWith('rem')) {
54
+ // return false;
55
+ //}
56
+ // RN on android doesn't like explicitly specified px units
57
+ if (propValue.endsWith('px')) {
58
+ return false;
59
+ }
60
+ // RN doesn't support calc functions
61
+ if (propValue.includes('calc(')) {
62
+ return false;
63
+ }
64
+ }
65
+ return true;
66
+ }
67
+ function preprocessPropertyValue(propValue) {
68
+ if (typeof propValue === 'string') {
69
+ if ((0, _CSSCustomPropertyValue.isCustomPropertyValue)(propValue)) {
70
+ return new _CSSCustomPropertyValue.CSSCustomPropertyValue(propValue);
71
+ }
72
+ const maybeViewportValue = _CSSLengthUnitValue.CSSLengthUnitValue.parse(propValue);
73
+ if (maybeViewportValue != null) {
74
+ return maybeViewportValue;
75
+ }
76
+ }
77
+ return propValue;
78
+ }
79
+ function preprocessCreate(style) {
80
+ // eslint-disable-next-line flowtype/no-flow-fix-me-comments
81
+ const processedStyle = {};
82
+ for (const propName in style) {
83
+ const styleValue = style[propName];
84
+ if (_CSSMediaQuery.CSSMediaQuery.isMediaQueryString(propName) && typeof styleValue === 'object' && styleValue != null) {
85
+ // have to spread styleValue into a copied object to appease flow
86
+ const processsedSubStyle = preprocessCreate({
87
+ ...styleValue
88
+ });
89
+ processedStyle[propName] = new _CSSMediaQuery.CSSMediaQuery(propName, processsedSubStyle);
90
+ continue;
91
+ }
92
+ if (propName === 'backgroundImage') {
93
+ (0, _errorMsg.errorMsg)('"backgroundImage" is not supported in React Native.');
94
+ }
95
+ // React Native only supports non-standard box-shadow styles
96
+ else if (propName === 'boxShadow' && typeof styleValue === 'string') {
97
+ const parsedShadow = (0, _parseShadow.parseShadow)(styleValue);
98
+ if (parsedShadow.length > 1) {
99
+ (0, _errorMsg.errorMsg)('Multiple "boxShadow" values are not supported in React Native.');
100
+ }
101
+ const {
102
+ inset,
103
+ offsetX,
104
+ offsetY,
105
+ blurRadius,
106
+ color
107
+ } = parsedShadow[0];
108
+ // TODO: parse alpha color inputs => alpha + color
109
+ // errorMsg('"boxShadow" opacity is not implemented in React Native.');
110
+ if (inset) {
111
+ (0, _errorMsg.errorMsg)('"boxShadow" value of "inset" is not supported in React Native.');
112
+ }
113
+ processedStyle.shadowColor = color;
114
+ processedStyle.shadowOffset = {
115
+ height: offsetY,
116
+ width: offsetX
117
+ };
118
+ processedStyle.shadowOpacity = 1;
119
+ processedStyle.shadowRadius = blurRadius;
120
+ }
121
+ // Needed by React Native for Desktop
122
+ else if (propName === 'fontWeight' && typeof styleValue === 'number') {
123
+ // $FlowFixMe
124
+ processedStyle[propName] = styleValue.toString();
125
+ } else if (propName === 'position') {
126
+ if (styleValue === 'fixed') {
127
+ processedStyle[propName] = 'absolute';
128
+ (0, _errorMsg.errorMsg)('"position" value of "fixed" is not supported in React Native. Falling back to "absolute".');
129
+ } else if (styleValue === 'sticky') {
130
+ processedStyle[propName] = 'relative';
131
+ (0, _errorMsg.errorMsg)('"position" value of "sticky" is not supported in React Native. Falling back to "relative".');
132
+ } else {
133
+ processedStyle[propName] = styleValue;
134
+ }
135
+ }
136
+ // React Native only supports non-standard text-shadow styles
137
+ else if (propName === 'textShadow' && typeof styleValue === 'string') {
138
+ const parsedShadow = (0, _parseShadow.parseShadow)(styleValue);
139
+ if (parsedShadow.length > 1) {
140
+ (0, _errorMsg.errorMsg)('Multiple "textShadow" values are not supported in React Native.');
141
+ }
142
+ const {
143
+ offsetX,
144
+ offsetY,
145
+ blurRadius,
146
+ color
147
+ } = parsedShadow[0];
148
+ processedStyle.textShadowColor = color;
149
+ processedStyle.textShadowOffset = {
150
+ height: offsetY,
151
+ width: offsetX
152
+ };
153
+ processedStyle.textShadowRadius = blurRadius;
154
+ } else {
155
+ processedStyle[propName] = styleValue;
156
+ }
157
+ }
158
+
159
+ // Process values that need to be resolved during render
160
+ for (const prop in processedStyle) {
161
+ const processedStyleValue = preprocessPropertyValue(processedStyle[prop]);
162
+ processedStyle[prop] = processedStyleValue;
163
+ }
164
+ return processedStyle;
165
+ }
166
+
167
+ /**
168
+ * The create method shim should do initial transforms like
169
+ * renaming/expanding/validating properties, essentially all the steps
170
+ * which can be done at initialization-time (could potentially be done at
171
+ * compile-time in the future).
172
+ */
173
+ function create(styles) {
174
+ const result = {};
175
+ for (const styleName in styles) {
176
+ result[styleName] = preprocessCreate(styles[styleName]);
177
+ }
178
+ return result;
179
+ }
180
+ const firstThatWorks = function () {
181
+ return arguments.length <= 0 ? undefined : arguments[0];
182
+ };
183
+ exports.firstThatWorks = firstThatWorks;
184
+ function keyframes() {
185
+ (0, _errorMsg.errorMsg)('keyframes are not supported in React Native.');
186
+ }
187
+
188
+ /**
189
+ * The spread method shim
190
+ */
191
+
192
+ function spread(style, _ref) {
193
+ let {
194
+ customProperties,
195
+ inheritedFontSize,
196
+ fontScale = 1,
197
+ viewportHeight,
198
+ viewportWidth,
199
+ writingDirection
200
+ } = _ref;
201
+ /* eslint-disable prefer-const */
202
+ let {
203
+ lineClamp,
204
+ ...flatStyle
205
+ } = (0, _flattenStyle.flattenStyle)(style);
206
+ /* eslint-enable prefer-const */
207
+
208
+ const nativeProps = {};
209
+ for (const styleProp in flatStyle) {
210
+ let styleValue = flatStyle[styleProp];
211
+
212
+ // resolve media queries
213
+ if (styleValue instanceof _CSSMediaQuery.CSSMediaQuery) {
214
+ const maybeExistingMediaQuery = flatStyle[styleProp];
215
+ if (maybeExistingMediaQuery instanceof _CSSMediaQuery.CSSMediaQuery) {
216
+ const s = (0, _flattenStyle.flattenStyle)([maybeExistingMediaQuery.matchedStyle, styleValue.matchedStyle]);
217
+ if (s != null) {
218
+ maybeExistingMediaQuery.matchedStyle = s;
219
+ }
220
+ continue;
221
+ }
222
+ }
223
+ // resolve custom property references
224
+ if (styleValue instanceof _CSSCustomPropertyValue.CSSCustomPropertyValue) {
225
+ const resolvedValue = customProperties[styleValue.name];
226
+ if (resolvedValue == null) {
227
+ (0, _errorMsg.errorMsg)(`Unrecognized custom property "--${styleValue.name}"`);
228
+ delete flatStyle[styleProp];
229
+ continue;
230
+ }
231
+ styleValue = resolvedValue;
232
+ }
233
+ // resolve viewport units
234
+ if (styleValue instanceof _CSSLengthUnitValue.CSSLengthUnitValue) {
235
+ const resolvedValue = styleValue.resolvePixelValue(viewportWidth, viewportHeight, fontScale, inheritedFontSize);
236
+ styleValue = resolvedValue;
237
+ }
238
+
239
+ // Filter out any unexpected style property names so RN doesn't crash but give
240
+ // the developer a warning to let them know that there's a new prop we should either
241
+ // explicitly ignore or process in some way.
242
+ // NOTE: Any kind of prop name transformations should happen before this check.
243
+ if (!isReactNativeStyleProp(styleProp)) {
244
+ (0, _errorMsg.errorMsg)(`Encountered unsupported style property "${styleProp}"`);
245
+ delete flatStyle[styleProp];
246
+ continue;
247
+ }
248
+
249
+ // Similar filter to the prop name one above but instead operates on the property's
250
+ // value. Similarly, any sort of prop value transformations should happen before this
251
+ // filter.
252
+ // We check this at resolve time to ensure the render-time styles are safe.
253
+ if (!isReactNativeStyleValue(styleValue)) {
254
+ (0, _errorMsg.errorMsg)(`Encounted unsupported style value "${String(styleValue)}" for property "${styleProp}"`);
255
+ delete flatStyle[styleProp];
256
+ continue;
257
+ }
258
+ flatStyle[styleProp] = styleValue;
259
+ }
260
+ if (flatStyle != null && Object.keys(flatStyle).length > 0) {
261
+ flatStyle = _CSSMediaQuery.CSSMediaQuery.resolveMediaQueries(flatStyle, {
262
+ width: viewportWidth,
263
+ height: viewportHeight,
264
+ direction: writingDirection
265
+ });
266
+ // $FlowFixMe
267
+ nativeProps.style = flatStyle;
268
+ }
269
+ if (lineClamp != null) {
270
+ // $FlowFixMe
271
+ nativeProps.numberOfLines = lineClamp;
272
+ }
273
+ return nativeProps;
274
+ }
275
+ const stylex = {
276
+ create,
277
+ firstThatWorks,
278
+ keyframes,
279
+ spread
280
+ };
281
+ exports.stylex = stylex;
282
+ var _default = stylex;
283
+ exports.default = _default;
package/lib/stylex.d.ts CHANGED
@@ -38,17 +38,14 @@ export type CompiledNamespaceSet = {
38
38
  readonly [K in string]: CompiledNamespace;
39
39
  };
40
40
 
41
- type Stylex$Create = <S extends StyleXNamespaceSet>(
41
+ type Stylex$Create = <S extends NamespaceSet>(
42
42
  styles: S
43
43
  ) => $ReadOnly<{
44
44
  readonly [K in keyof S]: {
45
45
  readonly [P in keyof S[K]]: S[K][P] extends string | number
46
- ? StyleXClassNameFor<P, S[K][P]>
46
+ ? ClassNameFor<P, S[K][P]>
47
47
  : {
48
- readonly [F in keyof S[K][P]]: StyleXClassNameFor<
49
- `${P}+${F}`,
50
- S[K][P][F]
51
- >;
48
+ readonly [F in keyof S[K][P]]: ClassNameFor<`${P}+${F}`, S[K][P][F]>;
52
49
  };
53
50
  };
54
51
  }>;
@@ -56,19 +53,17 @@ type Stylex$Create = <S extends StyleXNamespaceSet>(
56
53
  type StylexInclude = <S extends CompiledNamespace>(
57
54
  compiledNamespace: S
58
55
  ) => {
59
- readonly [K in keyof S]: S[K] extends ClassNameFor<K, infer V>
60
- ? V
61
- : Uncompiled<S[K]>;
56
+ readonly [K in keyof S]: S[K] extends ClassNameFor<K, infer V> ? V : S[K];
62
57
  };
63
58
 
64
- type Stylex$Keyframes = <S extends StyleXNamespaceSet>(
65
- animationConfig: S
66
- ) => string;
59
+ type Stylex$Keyframes = <S extends NamespaceSet>(animationConfig: S) => string;
67
60
 
68
- type stylex = {
61
+ type NestedArray<T> = T | Array<T | NestedArray<T>>;
62
+
63
+ declare let stylex: {
69
64
  (
70
65
  ...styles: ReadonlyArray<
71
- StyleXArray<(CompiledNamespace | null | undefined) | boolean>
66
+ NestedArray<(CompiledNamespace | null | undefined) | boolean>
72
67
  >
73
68
  ): string;
74
69
  create: Stylex$Create;
@@ -79,6 +74,14 @@ type stylex = {
79
74
  rtlRule: string | null | undefined
80
75
  ) => void;
81
76
  keyframes: Stylex$Keyframes;
77
+ spread: (
78
+ ...styles: ReadonlyArray<
79
+ NestedArray<(Object | CompiledNamespace | null | undefined) | boolean>
80
+ >
81
+ ) => {
82
+ className: string;
83
+ style: { [key: string]: string | number };
84
+ };
82
85
  };
83
86
 
84
87
  export default stylex;
package/lib/stylex.js CHANGED
@@ -12,79 +12,21 @@
12
12
  Object.defineProperty(exports, "__esModule", {
13
13
  value: true
14
14
  });
15
- exports.default = void 0;
15
+ exports.keyframes = exports.inject = exports.include = exports.firstThatWorks = exports.default = exports.create = exports.UNSUPPORTED_PROPERTY = void 0;
16
+ exports.spread = spread;
17
+ exports.stylex = void 0;
16
18
  var _stylexInject = _interopRequireDefault(require("./stylex-inject"));
19
+ var _styleq = require("styleq");
17
20
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
18
- const enableCache = true;
19
- const cache = enableCache ? new WeakMap() : null;
20
- function stylex() {
21
- // Keep a set of property commits to the className
22
- const definedProperties = [];
23
- let className = '';
24
- let nextCache = cache;
21
+ function spread() {
25
22
  for (var _len = arguments.length, styles = new Array(_len), _key = 0; _key < _len; _key++) {
26
23
  styles[_key] = arguments[_key];
27
24
  }
28
- while (styles.length) {
29
- // Push nested styles back onto the stack to be processed
30
- const possibleStyle = styles.pop();
31
- if (Array.isArray(possibleStyle)) {
32
- for (let i = 0; i < possibleStyle.length; i++) {
33
- styles.push(possibleStyle[i]);
34
- }
35
- continue;
36
- }
37
-
38
- // Process an individual style object
39
- const styleObj = possibleStyle;
40
- if (styleObj != null && typeof styleObj === 'object') {
41
- // Build up the class names defined by this object
42
- let classNameChunk = '';
43
- if (nextCache != null && nextCache.has(styleObj)) {
44
- // Cache: read
45
- const cacheEntry = nextCache.get(styleObj);
46
- if (cacheEntry != null) {
47
- classNameChunk = cacheEntry.classNameChunk;
48
- definedProperties.push(...cacheEntry.definedPropertiesChunk);
49
- nextCache = cacheEntry.next;
50
- }
51
- } else {
52
- // Record the properties this object defines (and that haven't already
53
- // been defined by later objects.)
54
- const definedPropertiesChunk = [];
55
- for (const prop in styleObj) {
56
- const value = styleObj[prop];
57
- // Style declarations, e.g., opacity: 's3fkgpd'
58
- if (typeof value === 'string') {
59
- // Skip adding to the chunks if property has already been seen
60
- if (!definedProperties.includes(prop)) {
61
- definedProperties.push(prop);
62
- definedPropertiesChunk.push(prop);
63
- classNameChunk += classNameChunk ? ' ' + value : value;
64
- }
65
- }
66
- }
67
- // Cache: write
68
- if (nextCache != null) {
69
- const emptyCache = new WeakMap();
70
- nextCache.set(styleObj, {
71
- classNameChunk,
72
- definedPropertiesChunk,
73
- next: emptyCache
74
- });
75
- nextCache = emptyCache;
76
- }
77
- }
78
-
79
- // Order of classes in chunks matches property-iteration order of style
80
- // object. Order of chunks matches passed order of styles from first to
81
- // last (which we iterate over in reverse).
82
- if (classNameChunk) {
83
- className = className ? classNameChunk + ' ' + className : classNameChunk;
84
- }
85
- }
86
- }
87
- return className;
25
+ const [className, style] = (0, _styleq.styleq)(styles);
26
+ return {
27
+ className,
28
+ style
29
+ };
88
30
  }
89
31
  function stylexCreate(_styles) {
90
32
  throw new Error('stylex.create should never be called. It should be compiled away.');
@@ -92,17 +34,39 @@ function stylexCreate(_styles) {
92
34
  function stylexIncludes(_styles) {
93
35
  throw new Error('stylex.extends should never be called. It should be compiled away.');
94
36
  }
95
- stylex.create = stylexCreate;
96
- stylex.include = stylexIncludes;
97
- stylex.keyframes = _keyframes => {
37
+ const create = stylexCreate;
38
+ exports.create = create;
39
+ const include = stylexIncludes;
40
+ exports.include = include;
41
+ const keyframes = _keyframes => {
98
42
  throw new Error('stylex.keyframes should never be called');
99
43
  };
100
- stylex.firstThatWorks = function () {
44
+ exports.keyframes = keyframes;
45
+ const firstThatWorks = function () {
101
46
  throw new Error('stylex.firstThatWorks should never be called.');
102
47
  };
103
- stylex.inject = _stylexInject.default;
104
- stylex.UNSUPPORTED_PROPERTY = props => {
48
+ exports.firstThatWorks = firstThatWorks;
49
+ const inject = _stylexInject.default;
50
+ exports.inject = inject;
51
+ const UNSUPPORTED_PROPERTY = _props => {
105
52
  throw new Error('stylex.UNSUPPORTED_PROPERTY should never be called. It should be compiled away.');
106
53
  };
107
- var _default = stylex;
108
- exports.default = _default;
54
+ exports.UNSUPPORTED_PROPERTY = UNSUPPORTED_PROPERTY;
55
+ function _stylex() {
56
+ for (var _len2 = arguments.length, styles = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
57
+ styles[_key2] = arguments[_key2];
58
+ }
59
+ const [className] = (0, _styleq.styleq)(styles);
60
+ return className;
61
+ }
62
+ _stylex.spread = spread;
63
+ _stylex.create = create;
64
+ _stylex.include = include;
65
+ _stylex.keyframes = keyframes;
66
+ _stylex.firstThatWorks = firstThatWorks;
67
+ _stylex.inject = inject;
68
+ _stylex.UNSUPPORTED_PROPERTY = UNSUPPORTED_PROPERTY;
69
+ var _default = _stylex;
70
+ exports.default = _default;
71
+ const stylex = _stylex;
72
+ exports.stylex = stylex;
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@stylexjs/stylex",
3
- "version": "0.1.0-beta.7",
4
- "description": "A minimal runtime styling library for web.",
3
+ "version": "0.2.0-beta.11",
4
+ "description": "A styling library for React.",
5
5
  "main": "lib/stylex.js",
6
+ "react-native": "lib/native/stylex.js",
6
7
  "types": "lib/stylex.d.ts",
7
- "repository": "https://www.github.com/facebookexternal/stylex",
8
- "author": "Naman Goel <nmn@fb.com>",
8
+ "repository": "https://www.github.com/facebook/stylex",
9
9
  "license": "MIT",
10
10
  "scripts": {
11
11
  "build": "babel src/ --out-dir lib/ --copy-files",
@@ -13,11 +13,10 @@
13
13
  "test": "jest"
14
14
  },
15
15
  "dependencies": {
16
+ "css-mediaquery": "^0.1.2",
16
17
  "invariant": "^2.2.4",
17
- "utility-types": "^3.10.0"
18
- },
19
- "devDependencies": {
20
- "benchmark": "^2.1.4"
18
+ "utility-types": "^3.10.0",
19
+ "styleq": "0.1.3"
21
20
  },
22
21
  "jest": {},
23
22
  "files": [